diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 25ccb0912a040037509d742883416659528cbb5d..36c4af21d4d3e342ee546a59cb806cfdbbcf1c0e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -95,8 +95,7 @@ cargo-check-benches: stage: test <<: *docker-env script: - - ./scripts/build.sh --locked - - time cargo check --benches + - BUILD_DUMMY_WASM_BINARY=1 time cargo check --benches - sccache -s @@ -107,7 +106,7 @@ cargo-check-subkey: - /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 script: - cd ./subkey - - time cargo check --release # makes sense to save artifacts for building it + - BUILD_DUMMY_WASM_BINARY=1 time cargo check --release # makes sense to save artifacts for building it - sccache -s @@ -122,22 +121,57 @@ test-linux-stable: &test-linux variables: - $DEPLOY_TAG script: - - ./scripts/build.sh --locked - time cargo test --all --release --verbose --locked - sccache -s + +test-srml-staking: &test-srml-staking + stage: test + <<: *docker-env + variables: + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: -Cdebug-assertions=y + RUST_BACKTRACE: 1 + except: + variables: + - $DEPLOY_TAG + only: + changes: + - .gitlab-ci.yml + - srml/staking/* + script: + - cd srml/staking/ + - time cargo test --release --verbose --no-default-features --features std + - sccache -s + + + + + + test-linux-stable-int: <<: *test-linux except: refs: - - /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 + - /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 variables: - $DEPLOY_TAG script: - - ./scripts/build.sh --locked - - time RUST_LOG=sync=trace,consensus=trace,client=trace,state-db=trace,db=trace,forks=trace,state_db=trace,storage_cache=trace - cargo test -p node-cli --release --verbose --locked -- --ignored --test-threads=1 + - echo "___Logs will be partly shown at the end in case of failure.___" + - echo "___Full log will be saved to the job artifacts only in case of failure.___" + - RUST_LOG=sync=trace,consensus=trace,client=trace,state-db=trace,db=trace,forks=trace,state_db=trace,storage_cache=trace + time cargo test -p node-cli --release --verbose --locked -- --ignored --test-threads=1 + &> ${CI_COMMIT_SHORT_SHA}_int_failure.log - sccache -s + after_script: + - awk '/FAILED/,0' ${CI_COMMIT_SHORT_SHA}_int_failure.log + artifacts: + name: $CI_COMMIT_SHORT_SHA + when: on_failure + expire_in: 24 hrs + paths: + - ${CI_COMMIT_SHORT_SHA}_int_failure.log allow_failure: true @@ -161,9 +195,12 @@ check-web-wasm: - time cargo web build -p substrate-keystore - time cargo web build -p substrate-executor - time cargo web build -p substrate-network + - time cargo web build -p substrate-offchain - time cargo web build -p substrate-panic-handler - time cargo web build -p substrate-peerset - time cargo web build -p substrate-primitives + # TODO: we can't use cargo web until https://github.com/paritytech/jsonrpc/pull/436 is deployed + - time cargo build -p substrate-rpc-servers --target wasm32-unknown-unknown - time cargo web build -p substrate-serializer - time cargo web build -p substrate-state-db - time cargo web build -p substrate-state-machine @@ -188,7 +225,6 @@ build-linux-release: variables: - $DEPLOY_TAG script: - - ./scripts/build.sh --locked - time cargo build --release --verbose - mkdir -p ./artifacts - mv ./target/release/substrate ./artifacts/. @@ -206,6 +242,28 @@ build-linux-release: - cp -r scripts/docker/* ./artifacts - sccache -s +build-linux-subkey: + stage: build + <<: *collect-artifacts + <<: *docker-env + # <<: *build-only + except: + variables: + - $DEPLOY_TAG + script: + - cd ./subkey + - BUILD_DUMMY_WASM_BINARY=1 time cargo build --release --verbose + - cd .. + # - time cargo build --release + - sccache -s + - mkdir -p ./artifacts + - mv ./target/release/subkey ./artifacts/. + - echo -n "Subkey version = " + - ./artifacts/subkey --version | + sed -n -r 's/^subkey ([0-9.]+.*)/\1/p' | + tee ./artifacts/SUBKEY-VERSION; + - sha256sum ./artifacts/subkey | tee ./artifacts/subkey.sha256 + build-rust-doc-release: stage: build <<: *docker-env @@ -218,9 +276,8 @@ build-rust-doc-release: - ./crate-docs <<: *build-only script: - - ./scripts/build.sh --locked - rm -f ./crate-docs/index.html # use it as an indicator if the job succeeds - - time cargo +nightly doc --release --all --verbose + - BUILD_DUMMY_WASM_BINARY=1 time cargo +nightly doc --release --all --verbose - cp -R ./target/doc ./crate-docs - echo "" > ./crate-docs/index.html - sccache -s @@ -231,6 +288,7 @@ build-rust-doc-release: stage: publish dependencies: - build-linux-release + - build-linux-subkey <<: *build-only <<: *kubernetes-build @@ -289,6 +347,7 @@ publish-s3-release: - aws s3 ls s3://${BUCKET}/${PREFIX}/latest/ --recursive --human-readable --summarize + publish-s3-doc: stage: publish image: parity/awscli:latest diff --git a/Cargo.lock b/Cargo.lock index b89743546f751abe449ca2e6477c101bb61f2322..6fcd6982e0115dc22e53ebe8f68b0e84a3e5611b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,10 +38,10 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -49,10 +49,10 @@ name = "aio-limited" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -91,7 +91,7 @@ dependencies = [ [[package]] name = "asn1_der" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "asn1_der_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -103,7 +103,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -116,8 +116,8 @@ name = "atty" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -128,23 +128,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "backtrace-sys" -version = "0.1.28" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -188,14 +187,14 @@ dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "clang-sys 0.26.4 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -209,6 +208,11 @@ name = "bitmask" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitvec" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "blake2" version = "0.8.0" @@ -216,7 +220,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -246,7 +250,7 @@ dependencies = [ "block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -254,7 +258,7 @@ name = "block-cipher-trait" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -272,20 +276,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bstr" -version = "0.1.4" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-automata 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "build_const" -version = "0.2.1" +name = "build-helper" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "bumpalo" -version = "2.4.3" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -318,11 +328,32 @@ dependencies = [ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "c2-chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "c_linked_list" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cargo_metadata" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cast" version = "0.2.2" @@ -333,7 +364,7 @@ name = "cc" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -361,9 +392,10 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -375,8 +407,8 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "libloading 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -429,7 +461,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -437,14 +469,6 @@ name = "core-foundation-sys" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "crc" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crc32fast" version = "1.2.0" @@ -462,19 +486,19 @@ dependencies = [ "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -513,15 +537,6 @@ dependencies = [ "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossbeam-deque" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crossbeam-deque" version = "0.6.3" @@ -540,20 +555,6 @@ dependencies = [ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossbeam-epoch" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crossbeam-epoch" version = "0.7.1" @@ -575,14 +576,6 @@ dependencies = [ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossbeam-utils" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crossbeam-utils" version = "0.6.5" @@ -616,27 +609,28 @@ name = "crypto-mac" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "csv" -version = "1.0.7" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "bstr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "csv-core" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -645,7 +639,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -682,7 +676,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -700,7 +694,20 @@ dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "derive_more" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -718,10 +725,10 @@ dependencies = [ [[package]] name = "digest" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -733,6 +740,11 @@ dependencies = [ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "doc-comment" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ed25519-dalek" version = "1.0.0-pre.1" @@ -760,13 +772,13 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -780,7 +792,7 @@ name = "erased-serde" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -788,7 +800,7 @@ name = "error-chain" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.30 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -797,7 +809,7 @@ name = "exit-future" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -806,7 +818,7 @@ name = "failure" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.30 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -817,7 +829,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -831,31 +843,29 @@ name = "fdlimit" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "finality-grandpa" -version = "0.7.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "hashmap_core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "fixed-hash" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -863,14 +873,15 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", "miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide_c_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -896,7 +907,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "fork-tree" version = "2.0.0" dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -905,8 +916,17 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "libloading 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -931,7 +951,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures" -version = "0.1.27" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-channel-preview" +version = "0.3.0-alpha.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-core-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-core-preview" +version = "0.3.0-alpha.17" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -939,10 +973,71 @@ name = "futures-cpupool" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "futures-executor-preview" +version = "0.3.0-alpha.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-channel-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-io-preview" +version = "0.3.0-alpha.17" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-preview" +version = "0.3.0-alpha.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-channel-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-executor-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-sink-preview" +version = "0.3.0-alpha.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-core-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-timer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-util-preview" +version = "0.3.0-alpha.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "gcc" version = "0.3.55" @@ -959,7 +1054,7 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.12.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -972,7 +1067,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "c_linked_list 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "get_if_addrs-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -982,7 +1077,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "getrandom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -997,41 +1101,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "globset" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "bstr 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bstr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "h2" -version = "0.1.23" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "string 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hash-db" -version = "0.12.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hash256-std-hasher" -version = "0.12.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1087,7 +1191,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hex-literal-impl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1103,7 +1207,7 @@ name = "hex-literal-impl" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro-hack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1122,7 +1226,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1151,14 +1255,14 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "httparse" -version = "1.3.3" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1175,7 +1279,7 @@ version = "0.10.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.3.4 (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.9 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1189,31 +1293,31 @@ dependencies = [ [[package]] name = "hyper" -version = "0.12.29" +version = "0.12.31" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "h2 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "h2 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1228,10 +1332,10 @@ dependencies = [ [[package]] name = "impl-codec" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1240,7 +1344,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1248,7 +1352,7 @@ name = "impl-serde" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1271,7 +1375,7 @@ name = "iovec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1295,67 +1399,68 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "js-sys" -version = "0.3.22" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jsonrpc-client-transports" -version = "12.0.0" +version = "12.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.29 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.31 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-pubsub 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "websocket 0.22.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jsonrpc-core" -version = "12.0.0" +version = "12.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jsonrpc-core-client" -version = "12.0.0" +version = "12.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "jsonrpc-client-transports 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-client-transports 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jsonrpc-derive" -version = "12.0.0" +version = "12.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jsonrpc-http-server" -version = "12.0.0" +version = "12.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hyper 0.12.29 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-server-utils 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.31 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-server-utils 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1364,38 +1469,38 @@ dependencies = [ [[package]] name = "jsonrpc-pubsub" -version = "12.0.0" +version = "12.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "jsonrpc-core 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jsonrpc-server-utils" -version = "12.0.0" +version = "12.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "globset 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jsonrpc-ws-server" -version = "12.0.0" +version = "12.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "jsonrpc-core 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-server-utils 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-server-utils 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1409,12 +1514,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "keccak-hasher" -version = "0.12.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hash256-std-hasher 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash256-std-hasher 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1456,7 +1561,7 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "rocksdb 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1469,6 +1574,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "lazy_static" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "lazycell" @@ -1477,12 +1585,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.58" +version = "0.2.59" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libloading" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1491,53 +1599,53 @@ dependencies = [ [[package]] name = "libp2p" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core-derive 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-deflate 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-dns 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-floodsub 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-identify 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-kad 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-mdns 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-mplex 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-noise 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-ping 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-plaintext 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-ratelimit 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-secio 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-tcp 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-uds 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-wasm-ext 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-websocket 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-yamux 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core-derive 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-deflate 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-dns 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-floodsub 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-identify 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-kad 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-mdns 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-mplex 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-noise 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-ping 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-plaintext 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-ratelimit 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-secio 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-tcp 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-uds 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-wasm-ext 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-websocket 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-yamux 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multihash 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-core" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "asn1_der 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "asn1_der 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1545,49 +1653,49 @@ dependencies = [ "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multihash 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", "rw-stream-sink 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-core-derive" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-deflate" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-dns" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-dns-unofficial 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1595,16 +1703,16 @@ dependencies = [ [[package]] name = "libp2p-floodsub" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "cuckoofilter 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1614,28 +1722,28 @@ dependencies = [ [[package]] name = "libp2p-identify" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-kad" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1644,13 +1752,13 @@ dependencies = [ "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multihash 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1658,18 +1766,18 @@ dependencies = [ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-mdns" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "dns-parser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1679,18 +1787,18 @@ dependencies = [ "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-mplex" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1700,33 +1808,33 @@ dependencies = [ [[package]] name = "libp2p-noise" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "curve25519-dalek 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", "snow 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "x25519-dalek 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-ping" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1734,50 +1842,50 @@ dependencies = [ "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-plaintext" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-ratelimit" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aio-limited 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-secio" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "asn1_der 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "asn1_der 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", "rw-stream-sink 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1785,21 +1893,21 @@ dependencies = [ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "twofish 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-futures 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-futures 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "web-sys 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-tcp" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "get_if_addrs 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "ipnet 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "tk-listen 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1808,40 +1916,40 @@ dependencies = [ [[package]] name = "libp2p-uds" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-wasm-ext" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-futures 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-futures 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-websocket" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rw-stream-sink 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "soketto 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "soketto 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-rustls 0.10.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1851,11 +1959,11 @@ dependencies = [ [[package]] name = "libp2p-yamux" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "yamux 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1869,7 +1977,7 @@ dependencies = [ "bindgen 0.47.3 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1885,6 +1993,17 @@ dependencies = [ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "libz-sys" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "linked-hash-map" version = "0.5.2" @@ -1939,6 +2058,16 @@ dependencies = [ "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "malloc_size_of_derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "matches" version = "0.1.8" @@ -1946,10 +2075,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memchr" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1959,12 +2088,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memory-db" -version = "0.12.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashmap_core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-util-mem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1997,12 +2126,12 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "miniz_oxide" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2010,13 +2139,13 @@ dependencies = [ [[package]] name = "miniz_oxide_c_api" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2028,7 +2157,7 @@ dependencies = [ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2053,7 +2182,7 @@ version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2074,7 +2203,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2096,7 +2225,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.10.23 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2104,7 +2233,7 @@ dependencies = [ "schannel 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2113,7 +2242,7 @@ version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2125,7 +2254,7 @@ dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2134,20 +2263,21 @@ name = "node-cli" version = "2.0.0" dependencies = [ "exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "node-executor 2.0.0", "node-primitives 2.0.0", "node-runtime 2.0.0", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", + "srml-contracts 2.0.0", "srml-finality-tracker 2.0.0", "srml-indices 2.0.0", "srml-timestamp 2.0.0", - "structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-basic-authorship 2.0.0", "substrate-cli 2.0.0", "substrate-client 2.0.0", @@ -2155,6 +2285,7 @@ dependencies = [ "substrate-consensus-aura-primitives 2.0.0", "substrate-consensus-common 2.0.0", "substrate-finality-grandpa 2.0.0", + "substrate-finality-grandpa-primitives 2.0.0", "substrate-inherents 2.0.0", "substrate-keyring 2.0.0", "substrate-keystore 2.0.0", @@ -2164,7 +2295,7 @@ dependencies = [ "substrate-service-test 2.0.0", "substrate-telemetry 2.0.0", "substrate-transaction-pool 2.0.0", - "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "transaction-factory 0.0.1", ] @@ -2174,7 +2305,7 @@ version = "2.0.0" dependencies = [ "node-primitives 2.0.0", "node-runtime 2.0.0", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "srml-balances 2.0.0", @@ -2193,7 +2324,7 @@ dependencies = [ "substrate-state-machine 2.0.0", "substrate-test-client 2.0.0", "substrate-trie 2.0.0", - "trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-root 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2201,9 +2332,9 @@ dependencies = [ name = "node-primitives" version = "2.0.0" dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "sr-std 2.0.0", "substrate-primitives 2.0.0", @@ -2214,10 +2345,10 @@ dependencies = [ name = "node-rpc-client" version = "2.0.0" dependencies = [ - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.29 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core-client 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.31 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core-client 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "node-primitives 2.0.0", "substrate-rpc 2.0.0", @@ -2229,18 +2360,20 @@ version = "2.0.0" dependencies = [ "integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "node-primitives 2.0.0", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "sr-std 2.0.0", "sr-version 2.0.0", "srml-aura 2.0.0", + "srml-authorship 0.1.0", "srml-balances 2.0.0", + "srml-collective 2.0.0", "srml-contracts 2.0.0", - "srml-council 2.0.0", "srml-democracy 2.0.0", + "srml-elections 2.0.0", "srml-executive 2.0.0", "srml-finality-tracker 2.0.0", "srml-grandpa 2.0.0", @@ -2257,6 +2390,7 @@ dependencies = [ "substrate-keyring 2.0.0", "substrate-offchain-primitives 2.0.0", "substrate-primitives 2.0.0", + "substrate-wasm-builder-runner 1.0.2", ] [[package]] @@ -2266,10 +2400,10 @@ dependencies = [ "ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", "exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "node-template-runtime 2.0.0", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "substrate-basic-authorship 2.0.0", @@ -2282,8 +2416,8 @@ dependencies = [ "substrate-primitives 2.0.0", "substrate-service 2.0.0", "substrate-transaction-pool 2.0.0", - "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-root 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2291,9 +2425,9 @@ dependencies = [ name = "node-template-runtime" version = "2.0.0" dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -2310,6 +2444,7 @@ dependencies = [ "substrate-consensus-aura-primitives 2.0.0", "substrate-offchain-primitives 2.0.0", "substrate-primitives 2.0.0", + "substrate-wasm-builder-runner 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2327,7 +2462,7 @@ name = "nom" version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2353,7 +2488,7 @@ name = "num_cpus" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2392,7 +2527,7 @@ dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.9.47 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2408,9 +2543,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2444,12 +2579,13 @@ source = "git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7 [[package]] name = "parity-codec" -version = "3.5.1" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "bitvec 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec-derive 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2460,7 +2596,7 @@ dependencies = [ "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2475,7 +2611,7 @@ dependencies = [ "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multihash 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2498,6 +2634,16 @@ name = "parity-send-wrapper" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "parity-util-mem" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "parity-wasm" version = "0.31.3" @@ -2548,7 +2694,7 @@ name = "parking_lot_core" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2559,7 +2705,7 @@ name = "parking_lot_core" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2571,7 +2717,7 @@ name = "parking_lot_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2585,9 +2731,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2599,7 +2745,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2607,10 +2753,10 @@ name = "paste-impl" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro-hack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2620,7 +2766,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2633,11 +2778,21 @@ name = "percent-encoding" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "pin-utils" +version = "0.1.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "pkg-config" version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "ppv-lite86" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "pretty_assertions" version = "0.5.1" @@ -2660,13 +2815,13 @@ dependencies = [ [[package]] name = "primitive-types" -version = "0.2.4" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "fixed-hash 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-codec 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fixed-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-codec 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "impl-serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "uint 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "uint 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2687,12 +2842,12 @@ dependencies = [ [[package]] name = "proc-macro-hack" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2710,7 +2865,7 @@ dependencies = [ [[package]] name = "protobuf" -version = "2.6.2" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2738,7 +2893,7 @@ name = "quickcheck" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2757,7 +2912,7 @@ name = "rand" version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2767,7 +2922,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2780,7 +2935,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2791,7 +2946,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2803,6 +2958,18 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_chacha" version = "0.1.1" @@ -2812,6 +2979,16 @@ dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_chacha" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_core" version = "0.3.1" @@ -2825,6 +3002,14 @@ name = "rand_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rand_core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_hc" version = "0.1.0" @@ -2833,6 +3018,14 @@ dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_isaac" version = "0.1.1" @@ -2846,7 +3039,7 @@ name = "rand_jitter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2858,7 +3051,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2892,22 +3085,23 @@ dependencies = [ [[package]] name = "rayon" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon-core" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2921,7 +3115,7 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.54" +version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2929,7 +3123,7 @@ name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2939,19 +3133,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "regex" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "regex-automata" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "regex-syntax" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2959,7 +3161,7 @@ dependencies = [ [[package]] name = "remove_dir_all" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2967,14 +3169,13 @@ dependencies = [ [[package]] name = "rhododendron" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2984,7 +3185,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2995,7 +3196,7 @@ name = "rocksdb" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "librocksdb-sys 5.18.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3005,7 +3206,7 @@ version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3046,13 +3247,13 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ryu" -version = "0.2.8" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -3128,7 +3329,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3140,12 +3341,21 @@ dependencies = [ "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "semver" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "semver" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3160,30 +3370,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.92" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.92" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3192,7 +3402,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3220,7 +3430,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3232,7 +3442,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3264,10 +3474,10 @@ name = "slog-json" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3288,7 +3498,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3315,14 +3525,15 @@ dependencies = [ [[package]] name = "soketto" -version = "0.1.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3347,7 +3558,7 @@ version = "2.0.0" dependencies = [ "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3358,8 +3569,8 @@ dependencies = [ "substrate-primitives 2.0.0", "substrate-state-machine 2.0.0", "substrate-test-runtime-client 2.0.0", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", - "trybuild 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", + "trybuild 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3367,16 +3578,16 @@ name = "sr-io" version = "2.0.0" dependencies = [ "environmental 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 2.0.0", "substrate-offchain 2.0.0", "substrate-primitives 2.0.0", "substrate-state-machine 2.0.0", "substrate-trie 2.0.0", - "tiny-keccak 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3386,10 +3597,11 @@ dependencies = [ "integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "primitive-types 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "primitive-types 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-std 2.0.0", "substrate-primitives 2.0.0", @@ -3400,7 +3612,7 @@ name = "sr-sandbox" version = "2.0.0" dependencies = [ "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 2.0.0", "substrate-primitives 2.0.0", @@ -3420,8 +3632,8 @@ name = "sr-version" version = "2.0.0" dependencies = [ "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "sr-std 2.0.0", ] @@ -3430,8 +3642,8 @@ dependencies = [ name = "srml-assets" version = "2.0.0" dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -3445,9 +3657,9 @@ name = "srml-aura" version = "2.0.0" dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -3461,15 +3673,28 @@ dependencies = [ "substrate-primitives 2.0.0", ] +[[package]] +name = "srml-authorship" +version = "0.1.0" +dependencies = [ + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 2.0.0", + "sr-primitives 2.0.0", + "sr-std 2.0.0", + "srml-support 2.0.0", + "srml-system 2.0.0", + "substrate-primitives 2.0.0", +] + [[package]] name = "srml-babe" version = "2.0.0" dependencies = [ "hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -3486,9 +3711,9 @@ dependencies = [ name = "srml-balances" version = "2.0.0" dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -3498,6 +3723,23 @@ dependencies = [ "substrate-primitives 2.0.0", ] +[[package]] +name = "srml-collective" +version = "2.0.0" +dependencies = [ + "hex-literal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 2.0.0", + "sr-primitives 2.0.0", + "sr-std 2.0.0", + "srml-balances 2.0.0", + "srml-support 2.0.0", + "srml-system 2.0.0", + "substrate-primitives 2.0.0", +] + [[package]] name = "srml-contracts" version = "2.0.0" @@ -3505,10 +3747,10 @@ dependencies = [ "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)", "pwasm-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-sandbox 2.0.0", @@ -3523,30 +3765,29 @@ dependencies = [ ] [[package]] -name = "srml-council" +name = "srml-democracy" version = "2.0.0" dependencies = [ - "hex-literal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", "srml-balances 2.0.0", - "srml-democracy 2.0.0", "srml-support 2.0.0", "srml-system 2.0.0", "substrate-primitives 2.0.0", ] [[package]] -name = "srml-democracy" +name = "srml-elections" version = "2.0.0" dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -3560,8 +3801,8 @@ dependencies = [ name = "srml-example" version = "2.0.0" dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "srml-balances 2.0.0", @@ -3575,8 +3816,8 @@ name = "srml-executive" version = "2.0.0" dependencies = [ "hex-literal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -3591,10 +3832,8 @@ dependencies = [ name = "srml-finality-tracker" version = "2.0.0" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -3604,12 +3843,26 @@ dependencies = [ "substrate-primitives 2.0.0", ] +[[package]] +name = "srml-generic-asset" +version = "2.0.0" +dependencies = [ + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 2.0.0", + "sr-primitives 2.0.0", + "sr-std 2.0.0", + "srml-support 2.0.0", + "srml-system 2.0.0", + "substrate-primitives 2.0.0", +] + [[package]] name = "srml-grandpa" version = "2.0.0" dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -3625,10 +3878,10 @@ dependencies = [ name = "srml-indices" version = "2.0.0" dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ref_thread_local 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -3642,8 +3895,8 @@ dependencies = [ name = "srml-metadata" version = "2.0.0" dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 2.0.0", "substrate-primitives 2.0.0", ] @@ -3653,9 +3906,9 @@ name = "srml-session" version = "2.0.0" dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -3663,16 +3916,17 @@ dependencies = [ "srml-system 2.0.0", "srml-timestamp 2.0.0", "substrate-primitives 2.0.0", + "substrate-trie 2.0.0", ] [[package]] name = "srml-staking" version = "2.0.0" dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -3689,8 +3943,8 @@ dependencies = [ name = "srml-sudo" version = "2.0.0" dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -3706,10 +3960,10 @@ version = "2.0.0" dependencies = [ "bitmask 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -3717,6 +3971,7 @@ dependencies = [ "srml-support-procedural 2.0.0", "srml-system 2.0.0", "substrate-inherents 2.0.0", + "substrate-primitives 2.0.0", ] [[package]] @@ -3727,7 +3982,7 @@ dependencies = [ "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "sr-api-macros 2.0.0", "srml-support-procedural-tools 2.0.0", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3738,7 +3993,7 @@ dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "srml-support-procedural-tools-derive 2.0.0", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3747,20 +4002,20 @@ version = "2.0.0" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "srml-support-test" version = "2.0.0" dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "srml-support 2.0.0", "substrate-inherents 2.0.0", "substrate-primitives 2.0.0", - "trybuild 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "trybuild 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3768,9 +4023,9 @@ name = "srml-system" version = "2.0.0" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -3782,8 +4037,8 @@ dependencies = [ name = "srml-timestamp" version = "2.0.0" dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -3797,8 +4052,8 @@ dependencies = [ name = "srml-treasury" version = "2.0.0" dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -3828,12 +4083,12 @@ name = "stream-cipher" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "string" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3846,22 +4101,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "structopt" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "structopt-derive" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3877,7 +4132,7 @@ dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3889,12 +4144,12 @@ dependencies = [ "hex-literal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "node-primitives 2.0.0", "node-runtime 2.0.0", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", - "substrate-bip39 0.2.1 (git+https://github.com/paritytech/substrate-bip39)", + "substrate-bip39 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-primitives 2.0.0", "tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3904,7 +4159,7 @@ name = "substrate" version = "2.0.0" dependencies = [ "ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "node-cli 2.0.0", "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3914,7 +4169,7 @@ name = "substrate-basic-authorship" version = "2.0.0" dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "substrate-client 2.0.0", "substrate-consensus-aura-primitives 2.0.0", @@ -3928,8 +4183,8 @@ dependencies = [ [[package]] name = "substrate-bip39" -version = "0.2.1" -source = "git+https://github.com/paritytech/substrate-bip39#44307fda4ea17fe97aeb93af317fbc8f6ed34193" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3946,18 +4201,19 @@ dependencies = [ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "names 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "rpassword 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", - "structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-client 2.0.0", "substrate-keyring 2.0.0", "substrate-network 2.0.0", @@ -3968,7 +4224,7 @@ dependencies = [ "substrate-telemetry 2.0.0", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3977,13 +4233,13 @@ version = "2.0.0" dependencies = [ "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)", "kvdb-memorydb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-api-macros 2.0.0", "sr-primitives 2.0.0", @@ -4004,14 +4260,14 @@ dependencies = [ name = "substrate-client-db" version = "2.0.0" dependencies = [ - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)", "kvdb-memorydb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)", "kvdb-rocksdb 0.1.4 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)", "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "substrate-client 2.0.0", @@ -4029,10 +4285,11 @@ dependencies = [ name = "substrate-consensus-aura" version = "2.0.0" dependencies = [ - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", @@ -4051,7 +4308,7 @@ dependencies = [ "substrate-service 2.0.0", "substrate-telemetry 2.0.0", "substrate-test-runtime-client 2.0.0", - "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4059,7 +4316,7 @@ dependencies = [ name = "substrate-consensus-aura-primitives" version = "2.0.0" dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "sr-std 2.0.0", "substrate-client 2.0.0", @@ -4070,12 +4327,12 @@ dependencies = [ name = "substrate-consensus-babe" version = "2.0.0" dependencies = [ - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "merlin 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4096,7 +4353,7 @@ dependencies = [ "substrate-service 2.0.0", "substrate-telemetry 2.0.0", "substrate-test-runtime-client 2.0.0", - "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4104,7 +4361,7 @@ dependencies = [ name = "substrate-consensus-babe-primitives" version = "2.0.0" dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "sr-std 2.0.0", "substrate-client 2.0.0", @@ -4116,12 +4373,11 @@ dependencies = [ name = "substrate-consensus-common" version = "2.0.0" dependencies = [ - "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -4129,6 +4385,7 @@ dependencies = [ "substrate-inherents 2.0.0", "substrate-primitives 2.0.0", "substrate-test-runtime-client 2.0.0", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4138,11 +4395,11 @@ version = "2.0.0" dependencies = [ "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", "exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rhododendron 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rhododendron 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-version 2.0.0", @@ -4153,16 +4410,16 @@ dependencies = [ "substrate-keyring 2.0.0", "substrate-primitives 2.0.0", "substrate-transaction-pool 2.0.0", - "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "substrate-consensus-slots" version = "2.0.0" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "substrate-client 2.0.0", @@ -4179,21 +4436,24 @@ version = "2.0.0" dependencies = [ "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", + "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-version 2.0.0", + "substrate-client 2.0.0", + "substrate-offchain 2.0.0", "substrate-panic-handler 2.0.0", "substrate-primitives 2.0.0", + "substrate-runtime-test 2.0.0", "substrate-serializer 2.0.0", "substrate-state-machine 2.0.0", "substrate-trie 2.0.0", - "tiny-keccak 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4202,15 +4462,16 @@ dependencies = [ name = "substrate-finality-grandpa" version = "2.0.0" dependencies = [ - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "finality-grandpa 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "finality-grandpa 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "fork-tree 2.0.0", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "srml-finality-tracker 2.0.0", "substrate-client 2.0.0", @@ -4223,15 +4484,17 @@ dependencies = [ "substrate-service 2.0.0", "substrate-telemetry 2.0.0", "substrate-test-runtime-client 2.0.0", - "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "substrate-finality-grandpa-primitives" version = "2.0.0" dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "sr-std 2.0.0", "substrate-client 2.0.0", @@ -4242,7 +4505,7 @@ dependencies = [ name = "substrate-inherents" version = "2.0.0" dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -4266,7 +4529,7 @@ dependencies = [ "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-primitives 2.0.0", "subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4279,23 +4542,25 @@ dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "fork-tree 2.0.0", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "linked_hash_set 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "quickcheck 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "slog_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4309,31 +4574,31 @@ dependencies = [ "substrate-test-runtime 2.0.0", "substrate-test-runtime-client 2.0.0", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "substrate-offchain" version = "2.0.0" dependencies = [ - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "substrate-client 2.0.0", - "substrate-consensus-common 2.0.0", + "substrate-client-db 2.0.0", "substrate-offchain-primitives 2.0.0", "substrate-primitives 2.0.0", "substrate-test-runtime-client 2.0.0", "substrate-transaction-pool 2.0.0", - "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4348,7 +4613,7 @@ dependencies = [ name = "substrate-panic-handler" version = "2.0.0" dependencies = [ - "backtrace 0.3.30 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4356,14 +4621,13 @@ dependencies = [ name = "substrate-peerset" version = "2.0.0" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4375,27 +4639,28 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hash256-std-hasher 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash256-std-hasher 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "primitive-types 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "primitive-types 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 2.0.0", - "substrate-bip39 0.2.1 (git+https://github.com/paritytech/substrate-bip39)", + "substrate-bip39 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-serializer 2.0.0", "tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "twox-hash 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "twox-hash 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4404,17 +4669,18 @@ version = "2.0.0" dependencies = [ "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core-client 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-derive 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-pubsub 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core-client 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-derive 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-pubsub 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-version 2.0.0", @@ -4425,28 +4691,39 @@ dependencies = [ "substrate-state-machine 2.0.0", "substrate-test-runtime-client 2.0.0", "substrate-transaction-pool 2.0.0", - "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "substrate-rpc-servers" version = "2.0.0" dependencies = [ - "jsonrpc-http-server 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-pubsub 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-ws-server 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-http-server 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-pubsub 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-ws-server 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "substrate-rpc 2.0.0", ] +[[package]] +name = "substrate-runtime-test" +version = "2.0.0" +dependencies = [ + "sr-io 2.0.0", + "sr-sandbox 2.0.0", + "sr-std 2.0.0", + "substrate-primitives 2.0.0", + "substrate-wasm-builder-runner 1.0.2", +] + [[package]] name = "substrate-serializer" version = "2.0.0" dependencies = [ - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4455,16 +4732,17 @@ version = "2.0.0" dependencies = [ "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", "exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "node-executor 2.0.0", "node-primitives 2.0.0", "node-runtime 2.0.0", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", @@ -4481,18 +4759,19 @@ dependencies = [ "substrate-telemetry 2.0.0", "substrate-test-runtime-client 2.0.0", "substrate-transaction-pool 2.0.0", - "sysinfo 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", + "sysinfo 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "substrate-service-test" version = "2.0.0" dependencies = [ - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "substrate-client 2.0.0", @@ -4501,16 +4780,16 @@ dependencies = [ "substrate-primitives 2.0.0", "substrate-service 2.0.0", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "substrate-state-db" version = "2.0.0" dependencies = [ - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-primitives 2.0.0", ] @@ -4519,17 +4798,17 @@ dependencies = [ name = "substrate-state-machine" version = "2.0.0" dependencies = [ - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-panic-handler 2.0.0", "substrate-primitives 2.0.0", "substrate-trie 2.0.0", - "trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-root 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4537,18 +4816,18 @@ name = "substrate-telemetry" version = "2.0.0" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-timer 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slog-scope 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4556,9 +4835,9 @@ dependencies = [ name = "substrate-test-client" version = "2.0.0" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "substrate-client 2.0.0", "substrate-client-db 2.0.0", @@ -4575,9 +4854,8 @@ version = "2.0.0" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memory-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -4594,7 +4872,8 @@ dependencies = [ "substrate-primitives 2.0.0", "substrate-test-runtime-client 2.0.0", "substrate-trie 2.0.0", - "trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "substrate-wasm-builder-runner 1.0.2", + "trie-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4613,12 +4892,12 @@ version = "2.0.0" dependencies = [ "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "substrate-primitives 2.0.0", "substrate-test-runtime 2.0.0", @@ -4629,9 +4908,9 @@ name = "substrate-transaction-pool" version = "2.0.0" dependencies = [ "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "substrate-client 2.0.0", @@ -4646,19 +4925,40 @@ name = "substrate-trie" version = "2.0.0" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hasher 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "memory-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "keccak-hasher 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memory-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 2.0.0", "substrate-primitives 2.0.0", - "trie-bench 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-standardmap 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-bench 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-root 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-standardmap 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "substrate-wasm-builder" +version = "1.0.4" +dependencies = [ + "build-helper 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "substrate-wasm-builder-runner" +version = "1.0.2" + +[[package]] +name = "substrate-wasm-builder-runner" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "subtle" version = "1.0.0" @@ -4671,7 +4971,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "0.15.35" +version = "0.15.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4686,18 +4986,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "sysinfo" -version = "0.8.5" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "doc-comment 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4712,19 +5013,19 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tempfile" -version = "3.0.8" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4738,12 +5039,12 @@ dependencies = [ [[package]] name = "termion" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4768,8 +5069,8 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4789,10 +5090,10 @@ dependencies = [ [[package]] name = "tiny-keccak" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4800,8 +5101,8 @@ name = "tinytemplate" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4809,32 +5110,31 @@ name = "tk-listen" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-sync 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-trace-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4846,7 +5146,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4855,7 +5155,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4864,8 +5164,8 @@ name = "tokio-current-thread" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4873,19 +5173,19 @@ name = "tokio-dns-unofficial" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-executor" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4893,9 +5193,9 @@ name = "tokio-fs" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4904,7 +5204,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4914,14 +5214,14 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-sync 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4932,7 +5232,7 @@ version = "0.10.0-alpha.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustls 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4945,7 +5245,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4954,7 +5254,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4963,18 +5263,18 @@ dependencies = [ [[package]] name = "tokio-threadpool" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4983,9 +5283,9 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4993,26 +5293,18 @@ name = "tokio-tls" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tokio-trace-core" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "tokio-udp" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5026,9 +5318,9 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5042,7 +5334,7 @@ name = "toml" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -5055,7 +5347,7 @@ name = "transaction-factory" version = "0.0.1" dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "substrate-cli 2.0.0", "substrate-client 2.0.0", @@ -5066,26 +5358,26 @@ dependencies = [ [[package]] name = "trie-bench" -version = "0.12.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hasher 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "memory-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-standardmap 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "keccak-hasher 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memory-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-root 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-standardmap 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "trie-db" -version = "0.12.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashmap_core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5093,19 +5385,19 @@ dependencies = [ [[package]] name = "trie-root" -version = "0.12.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "trie-standardmap" -version = "0.12.3" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hasher 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "keccak-hasher 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -5115,13 +5407,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "trybuild" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -5138,7 +5430,7 @@ dependencies = [ [[package]] name = "twox-hash" -version = "1.3.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5161,12 +5453,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "uint" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -5248,7 +5539,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "vcpkg" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -5262,7 +5553,7 @@ version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -5281,9 +5572,9 @@ name = "wabt" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -5309,75 +5600,75 @@ dependencies = [ [[package]] name = "want" -version = "0.0.6" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen" -version = "0.2.45" +version = "0.2.47" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "wasm-bindgen-macro 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.45" +version = "0.2.47" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bumpalo 2.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bumpalo 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-futures" -version = "0.3.22" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.45" +version = "0.2.47" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro-support 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro-support 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.45" +version = "0.2.47" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-backend 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-backend 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.45" +version = "0.2.47" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wasm-bindgen-webidl" -version = "0.2.45" +version = "0.2.47" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5385,21 +5676,22 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-backend 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-backend 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)", "weedle 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-timer" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "send_wrapper 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)", + "web-sys 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -5423,15 +5715,14 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.22" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-webidl 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-webidl 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -5461,7 +5752,7 @@ dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5489,7 +5780,7 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -5545,7 +5836,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", "mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5590,7 +5881,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "nohash-hasher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5602,43 +5893,20 @@ dependencies = [ [[package]] name = "zeroize" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "zeroize" -version = "0.6.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "zeroize_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zeroize" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "zeroize_derive 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize_derive 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "zeroize_derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zeroize_derive" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -5647,19 +5915,19 @@ dependencies = [ "checksum aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2e5b0458ea3beae0d1d8c0f3946564f8e10f90646cf78c06b4351052058d1ee" "checksum aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" "checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" -"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" +"checksum aho-corasick 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "36b7aa1ccb7d7ea3f437cf025a2ab1c47cc6c1bc9fc84918ff449def12f5e282" "checksum aio-limited 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f10b352bc3fc08ae24dc5d2d3ddcac153678533986122dc283d747b12071000" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e73a24bad9bd6a94d6395382a6c69fe071708ae4409f763c5475e14ee896313d" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" -"checksum asn1_der 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9893d63fc3b1c44231e667da6836a33f27d8b6b3bdc82f83da5dfd579d1b6528" +"checksum asn1_der 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bea40e881533b1fe23afca9cd1c1ca022219a10fce604099ecfc96bfa26eaf1a" "checksum asn1_der_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e7f92edafad155aff997fa5b727c6429b91e996b5a5d62a2b0adbae1306b5fe" "checksum assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7deb0a829ca7bcfaf5da70b073a8d128619259a7be8216a355e23f00763059e5" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" -"checksum backtrace 0.3.30 (registry+https://github.com/rust-lang/crates.io-index)" = "ada4c783bb7e7443c14e0480f429ae2cc99da95065aeab7ee1b81ada0419404f" -"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" +"checksum backtrace 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)" = "18b50f5258d1a9ad8396d2d345827875de4261b158124d4c819d9b351454fae5" +"checksum backtrace-sys 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "5b3a000b9c543553af61bc01cbfc403b04b5caa9e421033866f2e98061eb3e61" "checksum base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" @@ -5667,6 +5935,7 @@ dependencies = [ "checksum bindgen 0.47.3 (registry+https://github.com/rust-lang/crates.io-index)" = "df683a55b54b41d5ea8ebfaebb5aa7e6b84e3f3006a78f010dadc9ca88469260" "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum bitmask 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5da9b3d9f6f585199287a473f4f8dfab6566cf827d15c00c219f53c645687ead" +"checksum bitvec 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b67491e1cc6f37da6c4415cd743cb8d2e2c65388acc91ca3094a054cbf3cbd0c" "checksum blake2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91721a6330935673395a0607df4d49a9cb90ae12d259f1b3e0a3f6e1d486872e" "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "checksum block-buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1339a1042f5d9f295737ad4d9a6ab6bf81c84a933dba110b9200cd6d1448b814" @@ -5674,20 +5943,22 @@ dependencies = [ "checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" "checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" "checksum bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0de79cfb98e7aa9988188784d8664b4b5dad6eaaa0863b91d9a4ed871d4f7a42" -"checksum bstr 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "59604ece62a407dc9164732e5adea02467898954c3a5811fd2dc140af14ef15b" -"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" -"checksum bumpalo 2.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "84dca3afd8e01b9526818b7963e5b4916063b3cdf9f10cf6b73ef0bd0ec37aa5" +"checksum bstr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc0572e02f76cb335f309b19e0a0d585b4f62788f7d26de2a13a836a637385f" +"checksum build-helper 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdce191bf3fa4995ce948c8c83b4640a1745457a149e73c6db75b4ffe36aad5f" +"checksum bumpalo 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2cd43d82f27d68911e6ee11ee791fb248f138f5d69424dc02e098d4f152b0b05" "checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" +"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum c_linked_list 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4964518bd3b4a8190e832886cdc0da9794f12e8e6c1613a9e90ff331c4c8724b" +"checksum cargo_metadata 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "929766d993a2fde7a0ae962ee82429069cd7b68839cd9375b98efd719df65d3a" "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" "checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d" "checksum cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7fa24eb00d5ffab90eaeaf1092ac85c04c64aaf358ea6f84505b8116d24c6af" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" -"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" +"checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe" "checksum clang-sys 0.26.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ef0c1bcf2e99c649104bd7a7012d8f8802684400e03db0ec0af48583c6fa0e4" "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" "checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" @@ -5696,26 +5967,22 @@ dependencies = [ "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" "checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" "checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" -"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0363053954f3e679645fc443321ca128b7b950a6fe288cf5f9335cc22ee58394" "checksum criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76f9212ddf2f4a9eb2d401635190600656a1f88a932ef53d06e7fa4c7e02fb8e" "checksum crossbeam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad4c7ea749d9fb09e23c5cb17e3b70650860553a0e2744e38446b1803bf7db94" "checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" -"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" "checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" -"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" "checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" -"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" "checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" "checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" "checksum crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" "checksum crypto-mac 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "779015233ac67d65098614aec748ac1c756ab6677fa2e14cf8b37c08dfed1198" "checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" -"checksum csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9044e25afb0924b5a5fc5511689b0918629e85d68ea591e5e87fbf1e85ea1b3b" -"checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65" +"checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d" +"checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" "checksum ctor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3b4c17619643c1252b5f690084b82639dd7fac141c57c8e77a00e0148132092c" "checksum ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "022cd691704491df67d25d006fe8eca083098253c4d43516c2206479c58c6736" "checksum ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c7dfd2d8b4c82121dfdff120f818e09fc4380b0b7e17a742081a89b94853e87f" @@ -5723,14 +5990,16 @@ dependencies = [ "checksum curve25519-dalek 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5d4b820e8711c211745880150f5fac78ab07d6e3851d8ce9f5a02cedc199174c" "checksum data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f47ca1860a761136924ddd2422ba77b2ea54fe8cc75b9040804a0d9d32ad97" "checksum derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6d944ac6003ed268757ef1ee686753b57efc5fcf0ebe7b64c9fc81e7e32ff839" +"checksum derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a141330240c921ec6d074a3e188a7c7ef95668bb95e7d44fa0e5778ec2a7afe" "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" "checksum digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5b29bf156f3f4b3c4f610a25ff69370616ae6e0657d416de22645483e72af0a" -"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" +"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" "checksum dns-parser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea" +"checksum doc-comment 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "923dea538cea0aa3025e8685b20d6ee21ef99c4f77e954a30febbaac5ec73a97" "checksum ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81956bcf7ef761fb4e1d88de3fa181358a0d26cbcb9755b587a08f9119824b86" "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" "checksum elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "073be79b6538296faf81c631872676600616073817dd9a440c477ad09b408983" -"checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a" +"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" "checksum environmental 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c7464757b80de8930c91c9afe77ddce501826bf9d134a87db2c67d9dc177e2c" "checksum erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3beee4bc16478a1b26f2e80ad819a52d24745e292f521a63c16eea5f74b7eb60" "checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9" @@ -5739,29 +6008,39 @@ dependencies = [ "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" -"checksum finality-grandpa 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5cdd9ef7c48777665dacc9657c272778121d4d09848100bcc2bd9c773c6cf837" -"checksum fixed-hash 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d1a683d1234507e4f3bf2736eeddf0de1dc65996dc0164d57eba0a74bcf29489" -"checksum flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f87e68aa82b2de08a6e037f1385455759df6e445a8df5e005b4297191dbf18aa" +"checksum finality-grandpa 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9e7cba2aaadf09932452a4fc054a77451b31eb99bc0b42bf54bd44f01a9daf4" +"checksum fixed-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "516877b7b9a1cc2d0293cbce23cd6203f0edbfd4090e6ca4489fecb5aa73050e" +"checksum flate2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "550934ad4808d5d39365e5d61727309bf18b3b02c6c56b729cb92e7dd84bc3d8" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" "checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" "checksum fs-swap 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "921d332c89b3b61a826de38c61ee5b6e02c56806cade1b0e5d81bd71f57a71bb" +"checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)" = "a2037ec1c6c1c4f79557762eab1f7eae1f64f6cb418ace90fae88f0942b60139" +"checksum futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "45dc39533a6cae6da2b56da48edae506bb767ec07370f86f70fc062e9d435869" +"checksum futures-channel-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)" = "21c71ed547606de08e9ae744bb3c6d80f5627527ef31ecf2a7210d0e67bc8fae" +"checksum futures-core-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4b141ccf9b7601ef987f36f1c0d9522f76df3bba1cf2e63bfacccc044c4558f5" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" +"checksum futures-executor-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)" = "87ba260fe51080ba37f063ad5b0732c4ff1f737ea18dcb67833d282cdc2c6f14" +"checksum futures-io-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)" = "082e402605fcb8b1ae1e5ba7d7fdfd3e31ef510e2a8367dd92927bb41ae41b3a" +"checksum futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)" = "bf25f91c8a9a1f64c451e91b43ba269ed359b9f52d35ed4b3ce3f9c842435867" +"checksum futures-sink-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4309a25a1069a1f3c10647b227b9afe6722b67a030d3f00a9cbdc171fc038de4" +"checksum futures-timer 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb4a32e84935678650944c6ebd0d912db46405d37bf94f1a058435c5080abcb1" +"checksum futures-util-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)" = "af8198c48b222f02326940ce2b3aa9e6e91a32886eeaad7ca3b8e4c70daa3f4e" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" -"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" +"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fceb69994e330afed50c93524be68c42fa898c2d9fd4ee8da03bd7363acd26f2" "checksum get_if_addrs 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "abddb55a898d32925f3148bd281174a68eeb68bbfd9a5938a57b18f506ee4ef7" "checksum get_if_addrs-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0d04f9fb746cf36b191c00f3ede8bde9c8e64f9f4b05ae2694a9ccf5e3f5ab48" +"checksum getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e65cce4e5084b14874c4e7097f38cab54f47ee554f9194673456ea379dcc4c55" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" -"checksum globset 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef4feaabe24a0a658fd9cf4a9acf6ed284f045c77df0f49020ba3245cfb7b454" -"checksum h2 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "1e42e3daed5a7e17b12a0c23b5b2fbff23a925a570938ebee4baca1a9a1a2240" -"checksum hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ba7fb417e5c470acdd61068c79767d0e65962e70836cf6c9dfd2409f06345ce0" -"checksum hash256-std-hasher 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b2027c19ec91eb304999abae7307d225cf93be42af53b0039f76e98ed5af86" +"checksum globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "925aa2cac82d8834e2b2a4415b6f6879757fb5c0928fc445ae76461a12eed8f2" +"checksum h2 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "a539b63339fbbb00e081e84b6e11bd1d9634a82d91da2984a18ac74a8823f392" +"checksum hash-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c4a2710506bcc28e53b6d48d9686b233a31ad831597da7de91e6112a2fc8f260" +"checksum hash256-std-hasher 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff4a5dcbaf4fe8977852851d137546bcad8679c9582f170032ca35b30701138e" "checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da" "checksum hashmap_core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8e04cb7a5051270ef3fa79f8c7604d581ecfa73d520e74f554e45541c4b5881a" "checksum heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461" @@ -5776,12 +6055,12 @@ dependencies = [ "checksum hmac-drbg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fe727d41d2eec0a6574d887914347e5ff96a3b87177817e2a9820c5c87fecc2" "checksum http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "eed324f0f0daf6ec10c474f150505af2c143f251722bf9dbd1261bd1f2ee2c1a" "checksum http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" -"checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" +"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" "checksum hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" -"checksum hyper 0.12.29 (registry+https://github.com/rust-lang/crates.io-index)" = "e2cd6adf83b3347d36e271f030621a8cf95fd1fd0760546b9fc5a24a0f1447c7" +"checksum hyper 0.12.31 (registry+https://github.com/rust-lang/crates.io-index)" = "6481fff8269772d4463253ca83c788104a7305cb3fb9136bc651a6211e46e03f" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -"checksum impl-codec 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2050d823639fbeae26b2b5ba09aca8907793117324858070ade0673c49f793b" +"checksum impl-codec 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "62ed8ff267bc916dd848a800b96d3129aec73d5b23a5e3d018c83655d0c55371" "checksum impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5158079de9d4158e0ce1de3ae0bd7be03904efc40b3d7dd8b8c301cbf6b52b56" "checksum impl-serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d26be4b97d738552ea423f76c4f681012ff06c3fa36fa968656b3679f60b4a1" "checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" @@ -5791,17 +6070,17 @@ dependencies = [ "checksum ipnet 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e61c2da0d0f700c77d2d313dbf4f93e41d235fa12c6681fee06621036df4c2af" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" -"checksum js-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "9987e7c13a91d9cf0efe59cca48a3a7a70e2b11695d5a4640f85ae71e28f5e73" -"checksum jsonrpc-client-transports 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0245e08f98d627a579cdee6a2138d05ab64f6093efbcdeec50805d121ee13c0c" -"checksum jsonrpc-core 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "288dca7f9713710a29e485076b9340156cb701edb46a881f5d0c31aa4f5b9143" -"checksum jsonrpc-core-client 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05e499e393aaa97cf5ff3a7444549c94a6d27e70be1c300b865187d722f1b426" -"checksum jsonrpc-derive 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b65eafb36286a4251c9a1d4cdf4e9a7cf8fa4f7bf991383e42f0cf26908767" -"checksum jsonrpc-http-server 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea8b3996f19dc6dd90d928c81d30b3ce9535840487734290da9fae3b3185db5d" -"checksum jsonrpc-pubsub 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fcdd238ecccde73faea93760b068f3fe3ca84caeb6b5414c2aabd4f008dad418" -"checksum jsonrpc-server-utils 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "036a53ffa47533dcccf1e1bb16abb0f45ef9a2dc9a63654d2d2cd199b80ad33e" -"checksum jsonrpc-ws-server 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "977ea40f077c027553e4112d750114b9e5cc7bcf5642512838abc2a9b322bd23" +"checksum js-sys 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "eac16f41aa9b9388230b1d6617d7ed897a1af5416b8fe1c8734dcef79c7aae10" +"checksum jsonrpc-client-transports 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6be24a8de4ced80f6fd8b6ace54aa610823a7642976a0e8e00e3bb2f4d8c33f0" +"checksum jsonrpc-core 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0216cf4c95fb373d89c63572672097b8aa74cfcdd77054accbf545d840be5bd7" +"checksum jsonrpc-core-client 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1603b6cc05060de7794c2962edd705e1ad2698bd2b0d2ddd4489f8c85df122b7" +"checksum jsonrpc-derive 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8afff172177878850d133ccdcd93cad794e85d7779ab334998d669ef80e13180" +"checksum jsonrpc-http-server 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a24e140242e0d2e9a694cf8db513a2bd739d24c392e0ad15e0d6d7ee8851e3a2" +"checksum jsonrpc-pubsub 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3c45f7cdb1bb28a3bfb3a0a5184bf99669c9ffe8cf8d7b8a582f2a52bf9944a" +"checksum jsonrpc-server-utils 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d7aac8e0029d19582b68c9fd498d18bdcf0846612c968acc93b6e5ae67eea4e0" +"checksum jsonrpc-ws-server 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "698fee4fcaf09a5927b7e39dd8a8136a102b343cebacaa351fc4def01a050a5b" "checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" -"checksum keccak-hasher 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "af672553b2abac1c86c29fd62c79880638b6abc91d96db4aa42a5baab2bc1ca9" +"checksum keccak-hasher 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3767172fe16797c41f975f12f38247964ace8e5e1a2539b82d5e19f9106b1cb9" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum kvdb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" "checksum kvdb-memorydb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" @@ -5809,30 +6088,31 @@ dependencies = [ "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" -"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" -"checksum libloading 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5692f82b51823e27c4118b3e5c0d98aee9be90633ebc71ad12afef380b50219" -"checksum libp2p 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6abde4e6fc777dc06ae2a15202ddedb1a38d7c71ed16bc10fa704b03f73aec37" -"checksum libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b4ceb4791289534d4c1ad8e4bd3c6f06d3670efa55ce71482951a287df93ddd1" -"checksum libp2p-core-derive 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "851a59dcaab66c96777ae0cace96de88a700243c3b8360ab51c7e093f3727066" -"checksum libp2p-deflate 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "902b44e92e1f8b7e697b3a186d15c841e0e38037f14286513207a5407650a635" -"checksum libp2p-dns 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71a6630a84552b39e5f752e1f6a951d31f3211079465d2e7af73491b6f48fc3f" -"checksum libp2p-floodsub 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9fced4da0c31e0dc8a759472c65fab41db40c01de2d93bc45e1431c13f0564f0" -"checksum libp2p-identify 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1ba5e882d72c71cdf77f45ab68dd715451d3b78a23085f8d385c7a31ec1b4272" -"checksum libp2p-kad 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d71966dbbb4cedcfcdb1d4c87d5dbb6f3f07b465d1ca74f2624256669997d1f2" -"checksum libp2p-mdns 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdbdaea6f0049cc09ba5db00308f5b93105a8a33b65ba2e36bd35da707850ea2" -"checksum libp2p-mplex 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b351bfd67e97154e7b60f62402237671486c8a89f83eabdb6838f37d4d5f006" -"checksum libp2p-noise 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44324032b2f9260d2b862c741d79d250dc02298dbba56354a992528a826ee2d5" -"checksum libp2p-ping 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1ac43ffd01de4210cf1b969bbb55a008c77f9ec22b74df26a6590bb6bd4c93f" -"checksum libp2p-plaintext 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0506e10770bcbcb59f2a6154ce93c8fd5cb9730b6ceb5aa1463164af1fd0b9c6" -"checksum libp2p-ratelimit 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3886b79a35c0348497bab763517a9a2b4965173f4b4c7438d59f1e4dcf5122ff" -"checksum libp2p-secio 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b811272e5cd86d39bd71fb94687025d9802b13daf0998ebe0d3f2885c636c51a" -"checksum libp2p-tcp 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b2c54cb75f17557de6ce0149aa03e729455e2d240f84d854272bc4b11012a324" -"checksum libp2p-uds 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fbedf4a1e72a5f67523915414e9e12d71d128731873f0f24d8b878398fb47aa4" -"checksum libp2p-wasm-ext 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c1f615b56aa2a6f4ec07bf9667be9fff8877b9c5bd5335601af47490eda341" -"checksum libp2p-websocket 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a0d1bfe60577558f48a9fdf9f35c0ee2dc5baa01f685ff847d3b5cf4f12ee135" -"checksum libp2p-yamux 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bf4bfc7ff127cd622502dbe56f10513dd6776b970e33d8ebb6e367f0752324f6" +"checksum libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)" = "3262021842bf00fe07dbd6cf34ff25c99d7a7ebef8deea84db72be3ea3bb0aff" +"checksum libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" +"checksum libp2p 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29f6b3be5b0cb89f7a072352e2a3bf86991dce0909624181e9e343db0b558568" +"checksum libp2p-core 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c71c33e59899d57ed0a14272984705561abd71788a2b303598ec57dac32130e8" +"checksum libp2p-core-derive 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1e6df0fa6933f4be908cfd8c6d627776aa8c909066ba7ce13b017bfe18b9c92b" +"checksum libp2p-deflate 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "448fe9d2231bc21bb308f394346780666a376274ceaf3380e5c7adf3cdbf5a9c" +"checksum libp2p-dns 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67ec2cea26aaccd4bdf264075d6a499bc635b90cb23419bcc3b1f2f0d135c451" +"checksum libp2p-floodsub 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4c39c17f2b7c994106e00ccd71a9941d8574c01bef5f97e36d9a106cbde14fab" +"checksum libp2p-identify 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9455cc0752fd3e3f35e9464598576c54476772eaa927b773f7fdf5686ae51f" +"checksum libp2p-kad 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a1f595983a76012779d6941a9d51fc0b9b95d720315787bf8d73f6672351f6d8" +"checksum libp2p-mdns 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7847e6e13a793d70ee5a5d833ddb13ff277c4c0d4fc65b5bc8543ef37df8cf" +"checksum libp2p-mplex 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29bd0885dd9154d93a1fa83e06a10aba2f0e3a0bf9eb63233c095141fbfaf525" +"checksum libp2p-noise 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f8e0852efc26bfcba11fcc7c4fb593ed00446c19b6d90db39794a3a7ac48e13" +"checksum libp2p-ping 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dfda9d329eacf6a8e875c18b5e5317a47b326cb58372f506fff8b6259c8951a" +"checksum libp2p-plaintext 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "86759777e5441725b60c6e78b23933b03a531b45d1f3e7d1fb430df49e0b151c" +"checksum libp2p-ratelimit 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f965ff88fda7b1fff062b18b25d781b86c17ea335a237958220895f3e3ddfdd8" +"checksum libp2p-secio 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df1d980a61a1423518205f6710e692102c94efb8132b5dcc54ffe5dbac621360" +"checksum libp2p-tcp 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24faf4ebb10b805f2e2221540097f764075edd18ca735cab0430a118382888df" +"checksum libp2p-uds 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f57a4942babd03f582a838238093b08f94521f63c8b12889a914be5c3cc170c2" +"checksum libp2p-wasm-ext 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5427b52a8a51460961fadd72bd9fdcd957a2a7706588559423ccb86b58a52a7d" +"checksum libp2p-websocket 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "152dce704e235f47b9460004d7ac09663d43f4ca3cb99ddb8d4e0be54240673e" +"checksum libp2p-yamux 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "907bf1f31d572aa8537595a784f59c86b94162eb03dc51839c32ab4a05a5faad" "checksum librocksdb-sys 5.18.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d19778314deaa7048f2ea7d07b8aa12e1c227acebe975a37eeab6d2f8c74e41b" "checksum libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "688e8d65e495567c2c35ea0001b26b9debf0b4ea11f8cccc954233b75fc3428a" +"checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" "checksum linked_hash_set 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7c91c4c7bbeb4f2f7c4e5be11e6a05bd6830bc37249c47ce1ad86ad453ff9c" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" @@ -5840,16 +6120,17 @@ dependencies = [ "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +"checksum malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "35adee9ed962cf7d07d62cb58bc45029f3227f5b5b86246caa8632f06c187bc3" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" +"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum memory-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7623b01a4f1b7acb7cf8e3f678f05e15e6ae26cb0b738dfeb5cc186fd6b82ef4" +"checksum memory-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "896b24d1a9850e7a25b070d552f311cbb8735214456efa222dcc4c431073c215" "checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" "checksum merlin 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8c39467de91b004f5b9c06fac5bbc8e7d28309a205ee66905166b70804a71fea" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9e3ae51cea1576ceba0dde3d484d30e6e5b86dee0b2d412fe3a16a15c98202" -"checksum miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c468f2369f07d651a5d0bb2c9079f8488a66d5466efe42d0c5c6466edcb7f71e" -"checksum miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7fe927a42e3807ef71defb191dc87d4e24479b221e67015fe38ae2b7b447bab" +"checksum miniz_oxide 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b6c3756d66cf286314d5f7ebe74886188a9a92f5eee68b06f31ac2b4f314c99d" +"checksum miniz_oxide_c_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5b78ca5446dd9fe0dab00e058731b6b08a8c1d2b9cdb8efb10876e24e9ae2494" "checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" "checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40" "checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" @@ -5876,11 +6157,12 @@ dependencies = [ "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" "checksum parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" -"checksum parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dcb43c05fb71c03b4ea7327bf15694da1e0f23f19d5b1e95bab6c6d74097e336" +"checksum parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7902deb39d3b431897f211c1918789938251e67a740f55effd53201e79c0906c" "checksum parity-codec-derive 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "00a486fd383382ddcb2de928364b1f82571c1e48274fc43b7667a4738ee4056c" "checksum parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "045b3c7af871285146300da35b1932bb6e4639b66c7c98e85d06a32cbc4e8fa7" "checksum parity-multihash 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eb83358a0c05e52c44d658981fec2d146d3516d1adffd9e553684f8c8e9e8fa5" "checksum parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f" +"checksum parity-util-mem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2005637ccf93dbb60c85081ccaaf3f945f573da48dcc79f27f9646caa3ec1dc" "checksum parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)" = "511379a8194230c2395d2f5fa627a5a7e108a9f976656ce723ae68fca4097bfc" "checksum parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4d05f1349491390b1730afba60bb20d55761bef489a954546b58b4b34e1e2ac" "checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" @@ -5895,16 +6177,18 @@ dependencies = [ "checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" +"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" "checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" +"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6" "checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427" -"checksum primitive-types 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6e8612a8dc70f26276fed6131c153ca277cf275ee0a5e2a50cd8a69c697beb8f" +"checksum primitive-types 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "366ef730e56c11fd21ab3e518866cf7feb0fdf7f7c16ddc68485579e9d802787" "checksum proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e" "checksum proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c725b36c99df7af7bf9324e9c999b9e37d92c8f8caf106d82e1d7953218d2d8" -"checksum proc-macro-hack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0c1dd4172a1e1f96f709341418f49b11ea6c2d95d53dca08c0f74cbd332d9cf3" +"checksum proc-macro-hack 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "982a35d1194084ba319d65c4a68d24ca28f5fdb5b8bc20899e4eef8641ea5178" "checksum proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b753ad9ed99dd8efeaa7d2fb8453c8f6bc3e54b97966d35f1bc77ca6865254a" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum protobuf 2.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e9076cae823584ab4d8fab3a111658d1232faf106611dc8378161b7d062b628" +"checksum protobuf 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f00e4a3cb64ecfeac2c0a73c74c68ae3439d7a6bead3870be56ad5dd2620a6f" "checksum pwasm-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "efb0dcbddbb600f47a7098d33762a00552c671992171637f5bb310b37fe1f0e4" "checksum quick-error 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5fb6ccf8db7bbcb9c2eae558db5ab4f3da1c2a87e4e597ed394726bc8ea6ca1d" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" @@ -5914,26 +6198,31 @@ dependencies = [ "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +"checksum rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e193067942ef6f485a349a113329140d0ab9e2168ce92274499bb0e9a4190d9d" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" +"checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" "checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03b418169fb9c46533f326efd6eed2576699c44ca92d3052a066214a8d828929" -"checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473" -"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" +"checksum rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4b0186e22767d5b9738a05eab7c6ac90b15db17e5b5f9bd87976dd7d89a10a4" +"checksum rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe0df8435ac0c397d467b6cad6d25543d06e8a019ef3f6af3c384597515bd2" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" +"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum ref_thread_local 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d813022b2e00774a48eaf43caaa3c20b45f040ba8cbf398e2e8911a06668dbe6" -"checksum regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0b2f0808e7d7e4fb1cb07feb6ff2f4bc827938f24f8c2e6a3beb7370af544bdd" -"checksum regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d76410686f9e3a17f06128962e0ecc5755870bb890c34820c7af7f1db2e1d48" -"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" -"checksum rhododendron 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ae9381ed76c1ec4e8994f1f7d2c6d7e33eed3ff7176e16fece09c2e993fc4a5a" +"checksum regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d9d8297cc20bbb6184f8b45ff61c8ee6a9ac56c156cec8e38c3e5084773c44ad" +"checksum regex-automata 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3ed09217220c272b29ef237a974ad58515bde75f194e3ffa7e6d0bf0f3b01f86" +"checksum regex-syntax 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9b01330cce219c1c6b2e209e5ed64ccd587ae5c67bed91c0b49eecf02ae40e21" +"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" +"checksum rhododendron 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "057fecd57cc69e24d9d215c9f283a42133c3f48952e4fc06b088ecf3ce3d90bb" "checksum ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)" = "426bc186e3e95cac1e4a4be125a4aca7e84c2d616ffc02244eef36e2a60a093c" "checksum rocksdb 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f1651697fefd273bfb4fd69466cc2a9d20de557a0213b97233b22b5e95924b5e" "checksum rpassword 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34fa7bcae7fca3c8471e8417088bbc3ad9af8066b0ecf4f3c0d98a0d772716e" @@ -5942,7 +6231,7 @@ dependencies = [ "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustls 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f271e3552cd835fa28c541c34a7e8fdd8cdff09d77fe4eb8f6c42e87a11b096e" "checksum rw-stream-sink 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9cbe61c20455d3015b2bb7be39e1872310283b8e5a52f5b242b0ac7581fe78" -"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f" +"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" "checksum safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7bf422d23a88c16d5090d455f182bc99c60af4df6a345c63428acf5129e347" "checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" @@ -5953,12 +6242,13 @@ dependencies = [ "checksum sct 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f5adf8fbd58e1b1b52699dc8bed2630faecb6d8c7bee77d009d6bbe4af569b9" "checksum security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2" "checksum security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56" +"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum send_wrapper 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0eddf2e8f50ced781f288c19f18621fa72a3779e3cb58dbf23b07469b0abeb4" -"checksum serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "32746bf0f26eab52f06af0d0aa1984f641341d06d8d673c693871da2d188c9be" -"checksum serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "46a3223d0c9ba936b61c0d2e3e559e3217dbfb8d65d06d26e8b3c25de38bae3e" -"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" +"checksum serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)" = "076a696fdea89c19d3baed462576b8f6d663064414b5c793642da8dfeb99475b" +"checksum serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)" = "ef45eb79d6463b22f5f9e16d283798b7c0175ba6050bc25c1a946c122727fe7b" +"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" "checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68" "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" "checksum sha2 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d963c78ce367df26d7ea8b8cc655c651b42e8a1e584e869c1e17dae3ccb116a" @@ -5972,69 +6262,69 @@ dependencies = [ "checksum slog_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eff3b513cf2e0d1a60e1aba152dc72bedc5b05585722bb3cebd7bcb1e31b98f" "checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" "checksum snow 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5a64f02fd208ef15bd2d1a65861df4707e416151e1272d02c8faafad1c138100" -"checksum soketto 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8cf3ae22c0bce5437c7dce6a2b00e492c19da1feb21ad64a7b6fd7058438c3f2" +"checksum soketto 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "db2383e992ba8ba8205cd1169cac2efdf325d3a0da465dc35f63a2074598347e" "checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3" "checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" "checksum static_slice 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "92a7e0c5e3dfb52e8fbe0e63a1b947bbb17b4036408b151353c4491374931362" "checksum stream-cipher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8861bc80f649f5b4c9bd38b696ae9af74499d479dbfb327f0607de6b326a36bc" -"checksum string 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0bbfb8937e38e34c3444ff00afb28b0811d9554f15c5ad64d12b0308d1d1995" +"checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" -"checksum structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fa19a5a708e22bb5be31c1b6108a2a902f909c4b9ba85cba44c06632386bc0ff" -"checksum structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "c6d59d0ae8ef8de16e49e3ca7afa16024a3e0dfd974a75ef93fdc5464e34523f" +"checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" +"checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" "checksum strum 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1810e25f576e7ffce1ff5243b37066da5ded0310b3274c20baaeccb1145b2806" "checksum strum_macros 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "572a2f4e53dd4c3483fd79e5cc10ddd773a3acb1169bbfe8762365e107110579" -"checksum substrate-bip39 0.2.1 (git+https://github.com/paritytech/substrate-bip39)" = "" +"checksum substrate-bip39 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d69ace596e9ca97837cc41f8edcfc4e0a997f227d5fc153d1010b60a0fe9acda" +"checksum substrate-wasm-builder-runner 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f52ecbff6cc3d6e5c6401828e15937b680f459d6803ce238f01fe615bc40d071" "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" "checksum subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "01dca13cf6c3b179864ab3292bd794e757618d35a7766b7c46050c614ba00829" -"checksum syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)" = "641e117d55514d6d918490e47102f7e08d096fdde360247e4a10f7a91a8478d3" +"checksum syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d960b829a55e56db167e861ddb43602c003c7be0bee1d345021703fac2fb7c" "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" -"checksum sysinfo 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cf62641ed7e88e20242b948d17b9fcc37e80b5599cf09cde190d6d4bb4bf289" +"checksum sysinfo 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c3e2cab189e59f72710e3dd5e1e0d5be0f6c5c999c326f2fdcdf3bf4483ec9fd" "checksum target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c63f48baada5c52e65a29eef93ab4f8982681b67f9e8d29c7b05abcfec2b9ffe" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" -"checksum tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dc4738f2e68ed2855de5ac9cdbe05c9216773ecde4739b2f095002ab03a13ef" +"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" -"checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea" +"checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330" "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c1c5676413eaeb1ea35300a0224416f57abc3bd251657e0fafc12c47ff98c060" -"checksum tiny-keccak 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dbbdebb0b801c7fa4260b6b9ac5a15980276d7d7bcc2dc2959a7c4dc8b426a1a" +"checksum tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d8a021c69bb74a44ccedb824a046447e2c84a01df9e5c20779750acb38e11b2" "checksum tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4574b75faccaacddb9b284faecdf0b544b80b6b294f3d062d325c5726a209c20" "checksum tk-listen 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5462b0f968c0457efe38fcd2df7e487096b992419e4f5337b06775a614bbda4b" -"checksum tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "ec2ffcf4bcfc641413fa0f1427bf8f91dfc78f56a6559cbf50e04837ae442a87" +"checksum tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" "checksum tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" "checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" "checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443" "checksum tokio-dns-unofficial 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82c65483db54eb91b4ef3a9389a3364558590faf30ce473141707c0e16fda975" -"checksum tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "83ea44c6c0773cc034771693711c35c677b4b5a4b21b9e7071704c54de7d555e" +"checksum tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f27ee0e6db01c5f0b2973824547ce7e637b2ed79b891a9677b0de9bd532b6ac" "checksum tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe6dc22b08d6993916647d108a1a7d15b9cd29c4f4496c62b92c45b5041b7af" "checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926" "checksum tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6af16bfac7e112bea8b0442542161bfc41cbfa4466b580bdda7d18cb88b911ce" "checksum tokio-rustls 0.10.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)" = "316fdbc899efec48b3b492bd0f339e6d81c4ee96a409257572147ec341943452" "checksum tokio-sync 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2162248ff317e2bc713b261f242b69dbb838b85248ed20bb21df56d60ea4cae7" "checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" -"checksum tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72558af20be886ea124595ea0f806dd5703b8958e4705429dd58b3d8231f72f2" +"checksum tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "90ca01319dea1e376a001e8dc192d42ebde6dd532532a5bad988ac37db365b19" "checksum tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f2106812d500ed25a4f38235b9cae8f78a09edf43203e16e59c3b769a342a60e" "checksum tokio-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "354b8cd83825b3c20217a9dc174d6a0c67441a2fae5c41bcb1ea6679f6ae0f7c" -"checksum tokio-trace-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9c8a256d6956f7cb5e2bdfe8b1e8022f1a09206c6c2b1ba00f3b746b260c613" "checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92" "checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" "checksum toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8c96d7873fa7ef8bdeb3a9cda3ac48389b4154f32b9803b4bc26220b677b039" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" -"checksum trie-bench 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ba20f7d9865497ea46511860b43e05a44f4ac9a76ee089d34cd80a839a690264" -"checksum trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1ba73747fd3a64ab531274c04cb588dfa9d30d972d62990831e63fbce2cfec59" -"checksum trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfa2e20c4f1418ac2e71ddc418e35e1b56e34022e2146209ffdbf1b2de8b1bd9" -"checksum trie-standardmap 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ebaa4b340046196efad8872b2dffe585b5ea330230dc44ee14e399f77da29f51" +"checksum trie-bench 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "401abff5ad06075d2c65d1eedeaaa70616d0df268f3186a82cf1aa2d798977d7" +"checksum trie-db 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1803d8ff63ec3743bee883aacf3df74c524ffab188d9abebe18ded4da0dcd5d4" +"checksum trie-root 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "226f4b2e7bc6a71172ffe7f137385cf63833de7c684059dde7520ddbf1fb04f4" +"checksum trie-standardmap 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b65b79aee5dcdcc7247fdd811f7e26b47e65ecc17f776ecf5db8e8fd46db3b54" "checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" -"checksum trybuild 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d1506db833ec4a139b8e3d2e88125d8999270cc944046ca1fb138f6bbfbc2e43" +"checksum trybuild 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b7592bfd3449da952920cb55618d55f34779293127f76d946c4a54f258ca87b8" "checksum twofish 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d261e83e727c8e2dbb75dacac67c36e35db36a958ee504f2164fc052434e1" -"checksum twox-hash 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6c7bcecad121018bdcd6b709fa2325b004878fcb3d3067934ce90749f0faff9a" +"checksum twox-hash 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7834480552ffc48e1930ceddd701f47d2234319d80b7bcbbe2fe7202933c101" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" -"checksum uint 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2143cded94692b156c356508d92888acc824db5bffc0b4089732264c6fcf86d4" +"checksum uint 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5375d2c574f89adad4108ad525c93e39669853a602560bf5ed4ca9943b10799" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a84e5511b2a947f3ae965dcb29b13b7b1691b6e7332cf5dbc1744138d5acb7f6" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" @@ -6046,7 +6336,7 @@ dependencies = [ "checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9d50aa7650df78abf942826607c62468ce18d9019673d4a2ebe1865dbb96ffde" -"checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d" +"checksum vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "33dd455d0f96e90a75803cfeb7f948768c08d70a6de9a8d2362461935698bf95" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" @@ -6054,18 +6344,18 @@ dependencies = [ "checksum wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "74e463a508e390cc7447e70f640fbf44ad52e1bd095314ace1fdf99516d32add" "checksum wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a6265b25719e82598d104b3717375e37661d41753e2c84cde3f51050c7ed7e3c" "checksum walkdir 2.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c7904a7e2bb3cdf0cf5e783f44204a85a37a93151738fa349f06680f59a98b45" -"checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3" -"checksum wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "b7ccc7b93cfd13e26700a9e2e41e6305f1951b87e166599069f77d10358100e6" -"checksum wasm-bindgen-backend 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "1953f91b1608eb1522513623c7739f047bb0fed4128ce51a93f08e12cc314645" -"checksum wasm-bindgen-futures 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "fa1af11c73eca3dc8c51c76ea475a4416e912da6402064a49fc6c0214701866d" -"checksum wasm-bindgen-macro 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "0f69da5696545d7ca6607a2e4b1a0edf5a6b36b2c49dbb0f1df6ad1d92884047" -"checksum wasm-bindgen-macro-support 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d4246f3bc73223bbb846f4f2430a60725826a96c9389adf715ed1d5af46dec6" -"checksum wasm-bindgen-shared 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "c08381e07e7a79e5e229ad7c60d15833d19033542cc5dd91d085df59d235f4a6" -"checksum wasm-bindgen-webidl 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "1f42ff7adb8102bf5ad8adbc45b1635c520c8175f9fdf6eb2c54479d485d435a" -"checksum wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad9ac33c834103916e373d648adf65f58c83fb3d8a0f3e6b9a64bca7253a4dca" +"checksum want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" +"checksum wasm-bindgen 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)" = "22029998cc650473cb05f10f19c06a1536b9e1f1572e4f5dacd45ab4d3f85877" +"checksum wasm-bindgen-backend 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)" = "6f858ff3cb4196c702e8c24b75fba1d3ab46958de4f7c253627f0507aae1507c" +"checksum wasm-bindgen-futures 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "cc16facd42fc3d0fa0cae78b39516bac04496cf80518fd09bbfa33e9b0e9c92d" +"checksum wasm-bindgen-macro 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)" = "15c29f04eb117312931e7b02878453ee63d67a6f291797651890128bf5ee71db" +"checksum wasm-bindgen-macro-support 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)" = "92b1356b623816248dfe0e2c4b7e113618d647808907ff6a3d9838ebee8e82ee" +"checksum wasm-bindgen-shared 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)" = "15de16ddb30cfd424a87598b30021491bae1607d32e52056979865c98b7913b4" +"checksum wasm-bindgen-webidl 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)" = "21724123084234fff2f986018b790afc5d6f45c9a3903025e6c55d0068cb7d15" +"checksum wasm-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3d6101df9a5987df809216bdda7289f52b58128e6b6a6546e9ee3e6b632b4921" "checksum wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aebbaef470840d157a5c47c8c49f024da7b1b80e90ff729ca982b2b80447e78b" "checksum wasmi-validation 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab380192444b3e8522ae79c0a1976e42a82920916ccdfbce3def89f456ea33f3" -"checksum web-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "540b8259eb242ff3a566fa0140bda03a4ece4e5c226e1284b5c95dddcd4341f6" +"checksum web-sys 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "22306ce642c58266cb5c5938150194911322bc179aa895146076217410ddbc82" "checksum webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4f7e1cd7900a3a6b65a3e8780c51a3e6b59c0e2c55c6dc69578c288d69f7d082" "checksum webpki-roots 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c10fa4212003ba19a564f25cd8ab572c6791f99a03cc219c13ed35ccab00de0e" "checksum websocket 0.22.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0adcd2a64c5746c9702b354a1b992802b0c363df1dfa324a74cb7aebe10e0cbf" @@ -6084,8 +6374,5 @@ dependencies = [ "checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" "checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" "checksum yamux 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "01bd67889938c48f0049fc60a77341039e6c3eaf16cb7693e6ead7c0ba701295" -"checksum zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8ddfeb6eee2fb3b262ef6e0898a52b7563bb8e0d5955a313b3cf2f808246ea14" -"checksum zeroize 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e68403b858b6af538b11614e62dfe9ab2facba9f13a0cafb974855cfb495ec95" -"checksum zeroize 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b60a6c572b91d8ecb0a460950d84fe5b40699edd07d65f73789b31237afc8f66" -"checksum zeroize_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3f07490820219949839d0027b965ffdd659d75be9220c00798762e36c6cd281" -"checksum zeroize_derive 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9dac4b660d969bff9c3fe1847a891cacaa8b21dd5f2aae6e0a3e0975aea96431" +"checksum zeroize 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4177936c03b5a349c1b8e4509c46add268e66bc66fe92663729fa0570fe4f213" +"checksum zeroize_derive 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afd1469e4bbca3b96606d26ba6e9bd6d3aed3b1299c82b92ec94377d22d78dbc" diff --git a/Cargo.toml b/Cargo.toml index f45353204f05ba3ec1c0a339eeb75cc7dafcb2c0..b8b6311a30cb9732f4253f57bd7f2e56144db4cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ members = [ "core/consensus/rhd", "core/consensus/slots", "core/executor", + "core/executor/runtime-test", "core/finality-grandpa", "core/finality-grandpa/primitives", "core/inherents", @@ -55,21 +56,26 @@ members = [ "core/transaction-pool", "core/transaction-pool/graph", "core/trie", - "core/util/fork-tree", + "core/utils/fork-tree", + "core/utils/wasm-builder", + "core/utils/wasm-builder-runner", "srml/support", "srml/support/procedural", "srml/support/procedural/tools", "srml/support/procedural/tools/derive", "srml/support/test", + "srml/authorship", "srml/assets", "srml/aura", "srml/balances", "srml/contracts", - "srml/council", + "srml/collective", "srml/democracy", + "srml/elections", "srml/example", "srml/executive", "srml/finality-tracker", + "srml/generic-asset", "srml/grandpa", "srml/indices", "srml/metadata", @@ -88,11 +94,6 @@ members = [ "subkey", "test-utils/chain-spec-builder", ] -exclude = [ - "node/runtime/wasm", - "core/executor/wasm", - "core/test-runtime/wasm", -] [badges] travis-ci = { repository = "paritytech/substrate", branch = "master" } diff --git a/Dockerfile b/Dockerfile index c5944dbab6de9231c9fa61af735fcf48d2b5be6b..b7512b26561edd71bd099b6399fd70eb4a4aa425 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,7 +20,6 @@ RUN curl https://sh.rustup.rs -sSf | sh -s -- -y && \ rustup target add wasm32-unknown-unknown --toolchain nightly && \ cargo install --git https://github.com/alexcrichton/wasm-gc && \ rustup default nightly && \ - ./scripts/build.sh && \ rustup default stable && \ cargo build --$PROFILE diff --git a/README.adoc b/README.adoc index 826370ee6f5a0a7f03f178f80ca60cf5a37a6d79..fd929e87a26ae4847375771c5892f50697cab163 100644 --- a/README.adoc +++ b/README.adoc @@ -138,7 +138,7 @@ Now, edit `~/chainspec.json` in your editor. There are a lot of individual field [source, json] ---- "timestamp": { - "period": 10 + "minimumPeriod": 10 }, ---- @@ -264,7 +264,6 @@ Then build the code: [source, shell] ---- -./scripts/build.sh # Builds the WebAssembly binaries cargo build # Builds all native code ---- @@ -309,6 +308,24 @@ cargo run --release \-- \ Additional Substrate CLI usage options are available and may be shown by running `cargo run \-- --help`. +== WASM binaries + +The WASM binaries are built during the normal `cargo build` process. To control the WASM binary building, +we support multiple environment variables: + +* `SKIP_WASM_BUILD` - Skips building any WASM binary. This is useful when only native should be recompiled. +* `BUILD_DUMMY_WASM_BINARY` - Builds dummy WASM binaries. These dummy binaries are empty and useful + for `cargo check` runs. +* `WASM_BUILD_TYPE` - Sets the build type for building WASM binaries. Supported values are `release` or `debug`. + By default the build type is equal to the build type used by the main build. +* `TRIGGER_WASM_BUILD` - Can be set to trigger a WASM build. On subsequent calls the value of the variable + needs to change. As WASM builder instructs `cargo` to watch for file changes + this environment variable should only be required in certain circumstances. + +Each project can be skipped individually by using the environment variable `SKIP_PROJECT_NAME_WASM_BUILD`. +Where `PROJECT_NAME` needs to be replaced by the name of the cargo project, e.g. `node-runtime` will +be `NODE_RUNTIME`. + [[flaming-fir]] === Joining the Flaming Fir Testnet diff --git a/core/basic-authorship/Cargo.toml b/core/basic-authorship/Cargo.toml index 547fca9030ee651ec0680d1caf01b39035bf4623..fa409f1b747d13472a38f28cbf7e701ab1ec6ae2 100644 --- a/core/basic-authorship/Cargo.toml +++ b/core/basic-authorship/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] log = "0.4" -codec = { package = "parity-codec", version = "3.2" } +codec = { package = "parity-codec", version = "4.1.1" } runtime_primitives = { package = "sr-primitives", path = "../../core/sr-primitives" } client = { package = "substrate-client", path = "../../core/client" } aura_primitives = { package = "substrate-consensus-aura-primitives", path = "../../core/consensus/aura/primitives" } diff --git a/core/cli/Cargo.toml b/core/cli/Cargo.toml index 6ca50ba5f8404277bb9e4377e199cd6c5a3ab813..bf583a3b7dc2e3b2fefb117f3a03d87c8791038f 100644 --- a/core/cli/Cargo.toml +++ b/core/cli/Cargo.toml @@ -18,6 +18,7 @@ lazy_static = "1.3" app_dirs = "1.2" tokio = "0.1.7" futures = "0.1.17" +futures03 = { package = "futures-preview", version = "0.3.0-alpha.17", features = ["compat"] } fdlimit = "0.1" exit-future = "0.1" serde_json = "1.0" diff --git a/core/cli/src/informant.rs b/core/cli/src/informant.rs index fda93d22e0a0040cbecfcd91aceeca9579015ef0..c066c3b4d1dd89cc25faa8cc283c537d1855e445 100644 --- a/core/cli/src/informant.rs +++ b/core/cli/src/informant.rs @@ -20,6 +20,7 @@ use ansi_term::Colour; use std::fmt; use std::time; use futures::{Future, Stream}; +use futures03::{StreamExt as _, TryStreamExt as _}; use service::{Service, Components}; use tokio::runtime::TaskExecutor; use network::SyncState; @@ -40,39 +41,36 @@ pub fn start(service: &Service, exit: ::exit_future::Exit, handle: TaskExe /// Creates an informant in the form of a `Future` that must be polled regularly. pub fn build(service: &Service) -> impl Future where C: Components { - let network = service.network(); let client = service.client(); let mut last_number = None; let mut last_update = time::Instant::now(); - let display_notifications = network.status().for_each(move |sync_status| { + let display_notifications = service.network_status().for_each(move |(net_status, _)| { let info = client.info(); let best_number = info.chain.best_number.saturated_into::(); let best_hash = info.chain.best_hash; let speed = move || speed(best_number, last_number, last_update); last_update = time::Instant::now(); - let (status, target) = match (sync_status.sync.state, sync_status.sync.best_seen_block) { + let (status, target) = match (net_status.sync_state, net_status.best_seen_block) { (SyncState::Idle, _) => ("Idle".into(), "".into()), (SyncState::Downloading, None) => (format!("Syncing{}", speed()), "".into()), (SyncState::Downloading, Some(n)) => (format!("Syncing{}", speed()), format!(", target=#{}", n)), }; last_number = Some(best_number); let finalized_number: u64 = info.chain.finalized_number.saturated_into::(); - let bandwidth_download = network.average_download_per_sec(); - let bandwidth_upload = network.average_upload_per_sec(); info!( target: "substrate", "{}{} ({} peers), best: #{} ({}), finalized #{} ({}), ⬇ {} ⬆ {}", Colour::White.bold().paint(&status), target, - Colour::White.bold().paint(format!("{}", sync_status.num_peers)), + Colour::White.bold().paint(format!("{}", net_status.num_connected_peers)), Colour::White.paint(format!("{}", best_number)), best_hash, Colour::White.paint(format!("{}", finalized_number)), info.chain.finalized_hash, - TransferRateFormat(bandwidth_download), - TransferRateFormat(bandwidth_upload), + TransferRateFormat(net_status.average_download_per_sec), + TransferRateFormat(net_status.average_upload_per_sec), ); Ok(()) @@ -84,7 +82,7 @@ where C: Components { Some((info.chain.best_number, info.chain.best_hash)) }; - let display_block_import = client.import_notification_stream().for_each(move |n| { + let display_block_import = client.import_notification_stream().map(|v| Ok::<_, ()>(v)).compat().for_each(move |n| { // detect and log reorganizations. if let Some((ref last_num, ref last_hash)) = last { if n.header.parent_hash() != last_hash { diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index c14c9625917e51d9a6b487668b634151d38429c8..cc31af184ed9ce1288708243f82687de34f94b65 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -32,8 +32,7 @@ use service::{ }; use network::{ self, multiaddr::Protocol, - config::{NetworkConfiguration, NonReservedPeerMode, NodeKeyConfig}, - build_multiaddr, + config::{NetworkConfiguration, TransportConfig, NonReservedPeerMode, NodeKeyConfig, build_multiaddr}, }; use primitives::H256; @@ -250,16 +249,16 @@ where params.node_key.as_ref().map(parse_secp256k1_secret).unwrap_or_else(|| Ok(params.node_key_file .or_else(|| net_config_file(net_config_dir, NODE_KEY_SECP256K1_FILE)) - .map(network::Secret::File) - .unwrap_or(network::Secret::New))) + .map(network::config::Secret::File) + .unwrap_or(network::config::Secret::New))) .map(NodeKeyConfig::Secp256k1), NodeKeyType::Ed25519 => params.node_key.as_ref().map(parse_ed25519_secret).unwrap_or_else(|| Ok(params.node_key_file .or_else(|| net_config_file(net_config_dir, NODE_KEY_ED25519_FILE)) - .map(network::Secret::File) - .unwrap_or(network::Secret::New))) + .map(network::config::Secret::File) + .unwrap_or(network::config::Secret::New))) .map(NodeKeyConfig::Ed25519) } } @@ -277,18 +276,18 @@ fn invalid_node_key(e: impl std::fmt::Display) -> error::Error { } /// Parse a Secp256k1 secret key from a hex string into a `network::Secret`. -fn parse_secp256k1_secret(hex: &String) -> error::Result { +fn parse_secp256k1_secret(hex: &String) -> error::Result { H256::from_str(hex).map_err(invalid_node_key).and_then(|bytes| - network::identity::secp256k1::SecretKey::from_bytes(bytes) - .map(network::Secret::Input) + network::config::identity::secp256k1::SecretKey::from_bytes(bytes) + .map(network::config::Secret::Input) .map_err(invalid_node_key)) } /// Parse a Ed25519 secret key from a hex string into a `network::Secret`. -fn parse_ed25519_secret(hex: &String) -> error::Result { +fn parse_ed25519_secret(hex: &String) -> error::Result { H256::from_str(&hex).map_err(invalid_node_key).and_then(|bytes| - network::identity::ed25519::SecretKey::from_bytes(bytes) - .map(network::Secret::Input) + network::config::identity::ed25519::SecretKey::from_bytes(bytes) + .map(network::config::Secret::Input) .map_err(invalid_node_key)) } @@ -354,7 +353,10 @@ fn fill_network_configuration( config.in_peers = cli.in_peers; config.out_peers = cli.out_peers; - config.enable_mdns = !is_dev && !cli.no_mdns; + config.transport = TransportConfig::Normal { + enable_mdns: !is_dev && !cli.no_mdns, + wasm_external_transport: None, + }; Ok(()) } @@ -374,7 +376,7 @@ where let spec = load_spec(&cli.shared_params, spec_factory)?; let mut config = service::Configuration::default_with_spec(spec.clone()); if cli.interactive_password { - config.password = input_keystore_password()? + config.password = input_keystore_password()?.into() } config.impl_name = impl_name; @@ -399,13 +401,9 @@ where let base_path = base_path(&cli.shared_params, version); - config.keystore_path = cli.keystore_path - .unwrap_or_else(|| keystore_path(&base_path, config.chain_spec.id())) - .to_string_lossy() - .into(); + config.keystore_path = cli.keystore_path.or_else(|| Some(keystore_path(&base_path, config.chain_spec.id()))); - config.database_path = - db_path(&base_path, config.chain_spec.id()).to_string_lossy().into(); + config.database_path = db_path(&base_path, config.chain_spec.id()); config.database_cache_size = cli.database_cache_size; config.state_cache_size = cli.state_cache_size; config.pruning = match cli.pruning { @@ -426,12 +424,13 @@ where }; let exec = cli.execution_strategies; + let exec_all_or = |strat: params::ExecutionStrategy| exec.execution.unwrap_or(strat).into(); config.execution_strategies = ExecutionStrategies { - syncing: exec.syncing_execution.into(), - importing: exec.importing_execution.into(), - block_construction: exec.block_construction_execution.into(), - offchain_worker: exec.offchain_worker_execution.into(), - other: exec.other_execution.into(), + syncing: exec_all_or(exec.execution_syncing), + importing: exec_all_or(exec.execution_import_block), + block_construction: exec_all_or(exec.execution_block_construction), + offchain_worker: exec_all_or(exec.execution_offchain_worker), + other: exec_all_or(exec.execution_other), }; config.offchain_worker = match (cli.offchain_worker, role) { @@ -443,6 +442,8 @@ where config.roles = role; config.disable_grandpa = cli.no_grandpa; + config.grandpa_voter = cli.grandpa_voter; + let is_dev = cli.shared_params.dev; @@ -594,7 +595,7 @@ where let base_path = base_path(cli, version); let mut config = service::Configuration::default_with_spec(spec.clone()); - config.database_path = db_path(&base_path, spec.id()).to_string_lossy().into(); + config.database_path = db_path(&base_path, spec.id()); Ok(config) } @@ -612,7 +613,7 @@ where { let config = create_config_with_db_path::(spec_factory, &cli.shared_params, version)?; - info!("DB path: {}", config.database_path); + info!("DB path: {}", config.database_path.display()); let from = cli.from.unwrap_or(1); let to = cli.to; let json = cli.json; @@ -645,7 +646,9 @@ where None => Box::new(stdin()), }; - service::chain_ops::import_blocks::(config, exit.into_exit(), file).map_err(Into::into) + let fut = service::chain_ops::import_blocks::(config, exit.into_exit(), file)?; + tokio::run(fut); + Ok(()) } fn revert_chain( @@ -809,7 +812,7 @@ fn kill_color(s: &str) -> String { mod tests { use super::*; use tempdir::TempDir; - use network::identity::{secp256k1, ed25519}; + use network::config::identity::{secp256k1, ed25519}; #[test] fn tests_node_name_good() { @@ -841,10 +844,10 @@ mod tests { node_key_file: None }; node_key_config(params, &net_config_dir).and_then(|c| match c { - NodeKeyConfig::Secp256k1(network::Secret::Input(ref ski)) + NodeKeyConfig::Secp256k1(network::config::Secret::Input(ref ski)) if node_key_type == NodeKeyType::Secp256k1 && &sk[..] == ski.to_bytes() => Ok(()), - NodeKeyConfig::Ed25519(network::Secret::Input(ref ski)) + NodeKeyConfig::Ed25519(network::config::Secret::Input(ref ski)) if node_key_type == NodeKeyType::Ed25519 && &sk[..] == ski.as_ref() => Ok(()), _ => Err(error::Error::Input("Unexpected node key config".into())) @@ -869,9 +872,9 @@ mod tests { node_key_file: Some(file.clone()) }; node_key_config(params, &net_config_dir).and_then(|c| match c { - NodeKeyConfig::Secp256k1(network::Secret::File(ref f)) + NodeKeyConfig::Secp256k1(network::config::Secret::File(ref f)) if node_key_type == NodeKeyType::Secp256k1 && f == &file => Ok(()), - NodeKeyConfig::Ed25519(network::Secret::File(ref f)) + NodeKeyConfig::Ed25519(network::config::Secret::File(ref f)) if node_key_type == NodeKeyType::Ed25519 && f == &file => Ok(()), _ => Err(error::Error::Input("Unexpected node key config".into())) }) @@ -903,9 +906,9 @@ mod tests { let typ = params.node_key_type; node_key_config::(params, &None) .and_then(|c| match c { - NodeKeyConfig::Secp256k1(network::Secret::New) + NodeKeyConfig::Secp256k1(network::config::Secret::New) if typ == NodeKeyType::Secp256k1 => Ok(()), - NodeKeyConfig::Ed25519(network::Secret::New) + NodeKeyConfig::Ed25519(network::config::Secret::New) if typ == NodeKeyType::Ed25519 => Ok(()), _ => Err(error::Error::Input("Unexpected node key config".into())) }) @@ -918,10 +921,10 @@ mod tests { let typ = params.node_key_type; node_key_config(params, &Some(net_config_dir.clone())) .and_then(move |c| match c { - NodeKeyConfig::Secp256k1(network::Secret::File(ref f)) + NodeKeyConfig::Secp256k1(network::config::Secret::File(ref f)) if typ == NodeKeyType::Secp256k1 && f == &dir.join(NODE_KEY_SECP256K1_FILE) => Ok(()), - NodeKeyConfig::Ed25519(network::Secret::File(ref f)) + NodeKeyConfig::Ed25519(network::config::Secret::File(ref f)) if typ == NodeKeyType::Ed25519 && f == &dir.join(NODE_KEY_ED25519_FILE) => Ok(()), _ => Err(error::Error::Input("Unexpected node key config".into())) diff --git a/core/cli/src/params.rs b/core/cli/src/params.rs index 0cdc633188d7dc3ef8ee80b6bece823e1730b74f..78899ccd4cb010b6dc293fa0844738ecd48d23a1 100644 --- a/core/cli/src/params.rs +++ b/core/cli/src/params.rs @@ -33,13 +33,12 @@ macro_rules! impl_get_log_filter { arg_enum! { /// How to execute blocks - #[derive(Debug, Clone)] + #[derive(Debug, Clone, Copy)] pub enum ExecutionStrategy { Native, Wasm, Both, NativeElseWasm, - NativeWhenPossible, } } @@ -50,7 +49,6 @@ impl Into for ExecutionStrategy { ExecutionStrategy::Wasm => client::ExecutionStrategy::AlwaysWasm, ExecutionStrategy::Both => client::ExecutionStrategy::Both, ExecutionStrategy::NativeElseWasm => client::ExecutionStrategy::NativeElseWasm, - ExecutionStrategy::NativeWhenPossible => client::ExecutionStrategy::NativeWhenPossible, } } } @@ -227,7 +225,7 @@ pub struct TransactionPoolParams { pub struct ExecutionStrategies { /// The means of execution used when calling into the runtime while syncing blocks. #[structopt( - long = "syncing-execution", + long = "execution-syncing", value_name = "STRATEGY", raw( possible_values = "&ExecutionStrategy::variants()", @@ -235,11 +233,11 @@ pub struct ExecutionStrategies { default_value = r#""NativeElseWasm""# ) )] - pub syncing_execution: ExecutionStrategy, + pub execution_syncing: ExecutionStrategy, /// The means of execution used when calling into the runtime while importing blocks. #[structopt( - long = "importing-execution", + long = "execution-import-block", value_name = "STRATEGY", raw( possible_values = "&ExecutionStrategy::variants()", @@ -247,11 +245,11 @@ pub struct ExecutionStrategies { default_value = r#""NativeElseWasm""# ) )] - pub importing_execution: ExecutionStrategy, + pub execution_import_block: ExecutionStrategy, /// The means of execution used when calling into the runtime while constructing blocks. #[structopt( - long = "block-construction-execution", + long = "execution-block-construction", value_name = "STRATEGY", raw( possible_values = "&ExecutionStrategy::variants()", @@ -259,31 +257,49 @@ pub struct ExecutionStrategies { default_value = r#""Wasm""# ) )] - pub block_construction_execution: ExecutionStrategy, + pub execution_block_construction: ExecutionStrategy, /// The means of execution used when calling into the runtime while using an off-chain worker. #[structopt( - long = "offchain-worker-execution", + long = "execution-offchain-worker", value_name = "STRATEGY", raw( possible_values = "&ExecutionStrategy::variants()", case_insensitive = "true", - default_value = r#""NativeWhenPossible""# + default_value = r#""Native""# ) )] - pub offchain_worker_execution: ExecutionStrategy, + pub execution_offchain_worker: ExecutionStrategy, /// The means of execution used when calling into the runtime while not syncing, importing or constructing blocks. #[structopt( - long = "other-execution", + long = "execution-other", value_name = "STRATEGY", raw( possible_values = "&ExecutionStrategy::variants()", case_insensitive = "true", - default_value = r#""Wasm""# + default_value = r#""Native""# ) )] - pub other_execution: ExecutionStrategy, + pub execution_other: ExecutionStrategy, + + /// The execution strategy that should be used by all execution contexts. + #[structopt( + long = "execution", + value_name = "STRATEGY", + raw( + possible_values = "&ExecutionStrategy::variants()", + case_insensitive = "true", + conflicts_with_all = "&[ + \"execution_other\", + \"execution_offchain_worker\", + \"execution_block_construction\", + \"execution_import_block\", + \"execution_syncing\", + ]" + ) + )] + pub execution: Option, } /// The `run` command used to run a node. @@ -305,6 +321,11 @@ pub struct RunCmd { #[structopt(long = "no-grandpa")] pub no_grandpa: bool, + /// Run GRANDPA voter even when no additional key seed via `--key` is specified. This can for example be of interest + /// when running a sentry node in front of a validator, thus needing to forward GRANDPA gossip messages. + #[structopt(long = "grandpa-voter")] + pub grandpa_voter: bool, + /// Experimental: Run in light client mode #[structopt(long = "light")] pub light: bool, @@ -421,7 +442,7 @@ lazy_static::lazy_static! { let conflicts_with = keyring::AuthorityKeyring::iter() .filter(|b| a != *b) .map(|b| b.to_string().to_lowercase()) - .chain(["name", "key"].iter().map(|s| s.to_string())) + .chain(["name", "key"].iter().map(ToString::to_string)) .collect::>(); let name = a.to_string().to_lowercase(); diff --git a/core/client/Cargo.toml b/core/client/Cargo.toml index 510ec50b8b5c1bb527460cadfa0059d70b2e6cc7..29951b5c484929c43f52de6d7bd32ffb759a335f 100644 --- a/core/client/Cargo.toml +++ b/core/client/Cargo.toml @@ -10,16 +10,16 @@ fnv = { version = "1.0", optional = true } log = { version = "0.4", optional = true } parking_lot = { version = "0.8.0", optional = true } hex = { package = "hex-literal", version = "0.1", optional = true } -futures = { version = "0.1.17", optional = true } +futures-preview = { version = "0.3.0-alpha.17", optional = true } consensus = { package = "substrate-consensus-common", path = "../consensus/common", optional = true } executor = { package = "substrate-executor", path = "../executor", optional = true } state-machine = { package = "substrate-state-machine", path = "../state-machine", optional = true } keyring = { package = "substrate-keyring", path = "../keyring", optional = true } trie = { package = "substrate-trie", path = "../trie", optional = true } substrate-telemetry = { path = "../telemetry", optional = true } -hash-db = { version = "0.12.2", default-features = false } +hash-db = { version = "0.14.0", default-features = false } kvdb = { git = "https://github.com/paritytech/parity-common", optional = true, rev="b0317f649ab2c665b7987b8475878fc4d2e1f81d" } -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } primitives = { package = "substrate-primitives", path = "../primitives", default-features = false } runtime-primitives = { package = "sr-primitives", path = "../sr-primitives", default-features = false } runtime-version = { package = "sr-version", path = "../sr-version", default-features = false } @@ -47,7 +47,7 @@ std = [ "fnv", "log", "hex", - "futures", + "futures-preview", "executor", "state-machine", "keyring", diff --git a/core/client/db/Cargo.toml b/core/client/db/Cargo.toml index bfc7108db750f19b8e2dadbf0c25e8857e4c6f08..899c85998a55447f772a23e11c7453addc5971ba 100644 --- a/core/client/db/Cargo.toml +++ b/core/client/db/Cargo.toml @@ -12,12 +12,12 @@ kvdb = { git = "https://github.com/paritytech/parity-common", rev="b0317f649ab2c kvdb-rocksdb = { git = "https://github.com/paritytech/parity-common", rev="b0317f649ab2c665b7987b8475878fc4d2e1f81d", optional = true } kvdb-memorydb = { git = "https://github.com/paritytech/parity-common", rev="b0317f649ab2c665b7987b8475878fc4d2e1f81d" } linked-hash-map = "0.5" -hash-db = { version = "0.12" } +hash-db = { version = "0.14.0" } primitives = { package = "substrate-primitives", path = "../../primitives" } runtime_primitives = { package = "sr-primitives", path = "../../sr-primitives" } client = { package = "substrate-client", path = "../../client" } state-machine = { package = "substrate-state-machine", path = "../../state-machine" } -parity-codec = { version = "3.3", features = ["derive"] } +parity-codec = { version = "4.1.1", features = ["derive"] } executor = { package = "substrate-executor", path = "../../executor" } state_db = { package = "substrate-state-db", path = "../../state-db" } trie = { package = "substrate-trie", path = "../../trie" } diff --git a/core/client/db/src/cache/list_cache.rs b/core/client/db/src/cache/list_cache.rs index 4f343e93fdc93f5dbadf066879b4393be623f076..727375244d6cee12f2386683a2c13eefcc0132ad 100644 --- a/core/client/db/src/cache/list_cache.rs +++ b/core/client/db/src/cache/list_cache.rs @@ -163,13 +163,15 @@ impl> ListCache }; match head { - Some(head) => head.search_best_before(&self.storage, at.number, true) - .map(|e| e.and_then(|e| e.0.value)), + Some(head) => head.search_best_before(&self.storage, at.number) + .map(|e| e.map(|e| e.0.value)), None => Ok(None), } } /// When new block is inserted into database. + /// + /// None passed as value means that the value has not changed since previous block. pub fn on_block_insert>( &self, tx: &mut Tx, @@ -191,6 +193,11 @@ impl> ListCache if !is_final { let mut fork_and_action = None; + // when value hasn't changed and block isn't final, there's nothing we need to do + if value.is_none() { + return Ok(None); + } + // first: try to find fork that is known to has the best block we're appending to for (index, fork) in self.unfinalized.iter().enumerate() { if fork.try_append(&parent) { @@ -231,7 +238,7 @@ impl> ListCache // it is possible that we're inserting extra (but still required) fork here let new_storage_entry = StorageEntry { prev_valid_from: Some(prev_valid_from), - value, + value: value.expect("chcecked abpve that !value.is_none(); qed"), }; tx.insert_storage_entry(&block, &new_storage_entry); @@ -250,7 +257,10 @@ impl> ListCache let new_storage_entry = match self.best_finalized_entry.as_ref() { Some(best_finalized_entry) => best_finalized_entry.try_update(value), - None if value.is_some() => Some(StorageEntry { prev_valid_from: None, value }), + None if value.is_some() => Some(StorageEntry { + prev_valid_from: None, + value: value.expect("value.is_some(); qed"), + }), None => None, }; @@ -378,8 +388,12 @@ impl> ListCache }); // destroy 'fork' ending with previous entry - Fork { best_block: None, head: Entry { valid_from: first_entry_to_truncate, value: None } } - .destroy(&self.storage, tx, None) + destroy_fork( + first_entry_to_truncate, + &self.storage, + tx, + None, + ) }; if let Err(error) = do_pruning() { @@ -491,25 +505,40 @@ impl Fork { tx: &mut Tx, best_finalized_block: Option>, ) -> ClientResult<()> { - let mut current = self.head.valid_from.clone(); - loop { - // optionally: deletion stops when we found entry at finalized block - if let Some(best_finalized_block) = best_finalized_block { - if chain::is_finalized_block(storage, ¤t, best_finalized_block)? { - return Ok(()); - } + destroy_fork( + self.head.valid_from.clone(), + storage, + tx, + best_finalized_block, + ) + } +} + +/// Destroy fork by deleting all unfinalized entries. +pub fn destroy_fork, Tx: StorageTransaction>( + head_valid_from: ComplexBlockId, + storage: &S, + tx: &mut Tx, + best_finalized_block: Option>, +) -> ClientResult<()> { + let mut current = head_valid_from; + loop { + // optionally: deletion stops when we found entry at finalized block + if let Some(best_finalized_block) = best_finalized_block { + if chain::is_finalized_block(storage, ¤t, best_finalized_block)? { + return Ok(()); } + } - // read pointer to previous entry - let entry = storage.require_entry(¤t)?; - tx.remove_storage_entry(¤t); + // read pointer to previous entry + let entry = storage.require_entry(¤t)?; + tx.remove_storage_entry(¤t); - // deletion stops when there are no more entries in the list - current = match entry.prev_valid_from { - Some(prev_valid_from) => prev_valid_from, - None => return Ok(()), - }; - } + // deletion stops when there are no more entries in the list + current = match entry.prev_valid_from { + Some(prev_valid_from) => prev_valid_from, + None => return Ok(()), + }; } } @@ -639,24 +668,14 @@ pub mod tests { // ----------> [100] assert_eq!(ListCache::<_, u64, _>::new(DummyStorage::new(), 1024, test_id(100)) .value_at_block(&test_id(50)).unwrap(), None); - // when block is earlier than best finalized block AND it is finalized AND value is empty - // [30] ---- 50 ---> [100] - assert_eq!(ListCache::new( - DummyStorage::new() - .with_meta(Some(test_id(100)), Vec::new()) - .with_id(50, H256::from_low_u64_be(50)) - .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(30)), value: Some(100) }) - .with_entry(test_id(30), StorageEntry { prev_valid_from: None, value: None }), - 1024, test_id(100) - ).value_at_block(&test_id(50)).unwrap(), None); // when block is earlier than best finalized block AND it is finalized AND value is some // [30] ---- 50 ---> [100] assert_eq!(ListCache::new( DummyStorage::new() .with_meta(Some(test_id(100)), Vec::new()) .with_id(50, H256::from_low_u64_be(50)) - .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(30)), value: Some(100) }) - .with_entry(test_id(30), StorageEntry { prev_valid_from: None, value: Some(30) }), + .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(30)), value: 100 }) + .with_entry(test_id(30), StorageEntry { prev_valid_from: None, value: 30 }), 1024, test_id(100) ).value_at_block(&test_id(50)).unwrap(), Some(30)); // when block is the best finalized block AND value is some @@ -665,8 +684,8 @@ pub mod tests { DummyStorage::new() .with_meta(Some(test_id(100)), Vec::new()) .with_id(100, H256::from_low_u64_be(100)) - .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(30)), value: Some(100) }) - .with_entry(test_id(30), StorageEntry { prev_valid_from: None, value: Some(30) }), + .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(30)), value: 100 }) + .with_entry(test_id(30), StorageEntry { prev_valid_from: None, value: 30 }), 1024, test_id(100) ).value_at_block(&test_id(100)).unwrap(), Some(100)); // when block is parallel to the best finalized block @@ -676,45 +695,21 @@ pub mod tests { DummyStorage::new() .with_meta(Some(test_id(100)), Vec::new()) .with_id(50, H256::from_low_u64_be(50)) - .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(30)), value: Some(100) }) - .with_entry(test_id(30), StorageEntry { prev_valid_from: None, value: Some(30) }), + .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(30)), value: 100 }) + .with_entry(test_id(30), StorageEntry { prev_valid_from: None, value: 30 }), 1024, test_id(100) ).value_at_block(&ComplexBlockId::new(H256::from_low_u64_be(2), 100)).unwrap(), None); - // when block is later than last finalized block AND there are no forks AND finalized value is None - // ---> [100] --- 200 - assert_eq!(ListCache::<_, u64, _>::new( - DummyStorage::new() - .with_meta(Some(test_id(100)), Vec::new()) - .with_id(50, H256::from_low_u64_be(50)) - .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(30)), value: None }), - 1024, test_id(100) - ).value_at_block(&test_id(200)).unwrap(), None); // when block is later than last finalized block AND there are no forks AND finalized value is Some // ---> [100] --- 200 assert_eq!(ListCache::new( DummyStorage::new() .with_meta(Some(test_id(100)), Vec::new()) .with_id(50, H256::from_low_u64_be(50)) - .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(30)), value: Some(100) }), + .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(30)), value: 100 }), 1024, test_id(100) ).value_at_block(&test_id(200)).unwrap(), Some(100)); - // when block is later than last finalized block AND there are no matching forks - // AND block is connected to finalized block AND finalized value is None - // --- 3 - // ---> [2] /---------> [4] - assert_eq!(ListCache::new( - DummyStorage::new() - .with_meta(Some(correct_id(2)), vec![correct_id(4)]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: None }) - .with_entry(correct_id(4), StorageEntry { prev_valid_from: Some(correct_id(2)), value: Some(4) }) - .with_header(test_header(2)) - .with_header(test_header(3)) - .with_header(test_header(4)) - .with_header(fork_header(0, 2, 3)), - 1024, test_id(2) - ).value_at_block(&fork_id(0, 2, 3)).unwrap(), None); // when block is later than last finalized block AND there are no matching forks // AND block is connected to finalized block AND finalized value is Some // --- 3 @@ -722,8 +717,8 @@ pub mod tests { assert_eq!(ListCache::new( DummyStorage::new() .with_meta(Some(correct_id(2)), vec![correct_id(4)]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: Some(2) }) - .with_entry(correct_id(4), StorageEntry { prev_valid_from: Some(correct_id(2)), value: Some(4) }) + .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) + .with_entry(correct_id(4), StorageEntry { prev_valid_from: Some(correct_id(2)), value: 4 }) .with_header(test_header(2)) .with_header(test_header(3)) .with_header(test_header(4)) @@ -737,8 +732,8 @@ pub mod tests { assert_eq!(ListCache::new( DummyStorage::new() .with_meta(Some(correct_id(2)), vec![correct_id(4)]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: Some(2) }) - .with_entry(correct_id(4), StorageEntry { prev_valid_from: Some(correct_id(2)), value: Some(4) }) + .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) + .with_entry(correct_id(4), StorageEntry { prev_valid_from: Some(correct_id(2)), value: 4 }) .with_header(test_header(1)) .with_header(test_header(2)) .with_header(test_header(3)) @@ -754,52 +749,12 @@ pub mod tests { assert_eq!(ListCache::new( DummyStorage::new() .with_meta(Some(correct_id(2)), vec![correct_id(4)]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: Some(2) }) - .with_entry(correct_id(4), StorageEntry { prev_valid_from: Some(correct_id(2)), value: Some(4) }) + .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) + .with_entry(correct_id(4), StorageEntry { prev_valid_from: Some(correct_id(2)), value: 4 }) .with_header(test_header(4)) .with_header(test_header(5)), 1024, test_id(2) ).value_at_block(&correct_id(5)).unwrap(), Some(4)); - // when block is later than last finalized block AND it appends to unfinalized fork from the end - // AND unfinalized value is None - // ---> [2] ---> [4] ---> 5 - assert_eq!(ListCache::new( - DummyStorage::new() - .with_meta(Some(correct_id(2)), vec![correct_id(4)]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: Some(2) }) - .with_entry(correct_id(4), StorageEntry { prev_valid_from: Some(correct_id(2)), value: None }) - .with_header(test_header(4)) - .with_header(test_header(5)), - 1024, test_id(2) - ).value_at_block(&correct_id(5)).unwrap(), None); - // when block is later than last finalized block AND it fits to the middle of unfinalized fork - // AND unfinalized value is Some - // ---> [2] ---> [4] ---> 5 ---> [6] - assert_eq!(ListCache::new( - DummyStorage::new() - .with_meta(Some(correct_id(2)), vec![correct_id(6)]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: Some(2) }) - .with_entry(correct_id(4), StorageEntry { prev_valid_from: Some(correct_id(2)), value: Some(4) }) - .with_entry(correct_id(6), StorageEntry { prev_valid_from: Some(correct_id(4)), value: None }) - .with_header(test_header(4)) - .with_header(test_header(5)) - .with_header(test_header(6)), - 1024, test_id(2) - ).value_at_block(&correct_id(5)).unwrap(), Some(4)); - // when block is later than last finalized block AND it fits to the middle of unfinalized fork - // AND unfinalized value is None - // ---> [2] ---> [4] ---> 5 ---> [6] - assert_eq!(ListCache::new( - DummyStorage::new() - .with_meta(Some(correct_id(2)), vec![correct_id(6)]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: Some(2) }) - .with_entry(correct_id(4), StorageEntry { prev_valid_from: Some(correct_id(2)), value: None }) - .with_entry(correct_id(6), StorageEntry { prev_valid_from: Some(correct_id(4)), value: Some(4) }) - .with_header(test_header(4)) - .with_header(test_header(5)) - .with_header(test_header(6)), - 1024, test_id(2) - ).value_at_block(&correct_id(5)).unwrap(), None); // when block is later than last finalized block AND it does not fits unfinalized fork // AND it is connected to the finalized block AND finalized value is Some // ---> [2] ----------> [4] @@ -807,29 +762,14 @@ pub mod tests { assert_eq!(ListCache::new( DummyStorage::new() .with_meta(Some(correct_id(2)), vec![correct_id(4)]) - .with_entry(correct_id(4), StorageEntry { prev_valid_from: Some(correct_id(2)), value: Some(4) }) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: Some(2) }) + .with_entry(correct_id(4), StorageEntry { prev_valid_from: Some(correct_id(2)), value: 4 }) + .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) .with_header(test_header(2)) .with_header(test_header(3)) .with_header(test_header(4)) .with_header(fork_header(0, 2, 3)), 1024, test_id(2) ).value_at_block(&fork_id(0, 2, 3)).unwrap(), Some(2)); - // when block is later than last finalized block AND it does not fits unfinalized fork - // AND it is connected to the finalized block AND finalized value is Some - // ---> [2] ----------> [4] - // \--- 3 - assert_eq!(ListCache::new( - DummyStorage::new() - .with_meta(Some(correct_id(2)), vec![correct_id(4)]) - .with_entry(correct_id(4), StorageEntry { prev_valid_from: Some(correct_id(2)), value: Some(4) }) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: None }) - .with_header(test_header(2)) - .with_header(test_header(3)) - .with_header(test_header(4)) - .with_header(fork_header(0, 2, 3)), - 1024, test_id(2) - ).value_at_block(&fork_id(0, 2, 3)).unwrap(), None); } #[test] @@ -861,7 +801,7 @@ pub mod tests { let mut cache = ListCache::new( DummyStorage::new() .with_meta(None, vec![test_id(4)]) - .with_entry(test_id(4), StorageEntry { prev_valid_from: None, value: Some(4) }), + .with_entry(test_id(4), StorageEntry { prev_valid_from: None, value: 4 }), 1024, test_id(2) ); cache.unfinalized[0].best_block = Some(test_id(4)); @@ -875,7 +815,7 @@ pub mod tests { // AND new value is the same as in the fork' best block let mut tx = DummyTransaction::new(); assert_eq!(cache.on_block_insert(&mut tx, test_id(4), test_id(5), Some(5), nfin).unwrap(), - Some(CommitOperation::AppendNewEntry(0, Entry { valid_from: test_id(5), value: Some(5) }))); + Some(CommitOperation::AppendNewEntry(0, Entry { valid_from: test_id(5), value: 5 }))); assert_eq!(*tx.inserted_entries(), vec![test_id(5).hash].into_iter().collect()); assert!(tx.removed_entries().is_empty()); assert_eq!(*tx.updated_meta(), Some(Metadata { finalized: None, unfinalized: vec![test_id(5)] })); @@ -885,7 +825,7 @@ pub mod tests { let cache = ListCache::new( DummyStorage::new() .with_meta(None, vec![correct_id(4)]) - .with_entry(correct_id(4), StorageEntry { prev_valid_from: None, value: Some(4) }) + .with_entry(correct_id(4), StorageEntry { prev_valid_from: None, value: 4 }) .with_header(test_header(4)), 1024, test_id(2) ); @@ -899,7 +839,7 @@ pub mod tests { // AND new value is the same as in the fork' best block let mut tx = DummyTransaction::new(); assert_eq!(cache.on_block_insert(&mut tx, correct_id(4), correct_id(5), Some(5), nfin).unwrap(), - Some(CommitOperation::AppendNewEntry(0, Entry { valid_from: correct_id(5), value: Some(5) }))); + Some(CommitOperation::AppendNewEntry(0, Entry { valid_from: correct_id(5), value: 5 }))); assert_eq!(*tx.inserted_entries(), vec![correct_id(5).hash].into_iter().collect()); assert!(tx.removed_entries().is_empty()); assert_eq!(*tx.updated_meta(), Some(Metadata { finalized: None, unfinalized: vec![correct_id(5)] })); @@ -908,8 +848,8 @@ pub mod tests { let cache = ListCache::new( DummyStorage::new() .with_meta(Some(correct_id(2)), vec![correct_id(4)]) - .with_entry(correct_id(4), StorageEntry { prev_valid_from: Some(correct_id(2)), value: Some(4) }) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: Some(2) }) + .with_entry(correct_id(4), StorageEntry { prev_valid_from: Some(correct_id(2)), value: 4 }) + .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) .with_header(test_header(2)) .with_header(test_header(3)) .with_header(test_header(4)), @@ -917,7 +857,7 @@ pub mod tests { ); let mut tx = DummyTransaction::new(); assert_eq!(cache.on_block_insert(&mut tx, correct_id(3), fork_id(0, 3, 4), Some(14), nfin).unwrap(), - Some(CommitOperation::AddNewFork(Entry { valid_from: fork_id(0, 3, 4), value: Some(14) }))); + Some(CommitOperation::AddNewFork(Entry { valid_from: fork_id(0, 3, 4), value: 14 }))); assert_eq!(*tx.inserted_entries(), vec![fork_id(0, 3, 4).hash].into_iter().collect()); assert!(tx.removed_entries().is_empty()); assert_eq!(*tx.updated_meta(), Some(Metadata { finalized: Some(correct_id(2)), unfinalized: vec![correct_id(4), fork_id(0, 3, 4)] })); @@ -927,7 +867,7 @@ pub mod tests { let cache = ListCache::new( DummyStorage::new() .with_meta(Some(correct_id(2)), vec![]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: Some(2) }), + .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }), 1024, correct_id(2) ); let mut tx = DummyTransaction::new(); @@ -940,12 +880,12 @@ pub mod tests { let cache = ListCache::new( DummyStorage::new() .with_meta(Some(correct_id(2)), vec![]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: Some(2) }), + .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }), 1024, correct_id(2) ); let mut tx = DummyTransaction::new(); assert_eq!(cache.on_block_insert(&mut tx, correct_id(2), correct_id(3), Some(3), nfin).unwrap(), - Some(CommitOperation::AddNewFork(Entry { valid_from: correct_id(3), value: Some(3) }))); + Some(CommitOperation::AddNewFork(Entry { valid_from: correct_id(3), value: 3 }))); assert_eq!(*tx.inserted_entries(), vec![correct_id(3).hash].into_iter().collect()); assert!(tx.removed_entries().is_empty()); assert_eq!(*tx.updated_meta(), Some(Metadata { finalized: Some(correct_id(2)), unfinalized: vec![correct_id(3)] })); @@ -953,8 +893,14 @@ pub mod tests { // when inserting finalized entry AND there are no previous finalized entries let cache = ListCache::new(DummyStorage::new(), 1024, correct_id(2)); let mut tx = DummyTransaction::new(); - assert_eq!(cache.on_block_insert(&mut tx, correct_id(2), correct_id(3), Some(3), fin).unwrap(), - Some(CommitOperation::BlockFinalized(correct_id(3), Some(Entry { valid_from: correct_id(3), value: Some(3) }), Default::default()))); + assert_eq!( + cache.on_block_insert(&mut tx, correct_id(2), correct_id(3), Some(3), fin).unwrap(), + Some(CommitOperation::BlockFinalized( + correct_id(3), + Some(Entry { valid_from: correct_id(3), value: 3 }), + Default::default(), + )), + ); assert_eq!(*tx.inserted_entries(), vec![correct_id(3).hash].into_iter().collect()); assert!(tx.removed_entries().is_empty()); assert_eq!(*tx.updated_meta(), Some(Metadata { finalized: Some(correct_id(3)), unfinalized: vec![] })); @@ -962,7 +908,7 @@ pub mod tests { let cache = ListCache::new( DummyStorage::new() .with_meta(Some(correct_id(2)), vec![]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: Some(2) }), + .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }), 1024, correct_id(2) ); let mut tx = DummyTransaction::new(); @@ -973,8 +919,14 @@ pub mod tests { assert!(tx.updated_meta().is_none()); // when inserting finalized entry AND value differs from previous finalized let mut tx = DummyTransaction::new(); - assert_eq!(cache.on_block_insert(&mut tx, correct_id(2), correct_id(3), Some(3), fin).unwrap(), - Some(CommitOperation::BlockFinalized(correct_id(3), Some(Entry { valid_from: correct_id(3), value: Some(3) }), Default::default()))); + assert_eq!( + cache.on_block_insert(&mut tx, correct_id(2), correct_id(3), Some(3), fin).unwrap(), + Some(CommitOperation::BlockFinalized( + correct_id(3), + Some(Entry { valid_from: correct_id(3), value: 3 }), + Default::default(), + )), + ); assert_eq!(*tx.inserted_entries(), vec![correct_id(3).hash].into_iter().collect()); assert!(tx.removed_entries().is_empty()); assert_eq!(*tx.updated_meta(), Some(Metadata { finalized: Some(correct_id(3)), unfinalized: vec![] })); @@ -983,8 +935,8 @@ pub mod tests { let cache = ListCache::new( DummyStorage::new() .with_meta(Some(correct_id(2)), vec![fork_id(0, 1, 3)]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: Some(2) }) - .with_entry(fork_id(0, 1, 3), StorageEntry { prev_valid_from: None, value: Some(13) }), + .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) + .with_entry(fork_id(0, 1, 3), StorageEntry { prev_valid_from: None, value: 13 }), 1024, correct_id(2) ); let mut tx = DummyTransaction::new(); @@ -998,8 +950,8 @@ pub mod tests { let cache = ListCache::new( DummyStorage::new() .with_meta(Some(correct_id(2)), vec![correct_id(5)]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: Some(2) }) - .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(2)), value: Some(5) }), + .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) + .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(2)), value: 5 }), 1024, correct_id(2) ); let mut tx = DummyTransaction::new(); @@ -1012,13 +964,19 @@ pub mod tests { let cache = ListCache::new( DummyStorage::new() .with_meta(Some(correct_id(2)), vec![correct_id(5)]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: Some(2) }) - .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(2)), value: Some(5) }), + .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) + .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(2)), value: 5 }), 1024, correct_id(4) ); let mut tx = DummyTransaction::new(); - assert_eq!(cache.on_block_finalize(&mut tx, correct_id(4), correct_id(5)).unwrap(), - Some(CommitOperation::BlockFinalized(correct_id(5), Some(Entry { valid_from: correct_id(5), value: Some(5) }), vec![0].into_iter().collect()))); + assert_eq!( + cache.on_block_finalize(&mut tx, correct_id(4), correct_id(5)).unwrap(), + Some(CommitOperation::BlockFinalized( + correct_id(5), + Some(Entry { valid_from: correct_id(5), value: 5 }), + vec![0].into_iter().collect(), + )), + ); assert!(tx.inserted_entries().is_empty()); assert!(tx.removed_entries().is_empty()); assert_eq!(*tx.updated_meta(), Some(Metadata { finalized: Some(correct_id(5)), unfinalized: vec![] })); @@ -1026,8 +984,8 @@ pub mod tests { let cache = ListCache::new( DummyStorage::new() .with_meta(Some(correct_id(2)), vec![fork_id(0, 1, 3)]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: Some(2) }) - .with_entry(fork_id(0, 1, 3), StorageEntry { prev_valid_from: None, value: Some(13) }), + .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) + .with_entry(fork_id(0, 1, 3), StorageEntry { prev_valid_from: None, value: 13 }), 1024, correct_id(2) ); let mut tx = DummyTransaction::new(); @@ -1040,9 +998,9 @@ pub mod tests { let mut cache = ListCache::new( DummyStorage::new() .with_meta(Some(correct_id(2)), vec![correct_id(5), correct_id(6)]) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: Some(2) }) - .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(2)), value: Some(5) }) - .with_entry(correct_id(6), StorageEntry { prev_valid_from: Some(correct_id(5)), value: Some(6) }), + .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) + .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(2)), value: 5 }) + .with_entry(correct_id(6), StorageEntry { prev_valid_from: Some(correct_id(5)), value: 6 }), 1024, correct_id(2) ); @@ -1050,17 +1008,21 @@ pub mod tests { cache.on_transaction_commit(CommitOperation::AppendNewBlock(0, correct_id(6))); assert_eq!(cache.unfinalized[0].best_block, Some(correct_id(6))); // when new entry is appended to unfinalized fork - cache.on_transaction_commit(CommitOperation::AppendNewEntry(0, Entry { valid_from: correct_id(7), value: Some(7) })); + cache.on_transaction_commit(CommitOperation::AppendNewEntry(0, Entry { valid_from: correct_id(7), value: 7 })); assert_eq!(cache.unfinalized[0].best_block, Some(correct_id(7))); - assert_eq!(cache.unfinalized[0].head, Entry { valid_from: correct_id(7), value: Some(7) }); + assert_eq!(cache.unfinalized[0].head, Entry { valid_from: correct_id(7), value: 7 }); // when new fork is added - cache.on_transaction_commit(CommitOperation::AddNewFork(Entry { valid_from: correct_id(10), value: Some(10) })); + cache.on_transaction_commit(CommitOperation::AddNewFork(Entry { valid_from: correct_id(10), value: 10 })); assert_eq!(cache.unfinalized[2].best_block, Some(correct_id(10))); - assert_eq!(cache.unfinalized[2].head, Entry { valid_from: correct_id(10), value: Some(10) }); + assert_eq!(cache.unfinalized[2].head, Entry { valid_from: correct_id(10), value: 10 }); // when block is finalized + entry is finalized + unfinalized forks are deleted - cache.on_transaction_commit(CommitOperation::BlockFinalized(correct_id(20), Some(Entry { valid_from: correct_id(20), value: Some(20) }), vec![0, 1, 2].into_iter().collect())); + cache.on_transaction_commit(CommitOperation::BlockFinalized( + correct_id(20), + Some(Entry { valid_from: correct_id(20), value: 20 }), + vec![0, 1, 2].into_iter().collect(), + )); assert_eq!(cache.best_finalized_block, correct_id(20)); - assert_eq!(cache.best_finalized_entry, Some(Entry { valid_from: correct_id(20), value: Some(20) })); + assert_eq!(cache.best_finalized_entry, Some(Entry { valid_from: correct_id(20), value: 20 })); assert!(cache.unfinalized.is_empty()); } @@ -1071,9 +1033,9 @@ pub mod tests { assert_eq!(ListCache::new( DummyStorage::new() .with_meta(None, vec![fork_id(0, 1, 3), correct_id(5)]) - .with_entry(fork_id(0, 1, 3), StorageEntry { prev_valid_from: Some(correct_id(1)), value: Some(13) }) - .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(2)), value: Some(5) }) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: None }) + .with_entry(fork_id(0, 1, 3), StorageEntry { prev_valid_from: Some(correct_id(1)), value: 13 }) + .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(2)), value: 5 }) + .with_entry(correct_id(2), StorageEntry { prev_valid_from: None, value: 2 }) .with_header(test_header(2)) .with_header(test_header(3)) .with_header(test_header(4)) @@ -1085,9 +1047,9 @@ pub mod tests { assert_eq!(ListCache::new( DummyStorage::new() .with_meta(None, vec![correct_id(5), fork_id(0, 1, 3)]) - .with_entry(fork_id(0, 1, 3), StorageEntry { prev_valid_from: Some(correct_id(1)), value: Some(13) }) - .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(2)), value: Some(5) }) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: Some(correct_id(1)), value: Some(2) }) + .with_entry(fork_id(0, 1, 3), StorageEntry { prev_valid_from: Some(correct_id(1)), value: 13 }) + .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(2)), value: 5 }) + .with_entry(correct_id(2), StorageEntry { prev_valid_from: Some(correct_id(1)), value: 2 }) .with_header(test_header(2)) .with_header(test_header(3)) .with_header(test_header(4)) @@ -1103,9 +1065,9 @@ pub mod tests { assert!(ListCache::new( DummyStorage::new() .with_meta(None, vec![correct_id(5), fork_id(0, 1, 3)]) - .with_entry(fork_id(0, 1, 3), StorageEntry { prev_valid_from: Some(correct_id(1)), value: Some(13) }) - .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(2)), value: Some(5) }) - .with_entry(correct_id(2), StorageEntry { prev_valid_from: Some(correct_id(1)), value: Some(2) }) + .with_entry(fork_id(0, 1, 3), StorageEntry { prev_valid_from: Some(correct_id(1)), value: 13 }) + .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(2)), value: 5 }) + .with_entry(correct_id(2), StorageEntry { prev_valid_from: Some(correct_id(1)), value: 2 }) .with_header(test_header(2)) .with_header(test_header(3)) .with_header(test_header(4)) @@ -1123,59 +1085,59 @@ pub mod tests { fn fork_matches_works() { // when block is not within list range let storage = DummyStorage::new() - .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(50)), value: Some(100) }) - .with_entry(test_id(50), StorageEntry { prev_valid_from: None, value: Some(50) }); - assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: None } } + .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(50)), value: 100 }) + .with_entry(test_id(50), StorageEntry { prev_valid_from: None, value: 50 }); + assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: 0 } } .matches(&storage, &test_id(20)).unwrap(), false); // when block is not connected to the begin block let storage = DummyStorage::new() - .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(3)), value: Some(100) }) - .with_entry(correct_id(3), StorageEntry { prev_valid_from: None, value: Some(200) }) + .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(3)), value: 100 }) + .with_entry(correct_id(3), StorageEntry { prev_valid_from: None, value: 200 }) .with_header(test_header(5)) .with_header(test_header(4)) .with_header(test_header(3)) .with_header(fork_header(0, 2, 4)) .with_header(fork_header(0, 2, 3)); - assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: correct_id(5), value: Some(100) } } + assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: correct_id(5), value: 100 } } .matches(&storage, &fork_id(0, 2, 4)).unwrap(), false); // when block is not connected to the end block let storage = DummyStorage::new() - .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(3)), value: Some(100) }) - .with_entry(correct_id(3), StorageEntry { prev_valid_from: None, value: Some(200) }) + .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(3)), value: 100 }) + .with_entry(correct_id(3), StorageEntry { prev_valid_from: None, value: 200 }) .with_header(test_header(5)) .with_header(test_header(4)) .with_header(test_header(3)) .with_header(fork_header(0, 3, 4)); - assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: correct_id(5), value: Some(100) } } + assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: correct_id(5), value: 100 } } .matches(&storage, &fork_id(0, 3, 4)).unwrap(), false); // when block is connected to the begin block AND end is open let storage = DummyStorage::new() - .with_entry(correct_id(5), StorageEntry { prev_valid_from: None, value: Some(100) }) + .with_entry(correct_id(5), StorageEntry { prev_valid_from: None, value: 100 }) .with_header(test_header(5)) .with_header(test_header(6)); - assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: correct_id(5), value: Some(100) } } + assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: correct_id(5), value: 100 } } .matches(&storage, &correct_id(6)).unwrap(), true); // when block is connected to the begin block AND to the end block let storage = DummyStorage::new() - .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(3)), value: Some(100) }) - .with_entry(correct_id(3), StorageEntry { prev_valid_from: None, value: Some(200) }) + .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(3)), value: 100 }) + .with_entry(correct_id(3), StorageEntry { prev_valid_from: None, value: 200 }) .with_header(test_header(5)) .with_header(test_header(4)) .with_header(test_header(3)); - assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: correct_id(5), value: Some(100) } } + assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: correct_id(5), value: 100 } } .matches(&storage, &correct_id(4)).unwrap(), true); } #[test] fn fork_try_append_works() { // when best block is unknown - assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: None } } + assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: 0 } } .try_append(&test_id(100)), false); // when best block is known but different - assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: None } } + assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: 0 } } .try_append(&test_id(101)), false); // when best block is known and the same - assert_eq!(Fork::<_, u64> { best_block: Some(test_id(100)), head: Entry { valid_from: test_id(100), value: None } } + assert_eq!(Fork::<_, u64> { best_block: Some(test_id(100)), head: Entry { valid_from: test_id(100), value: 0 } } .try_append(&test_id(100)), true); } @@ -1183,49 +1145,52 @@ pub mod tests { fn fork_try_append_or_fork_works() { // when there's no entry before parent let storage = DummyStorage::new() - .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(50)), value: Some(100) }) - .with_entry(test_id(50), StorageEntry { prev_valid_from: None, value: Some(50) }); - assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: None } } + .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(50)), value: 100 }) + .with_entry(test_id(50), StorageEntry { prev_valid_from: None, value: 50 }); + assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: 0 } } .try_append_or_fork(&storage, &test_id(30), None).unwrap(), None); // when parent does not belong to the fork let storage = DummyStorage::new() - .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(3)), value: Some(100) }) - .with_entry(correct_id(3), StorageEntry { prev_valid_from: None, value: Some(200) }) + .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(3)), value: 100 }) + .with_entry(correct_id(3), StorageEntry { prev_valid_from: None, value: 200 }) .with_header(test_header(5)) .with_header(test_header(4)) .with_header(test_header(3)) .with_header(fork_header(0, 2, 4)) .with_header(fork_header(0, 2, 3)); - assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: correct_id(5), value: Some(100) } } + assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: correct_id(5), value: 100 } } .try_append_or_fork(&storage, &fork_id(0, 2, 4), None).unwrap(), None); // when the entry before parent is the head entry let storage = DummyStorage::new() - .with_entry(ComplexBlockId::new(test_header(5).hash(), 5), StorageEntry { prev_valid_from: Some(correct_id(3)), value: Some(100) }) + .with_entry( + ComplexBlockId::new(test_header(5).hash(), 5), + StorageEntry { prev_valid_from: Some(correct_id(3)), value: 100 }, + ) .with_header(test_header(6)) .with_header(test_header(5)); - assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: correct_id(5), value: Some(100) } } + assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: correct_id(5), value: 100 } } .try_append_or_fork(&storage, &correct_id(6), None).unwrap(), Some(ForkAppendResult::Append)); // when the parent located after last finalized entry let storage = DummyStorage::new() - .with_entry(correct_id(6), StorageEntry { prev_valid_from: Some(correct_id(3)), value: Some(100) }) - .with_entry(correct_id(3), StorageEntry { prev_valid_from: None, value: Some(200) }) + .with_entry(correct_id(6), StorageEntry { prev_valid_from: Some(correct_id(3)), value: 100 }) + .with_entry(correct_id(3), StorageEntry { prev_valid_from: None, value: 200 }) .with_header(test_header(6)) .with_header(test_header(5)) .with_header(test_header(4)) .with_header(test_header(3)) .with_header(fork_header(0, 4, 5)); - assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: correct_id(6), value: Some(100) } } + assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: correct_id(6), value: 100 } } .try_append_or_fork(&storage, &fork_id(0, 4, 5), None).unwrap(), Some(ForkAppendResult::Fork(ComplexBlockId::new(test_header(3).hash(), 3)))); // when the parent located before last finalized entry let storage = DummyStorage::new() - .with_entry(correct_id(6), StorageEntry { prev_valid_from: Some(correct_id(3)), value: Some(100) }) - .with_entry(correct_id(3), StorageEntry { prev_valid_from: None, value: Some(200) }) + .with_entry(correct_id(6), StorageEntry { prev_valid_from: Some(correct_id(3)), value: 100 }) + .with_entry(correct_id(3), StorageEntry { prev_valid_from: None, value: 200 }) .with_header(test_header(6)) .with_header(test_header(5)) .with_header(test_header(4)) .with_header(test_header(3)) .with_header(fork_header(0, 4, 5)); - assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: correct_id(6), value: Some(100) } } + assert_eq!(Fork::<_, u64> { best_block: None, head: Entry { valid_from: correct_id(6), value: 100 } } .try_append_or_fork(&storage, &fork_id(0, 4, 5), Some(3)).unwrap(), None); } @@ -1234,30 +1199,30 @@ pub mod tests { // when we reached finalized entry without iterations let storage = DummyStorage::new().with_id(100, H256::from_low_u64_be(100)); let mut tx = DummyTransaction::new(); - Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: None } } + Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: 0 } } .destroy(&storage, &mut tx, Some(200)).unwrap(); assert!(tx.removed_entries().is_empty()); // when we reach finalized entry with iterations let storage = DummyStorage::new() .with_id(10, H256::from_low_u64_be(10)) - .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(50)), value: Some(100) }) - .with_entry(test_id(50), StorageEntry { prev_valid_from: Some(test_id(20)), value: Some(50) }) - .with_entry(test_id(20), StorageEntry { prev_valid_from: Some(test_id(10)), value: Some(20) }) - .with_entry(test_id(10), StorageEntry { prev_valid_from: Some(test_id(5)), value: Some(10) }) - .with_entry(test_id(5), StorageEntry { prev_valid_from: Some(test_id(3)), value: Some(5) }) - .with_entry(test_id(3), StorageEntry { prev_valid_from: None, value: None }); + .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(50)), value: 100 }) + .with_entry(test_id(50), StorageEntry { prev_valid_from: Some(test_id(20)), value: 50 }) + .with_entry(test_id(20), StorageEntry { prev_valid_from: Some(test_id(10)), value: 20 }) + .with_entry(test_id(10), StorageEntry { prev_valid_from: Some(test_id(5)), value: 10 }) + .with_entry(test_id(5), StorageEntry { prev_valid_from: Some(test_id(3)), value: 5 }) + .with_entry(test_id(3), StorageEntry { prev_valid_from: None, value: 0 }); let mut tx = DummyTransaction::new(); - Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: None } } + Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: 0 } } .destroy(&storage, &mut tx, Some(200)).unwrap(); assert_eq!(*tx.removed_entries(), vec![test_id(100).hash, test_id(50).hash, test_id(20).hash].into_iter().collect()); // when we reach beginning of fork before finalized block let storage = DummyStorage::new() .with_id(10, H256::from_low_u64_be(10)) - .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(50)), value: Some(100) }) - .with_entry(test_id(50), StorageEntry { prev_valid_from: None, value: Some(50) }); + .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(50)), value: 100 }) + .with_entry(test_id(50), StorageEntry { prev_valid_from: None, value: 50 }); let mut tx = DummyTransaction::new(); - Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: None } } + Fork::<_, u64> { best_block: None, head: Entry { valid_from: test_id(100), value: 0 } } .destroy(&storage, &mut tx, Some(200)).unwrap(); assert_eq!(*tx.removed_entries(), vec![test_id(100).hash, test_id(50).hash].into_iter().collect()); @@ -1355,14 +1320,14 @@ pub mod tests { #[test] fn read_forks_works() { let storage = DummyStorage::new() - .with_entry(test_id(10), StorageEntry { prev_valid_from: Some(test_id(1)), value: Some(11) }) - .with_entry(test_id(20), StorageEntry { prev_valid_from: Some(test_id(2)), value: None }) - .with_entry(test_id(30), StorageEntry { prev_valid_from: None, value: Some(33) }); + .with_entry(test_id(10), StorageEntry { prev_valid_from: Some(test_id(1)), value: 11 }) + .with_entry(test_id(20), StorageEntry { prev_valid_from: Some(test_id(2)), value: 0 }) + .with_entry(test_id(30), StorageEntry { prev_valid_from: None, value: 33 }); let expected = ( - Some(Entry { valid_from: test_id(10), value: Some(11) }), + Some(Entry { valid_from: test_id(10), value: 11 }), vec![ - Fork { best_block: None, head: Entry { valid_from: test_id(20), value: None } }, - Fork { best_block: None, head: Entry { valid_from: test_id(30), value: Some(33) } }, + Fork { best_block: None, head: Entry { valid_from: test_id(20), value: 0 } }, + Fork { best_block: None, head: Entry { valid_from: test_id(30), value: 33 } }, ], ); @@ -1378,9 +1343,9 @@ pub mod tests { .with_id(10, H256::from_low_u64_be(10)) .with_id(20, H256::from_low_u64_be(20)) .with_id(30, H256::from_low_u64_be(30)) - .with_entry(test_id(10), StorageEntry { prev_valid_from: None, value: Some(10) }) - .with_entry(test_id(20), StorageEntry { prev_valid_from: Some(test_id(10)), value: Some(20) }) - .with_entry(test_id(30), StorageEntry { prev_valid_from: Some(test_id(20)), value: Some(30) }), + .with_entry(test_id(10), StorageEntry { prev_valid_from: None, value: 10 }) + .with_entry(test_id(20), StorageEntry { prev_valid_from: Some(test_id(10)), value: 20 }) + .with_entry(test_id(30), StorageEntry { prev_valid_from: Some(test_id(20)), value: 30 }), 10, test_id(9)); let mut tx = DummyTransaction::new(); diff --git a/core/client/db/src/cache/list_entry.rs b/core/client/db/src/cache/list_entry.rs index 237ae9a268026744b87f6d85b7c6301cb82ee204..3305b909d2b2ce088ffd1cf8c10c7f0e987f2469 100644 --- a/core/client/db/src/cache/list_entry.rs +++ b/core/client/db/src/cache/list_entry.rs @@ -27,10 +27,10 @@ use crate::cache::list_storage::{Storage}; #[derive(Debug)] #[cfg_attr(test, derive(PartialEq))] pub struct Entry { - /// first block, when this value became actual + /// first block, when this value became actual. pub valid_from: ComplexBlockId, - /// None means that we do not know the value starting from `valid_from` block - pub value: Option, + /// Value stored at this entry. + pub value: T, } /// Internal representation of the single list-based cache entry. The entry points to the @@ -38,21 +38,24 @@ pub struct Entry { #[derive(Debug, Encode, Decode)] #[cfg_attr(test, derive(Clone, PartialEq))] pub struct StorageEntry { - /// None if valid from the beginning + /// None if valid from the beginning. pub prev_valid_from: Option>, - /// None means that we do not know the value starting from `valid_from` block - pub value: Option, + /// Value stored at this entry. + pub value: T, } impl Entry { /// Returns Some if the entry should be updated with the new value. pub fn try_update(&self, value: Option) -> Option> { - match self.value == value { - true => None, - false => Some(StorageEntry { - prev_valid_from: Some(self.valid_from.clone()), - value, - }), + match value { + Some(value) => match self.value == value { + true => None, + false => Some(StorageEntry { + prev_valid_from: Some(self.valid_from.clone()), + value, + }), + }, + None => None, } } @@ -62,7 +65,7 @@ impl Entry { storage: &S, block: NumberFor, ) -> ClientResult, Option>)>> { - Ok(self.search_best_before(storage, block, false)? + Ok(self.search_best_before(storage, block)? .map(|(entry, next)| (entry.valid_from, next))) } @@ -75,13 +78,12 @@ impl Entry { &self, storage: &S, block: NumberFor, - require_value: bool, ) -> ClientResult, Option>)>> { // we're looking for the best value let mut next = None; let mut current = self.valid_from.clone(); if block >= self.valid_from.number { - let value = if require_value { self.value.clone() } else { None }; + let value = self.value.clone(); return Ok(Some((Entry { valid_from: current, value }, next))); } @@ -119,47 +121,41 @@ mod tests { #[test] fn entry_try_update_works() { - // when trying to update with the same None value - assert_eq!(Entry::<_, u64> { valid_from: test_id(1), value: None }.try_update(None), None); + // when trying to update with None value + assert_eq!(Entry::<_, u64> { valid_from: test_id(1), value: 42 }.try_update(None), None); // when trying to update with the same Some value - assert_eq!(Entry { valid_from: test_id(1), value: Some(1) }.try_update(Some(1)), None); - // when trying to update with different None value - assert_eq!(Entry { valid_from: test_id(1), value: Some(1) }.try_update(None), - Some(StorageEntry { prev_valid_from: Some(test_id(1)), value: None })); + assert_eq!(Entry { valid_from: test_id(1), value: 1 }.try_update(Some(1)), None); // when trying to update with different Some value - assert_eq!(Entry { valid_from: test_id(1), value: Some(1) }.try_update(Some(2)), - Some(StorageEntry { prev_valid_from: Some(test_id(1)), value: Some(2) })); + assert_eq!(Entry { valid_from: test_id(1), value: 1 }.try_update(Some(2)), + Some(StorageEntry { prev_valid_from: Some(test_id(1)), value: 2 })); } #[test] fn entry_search_best_before_fails() { // when storage returns error - assert!(Entry::<_, u64> { valid_from: test_id(100), value: None }.search_best_before(&FaultyStorage, 50, false).is_err()); + assert!(Entry::<_, u64> { valid_from: test_id(100), value: 42 } + .search_best_before(&FaultyStorage, 50).is_err()); } #[test] fn entry_search_best_before_works() { - // when block is better than our best block AND value is not required - assert_eq!(Entry::<_, u64> { valid_from: test_id(100), value: Some(100) } - .search_best_before(&DummyStorage::new(), 150, false).unwrap(), - Some((Entry::<_, u64> { valid_from: test_id(100), value: None }, None))); - // when block is better than our best block AND value is required - assert_eq!(Entry::<_, u64> { valid_from: test_id(100), value: Some(100) } - .search_best_before(&DummyStorage::new(), 150, true).unwrap(), - Some((Entry::<_, u64> { valid_from: test_id(100), value: Some(100) }, None))); + // when block is better than our best block + assert_eq!(Entry::<_, u64> { valid_from: test_id(100), value: 100 } + .search_best_before(&DummyStorage::new(), 150).unwrap(), + Some((Entry::<_, u64> { valid_from: test_id(100), value: 100 }, None))); // when block is found between two entries - assert_eq!(Entry::<_, u64> { valid_from: test_id(100), value: Some(100) } + assert_eq!(Entry::<_, u64> { valid_from: test_id(100), value: 100 } .search_best_before(&DummyStorage::new() - .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(50)), value: Some(100) }) - .with_entry(test_id(50), StorageEntry { prev_valid_from: Some(test_id(30)), value: Some(50) }), - 75, false).unwrap(), - Some((Entry::<_, u64> { valid_from: test_id(50), value: Some(50) }, Some(test_id(100))))); + .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(50)), value: 100 }) + .with_entry(test_id(50), StorageEntry { prev_valid_from: Some(test_id(30)), value: 50 }), + 75).unwrap(), + Some((Entry::<_, u64> { valid_from: test_id(50), value: 50 }, Some(test_id(100))))); // when block is not found - assert_eq!(Entry::<_, u64> { valid_from: test_id(100), value: Some(100) } + assert_eq!(Entry::<_, u64> { valid_from: test_id(100), value: 100 } .search_best_before(&DummyStorage::new() - .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(50)), value: Some(100) }) - .with_entry(test_id(50), StorageEntry { prev_valid_from: None, value: Some(50) }), - 30, true).unwrap(), + .with_entry(test_id(100), StorageEntry { prev_valid_from: Some(test_id(50)), value: 100 }) + .with_entry(test_id(50), StorageEntry { prev_valid_from: None, value: 50 }), + 30).unwrap(), None); } } diff --git a/core/client/db/src/cache/mod.rs b/core/client/db/src/cache/mod.rs index 64d3c4a25e7bf7e2d2a0e594295722b5bd64c307..1c112c9036f8272df799f685dcd1af927c1bd24a 100644 --- a/core/client/db/src/cache/mod.rs +++ b/core/client/db/src/cache/mod.rs @@ -221,7 +221,7 @@ impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> { ), parent.clone(), block.clone(), - value.or(cache.value_at_block(&parent)?), + value, entry_type, )?; if let Some(op) = op { diff --git a/core/client/db/src/lib.rs b/core/client/db/src/lib.rs index bf6ceeaa58cd3f69e91c19d0fd45687f8b7fdcd3..98ecbd717b7c3a8485a5806539b1af99981a3dc8 100644 --- a/core/client/db/src/lib.rs +++ b/core/client/db/src/lib.rs @@ -24,7 +24,10 @@ //! //! Finality implies canonicality but not vice-versa. +#![warn(missing_docs)] + pub mod light; +pub mod offchain; mod cache; mod storage_cache; @@ -77,6 +80,10 @@ const DEFAULT_CHILD_RATIO: (usize, usize) = (1, 10); /// DB-backed patricia trie state, transaction type is an overlay of changes to commit. pub type DbState = state_machine::TrieBackend>, Blake2Hasher>; +/// A reference tracking state. +/// +/// It makes sure that the hash we are using stays pinned in storage +/// until this structure is dropped. pub struct RefTrackingState { state: DbState, storage: Arc>, @@ -211,7 +218,7 @@ pub fn new_client( )) } -mod columns { +pub(crate) mod columns { pub const META: Option = crate::utils::COLUMN_META; pub const STATE: Option = Some(1); pub const STATE_META: Option = Some(2); @@ -222,6 +229,8 @@ mod columns { pub const JUSTIFICATION: Option = Some(6); pub const CHANGES_TRIE: Option = Some(7); pub const AUX: Option = Some(8); + /// Offchain workers local storage + pub const OFFCHAIN: Option = Some(9); } struct PendingBlock { @@ -540,6 +549,7 @@ impl state_machine::Storage for DbGenesisStorage { } } +/// A database wrapper for changes tries. pub struct DbChangesTrieStorage { db: Arc, meta: Arc, Block::Hash>>>, @@ -684,6 +694,7 @@ where /// Otherwise, trie nodes are kept only from some recent blocks. pub struct Backend { storage: Arc>, + offchain_storage: offchain::LocalStorage, changes_tries_storage: DbChangesTrieStorage, /// None<*> means that the value hasn't been cached yet. Some(*) means that the value (either None or /// Some(*)) has been cached and is valid. @@ -698,31 +709,29 @@ impl> Backend { /// Create a new instance of database backend. /// /// The pruning window is how old a block must be before the state is pruned. - pub fn new(config: DatabaseSettings, canonicalization_delay: u64) -> Result { + pub fn new(config: DatabaseSettings, canonicalization_delay: u64) -> client::error::Result { Self::new_inner(config, canonicalization_delay) } - #[cfg(feature = "kvdb-rocksdb")] fn new_inner(config: DatabaseSettings, canonicalization_delay: u64) -> Result { + #[cfg(feature = "kvdb-rocksdb")] let db = crate::utils::open_database(&config, columns::META, "full")?; - Backend::from_kvdb(db as Arc<_>, canonicalization_delay, &config) - } - - #[cfg(not(feature = "kvdb-rocksdb"))] - fn new_inner(config: DatabaseSettings, canonicalization_delay: u64) -> Result { - log::warn!("Running without the RocksDB feature. The database will NOT be saved."); - let db = Arc::new(kvdb_memorydb::create(crate::utils::NUM_COLUMNS)); - Backend::from_kvdb(db as Arc<_>, canonicalization_delay, &config) + #[cfg(not(feature = "kvdb-rocksdb"))] + let db = { + log::warn!("Running without the RocksDB feature. The database will NOT be saved."); + Arc::new(kvdb_memorydb::create(crate::utils::NUM_COLUMNS)) + }; + Self::from_kvdb(db as Arc<_>, canonicalization_delay, &config) } + /// Create new memory-backed client backend for tests. #[cfg(any(test, feature = "test-helpers"))] pub fn new_test(keep_blocks: u32, canonicalization_delay: u64) -> Self { - use utils::NUM_COLUMNS; - - let db = Arc::new(::kvdb_memorydb::create(NUM_COLUMNS)); + let db = Arc::new(kvdb_memorydb::create(crate::utils::NUM_COLUMNS)); Self::new_test_db(keep_blocks, canonicalization_delay, db as Arc<_>) } + /// Creates a client backend with test settings. #[cfg(any(test, feature = "test-helpers"))] pub fn new_test_db(keep_blocks: u32, canonicalization_delay: u64, db: Arc) -> Self { @@ -733,7 +742,7 @@ impl> Backend { path: Default::default(), pruning: PruningMode::keep_blocks(keep_blocks), }; - Backend::from_kvdb( + Self::from_kvdb( db, canonicalization_delay, &db_setting, @@ -754,6 +763,7 @@ impl> Backend { db: db.clone(), state_db, }; + let offchain_storage = offchain::LocalStorage::new(db.clone()); let changes_tries_storage = DbChangesTrieStorage { db, meta, @@ -763,6 +773,7 @@ impl> Backend { Ok(Backend { storage: Arc::new(storage_db), + offchain_storage, changes_tries_storage, changes_trie_config: Mutex::new(None), blockchain, @@ -1116,6 +1127,7 @@ impl> Backend { hash.clone(), (number.clone(), hash.clone()) )?; + meta_updates.push((hash, *number, true, false)); } else { return Err(client::error::Error::UnknownBlock(format!("Cannot set head {:?}", set_head))) } @@ -1241,6 +1253,7 @@ impl client::backend::Backend for Backend whe type Blockchain = BlockchainDb; type State = CachingState, Block>; type ChangesTrieStorage = DbChangesTrieStorage; + type OffchainStorage = offchain::LocalStorage; fn begin_operation(&self) -> Result { let old_state = self.state_at(BlockId::Hash(Default::default()))?; @@ -1314,6 +1327,10 @@ impl client::backend::Backend for Backend whe Some(&self.changes_tries_storage) } + fn offchain_storage(&self) -> Option { + Some(self.offchain_storage.clone()) + } + fn revert(&self, n: NumberFor) -> Result, client::error::Error> { let mut best = self.blockchain.info().best_number; let finalized = self.blockchain.info().finalized_number; diff --git a/core/client/db/src/light.rs b/core/client/db/src/light.rs index 83ea444c9067617eb6b7a379bb235476dea6f423..1b6f3b3b1ab4754d7220fcce60f84da70b2d2230 100644 --- a/core/client/db/src/light.rs +++ b/core/client/db/src/light.rs @@ -84,6 +84,7 @@ impl LightStorage Self::from_kvdb(db as Arc<_>) } + /// Create new memory-backed `LightStorage` for tests. #[cfg(any(test, feature = "test-helpers"))] pub fn new_test() -> Self { use utils::NUM_COLUMNS; @@ -496,6 +497,7 @@ impl LightBlockchainStorage for LightStorage let mut transaction = DBTransaction::new(); self.set_head_with_transaction(&mut transaction, hash.clone(), (number.clone(), hash.clone()))?; self.db.write(transaction).map_err(db_err)?; + self.update_meta(hash, header.number().clone(), true, false); Ok(()) } else { Err(ClientError::UnknownBlock(format!("Cannot set head {:?}", id))) diff --git a/core/client/db/src/offchain.rs b/core/client/db/src/offchain.rs new file mode 100644 index 0000000000000000000000000000000000000000..3cefdbf47a2888a0b2464e2508a7ea4eab146caf --- /dev/null +++ b/core/client/db/src/offchain.rs @@ -0,0 +1,148 @@ +// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +//! RocksDB-based offchain workers local storage. + +use std::{ + collections::HashMap, + sync::Arc, +}; + +use crate::columns; +use kvdb::KeyValueDB; +use parking_lot::Mutex; + +/// Offchain local storage +#[derive(Clone)] +pub struct LocalStorage { + db: Arc, + locks: Arc, Arc>>>>, +} + +impl std::fmt::Debug for LocalStorage { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + fmt.debug_struct("LocalStorage") + .finish() + } +} + +impl LocalStorage { + /// Create new offchain storage for tests (backed by memorydb) + #[cfg(any(test, feature = "test-helpers"))] + pub fn new_test() -> Self { + let db = Arc::new(::kvdb_memorydb::create(crate::utils::NUM_COLUMNS)); + Self::new(db as _) + } + + /// Create offchain local storage with given `KeyValueDB` backend. + pub fn new(db: Arc) -> Self { + Self { + db, + locks: Default::default(), + } + } +} + +impl client::backend::OffchainStorage for LocalStorage { + fn set(&mut self, prefix: &[u8], key: &[u8], value: &[u8]) { + let key: Vec = prefix.iter().chain(key).cloned().collect(); + let mut tx = self.db.transaction(); + tx.put(columns::OFFCHAIN, &key, value); + + if let Err(e) = self.db.write(tx) { + log::warn!("Error writing to the offchain DB: {:?}", e); + } + } + + fn get(&self, prefix: &[u8], key: &[u8]) -> Option> { + let key: Vec = prefix.iter().chain(key).cloned().collect(); + self.db.get(columns::OFFCHAIN, &key) + .ok() + .and_then(|x| x) + .map(|v| v.to_vec()) + } + + fn compare_and_set( + &mut self, + prefix: &[u8], + item_key: &[u8], + old_value: Option<&[u8]>, + new_value: &[u8], + ) -> bool { + let key: Vec = prefix.iter().chain(item_key).cloned().collect(); + let key_lock = { + let mut locks = self.locks.lock(); + locks.entry(key.clone()).or_default().clone() + }; + + let is_set; + { + let _key_guard = key_lock.lock(); + let val = self.db.get(columns::OFFCHAIN, &key) + .ok() + .and_then(|x| x); + is_set = val.as_ref().map(|x| &**x) == old_value; + + if is_set { + self.set(prefix, item_key, new_value) + } + } + + // clean the lock map if we're the only entry + let mut locks = self.locks.lock(); + { + drop(key_lock); + let key_lock = locks.get_mut(&key); + if let Some(_) = key_lock.and_then(Arc::get_mut) { + locks.remove(&key); + } + } + is_set + } +} + +#[cfg(test)] +mod tests { + use super::*; + use client::backend::OffchainStorage; + + #[test] + fn should_compare_and_set_and_clear_the_locks_map() { + let mut storage = LocalStorage::new_test(); + let prefix = b"prefix"; + let key = b"key"; + let value = b"value"; + + storage.set(prefix, key, value); + assert_eq!(storage.get(prefix, key), Some(value.to_vec())); + + assert_eq!(storage.compare_and_set(prefix, key, Some(value), b"asd"), true); + assert_eq!(storage.get(prefix, key), Some(b"asd".to_vec())); + assert!(storage.locks.lock().is_empty(), "Locks map should be empty!"); + } + + #[test] + fn should_compare_and_set_on_empty_field() { + let mut storage = LocalStorage::new_test(); + let prefix = b"prefix"; + let key = b"key"; + + assert_eq!(storage.compare_and_set(prefix, key, None, b"asd"), true); + assert_eq!(storage.get(prefix, key), Some(b"asd".to_vec())); + assert!(storage.locks.lock().is_empty(), "Locks map should be empty!"); + } + +} diff --git a/core/client/db/src/utils.rs b/core/client/db/src/utils.rs index a4ab82b5d8b2d72c81913ae8d7664fe6adfa32b3..39862dba8575090a8d03bd2ac71ca8b8da004bcd 100644 --- a/core/client/db/src/utils.rs +++ b/core/client/db/src/utils.rs @@ -17,7 +17,9 @@ //! Db-based backend utility structures and functions, used by both //! full and light storages. -use std::{io, convert::TryInto, sync::Arc}; +#[cfg(feature = "kvdb-rocksdb")] +use std::sync::Arc; +use std::{io, convert::TryInto}; use kvdb::{KeyValueDB, DBTransaction}; #[cfg(feature = "kvdb-rocksdb")] @@ -32,11 +34,12 @@ use runtime_primitives::traits::{ Block as BlockT, Header as HeaderT, Zero, UniqueSaturatedFrom, UniqueSaturatedInto, CheckedConversion }; +#[cfg(feature = "kvdb-rocksdb")] use crate::DatabaseSettings; /// Number of columns in the db. Must be the same for both full && light dbs. /// Otherwise RocksDb will fail to open database && check its type. -pub const NUM_COLUMNS: u32 = 9; +pub const NUM_COLUMNS: u32 = 10; /// Meta column. The set of keys in the column is shared by full && light storages. pub const COLUMN_META: Option = Some(0); diff --git a/core/client/src/backend.rs b/core/client/src/backend.rs index 8860f61c47e7045639145dcb9ec8b81983c98a45..79bc1b475b4140af2846f7067ed32b7053ec19d7 100644 --- a/core/client/src/backend.rs +++ b/core/client/src/backend.rs @@ -139,6 +139,8 @@ pub trait Backend: AuxStore + Send + Sync where type State: StateBackend; /// Changes trie storage. type ChangesTrieStorage: PrunableStateChangesTrieStorage; + /// Offchain workers local storage. + type OffchainStorage: OffchainStorage; /// Begin a new block insertion transaction with given parent block id. /// When constructing the genesis, this is called with all-zero hash. @@ -156,6 +158,8 @@ pub trait Backend: AuxStore + Send + Sync where fn used_state_cache_size(&self) -> Option; /// Returns reference to changes trie storage. fn changes_trie_storage(&self) -> Option<&Self::ChangesTrieStorage>; + /// Returns a handle to offchain storage. + fn offchain_storage(&self) -> Option; /// Returns true if state for given block is available. fn have_state_at(&self, hash: &Block::Hash, _number: NumberFor) -> bool { self.state_at(BlockId::Hash(hash.clone())).is_ok() @@ -194,6 +198,26 @@ pub trait Backend: AuxStore + Send + Sync where fn get_import_lock(&self) -> &Mutex<()>; } +/// Offchain workers local storage. +pub trait OffchainStorage: Clone + Send + Sync { + /// Persist a value in storage under given key and prefix. + fn set(&mut self, prefix: &[u8], key: &[u8], value: &[u8]); + + /// Retrieve a value from storage under given key and prefix. + fn get(&self, prefix: &[u8], key: &[u8]) -> Option>; + + /// Replace the value in storage if given old_value matches the current one. + /// + /// Returns `true` if the value has been set and false otherwise. + fn compare_and_set( + &mut self, + prefix: &[u8], + key: &[u8], + old_value: Option<&[u8]>, + new_value: &[u8], + ) -> bool; +} + /// Changes trie storage that supports pruning. pub trait PrunableStateChangesTrieStorage: StateChangesTrieStorage> diff --git a/core/client/src/blockchain.rs b/core/client/src/blockchain.rs index 1ac328190240eef125bac74f85affa78e26c778a..a957eeff87a5de81299894d5e13dde7bd0c2a963 100644 --- a/core/client/src/blockchain.rs +++ b/core/client/src/blockchain.rs @@ -85,7 +85,7 @@ pub trait Backend: HeaderBackend { /// Returns hashes of all blocks that are leaves of the block tree. /// in other words, that have no children, are chain heads. - /// Results must be ordered best (longest, heighest) chain first. + /// Results must be ordered best (longest, highest) chain first. fn leaves(&self) -> Result>; /// Return hashes of all blocks that are children of the block with `parent_hash`. diff --git a/core/client/src/call_executor.rs b/core/client/src/call_executor.rs index f956f27b5058b813452a00e448599da946be27f9..c107e6f2bbd4a91f6b874fb56d3b3331d9a6e86d 100644 --- a/core/client/src/call_executor.rs +++ b/core/client/src/call_executor.rs @@ -110,7 +110,7 @@ where manager: ExecutionManager, native_call: Option, side_effects_handler: Option<&mut O>, - ) -> Result<(NativeOrEncoded, S::Transaction, Option>), error::Error>; + ) -> Result<(NativeOrEncoded, (S::Transaction, H::Out), Option>), error::Error>; /// Execute a call to a contract on top of given state, gathering execution proof. /// @@ -314,7 +314,11 @@ where manager: ExecutionManager, native_call: Option, side_effects_handler: Option<&mut O>, - ) -> error::Result<(NativeOrEncoded, S::Transaction, Option>)> { + ) -> error::Result<( + NativeOrEncoded, + (S::Transaction, ::Out), + Option>, + )> { state_machine::new( state, self.backend.changes_trie_storage(), diff --git a/core/client/src/client.rs b/core/client/src/client.rs index 70dd0d2808f03885e2fdb962e20066203dfe66e3..e13ebd6dadb8ffd4699ceebc1f838db0cde4bad3 100644 --- a/core/client/src/client.rs +++ b/core/client/src/client.rs @@ -21,7 +21,7 @@ use std::{ panic::UnwindSafe, result, cell::RefCell, rc::Rc, }; use crate::error::Error; -use futures::sync::mpsc; +use futures::channel::mpsc; use parking_lot::{Mutex, RwLock}; use primitives::NativeOrEncoded; use runtime_primitives::{ @@ -1029,7 +1029,11 @@ impl Client where let (top, children) = overlay.into_committed(); let children = children.map(|(sk, it)| (sk, it.collect())).collect(); - Ok((Some(storage_update), Some(changes_update), Some((top.collect(), children)))) + if import_headers.post().state_root() != &storage_update.1 { + return Err(error::Error::InvalidStateRoot); + } + + Ok((Some(storage_update.0), Some(changes_update), Some((top.collect(), children)))) }, None => Ok((None, None, None)) } @@ -1073,8 +1077,13 @@ impl Client where // if the block is not a direct ancestor of the current best chain, // then some other block is the common ancestor. if route_from_best.common_block().hash != block { - // FIXME: #1442 reorganize best block to be the best chain containing - // `block`. + // NOTE: we're setting the finalized block as best block, this might + // be slightly innacurate since we might have a "better" block + // further along this chain, but since best chain selection logic is + // pluggable we cannot make a better choice here. usages that need + // an accurate "best" block need to go through `SelectChain` + // instead. + operation.op.mark_head(BlockId::Hash(block))?; } let enacted = route_from_finalized.enacted(); @@ -1186,6 +1195,11 @@ impl Client where /// Mark all blocks up to given as finalized in operation. If a /// justification is provided it is stored with the given finalized /// block (any other finalized blocks are left unjustified). + /// + /// If the block being finalized is on a different fork from the current + /// best block the finalized block is set as best, this might be slightly + /// innacurate (i.e. outdated), usages that require determining an accurate + /// best block should use `SelectChain` instead of the client. pub fn apply_finality( &self, operation: &mut ClientImportOperation, @@ -1201,6 +1215,11 @@ impl Client where /// Finalize a block. This will implicitly finalize all blocks up to it and /// fire finality notifications. /// + /// If the block being finalized is on a different fork from the current + /// best block the finalized block is set as best, this might be slightly + /// innacurate (i.e. outdated), usages that require determining an accurate + /// best block should use `SelectChain` instead of the client. + /// /// Pass a flag to indicate whether finality notifications should be propagated. /// This is usually tied to some synchronization state, where we don't send notifications /// while performing major synchronization work. @@ -1436,7 +1455,7 @@ impl CallRuntimeAt for Client where } } -impl consensus::BlockImport for Client where +impl<'a, B, E, Block, RA> consensus::BlockImport for &'a Client where B: backend::Backend, E: CallExecutor + Clone + Send + Sync, Block: BlockT, @@ -1446,7 +1465,7 @@ impl consensus::BlockImport for Client /// Import a checked and validated block. If a justification is provided in /// `ImportBlock` then `finalized` *must* be true. fn import_block( - &self, + &mut self, import_block: ImportBlock, new_cache: HashMap>, ) -> Result { @@ -1457,7 +1476,7 @@ impl consensus::BlockImport for Client /// Check block preconditions. fn check_block( - &self, + &mut self, hash: Block::Hash, parent_hash: Block::Hash, ) -> Result { @@ -1481,6 +1500,30 @@ impl consensus::BlockImport for Client } } +impl consensus::BlockImport for Client where + B: backend::Backend, + E: CallExecutor + Clone + Send + Sync, + Block: BlockT, +{ + type Error = ConsensusError; + + fn import_block( + &mut self, + import_block: ImportBlock, + new_cache: HashMap>, + ) -> Result { + (&*self).import_block(import_block, new_cache) + } + + fn check_block( + &mut self, + hash: Block::Hash, + parent_hash: Block::Hash, + ) -> Result { + (&*self).check_block(hash, parent_hash) + } +} + impl CurrentHeight for Client where B: backend::Backend, E: CallExecutor, @@ -1564,9 +1607,12 @@ where } fn best_block_header(&self) -> error::Result<::Header> { - let info : ChainInfo = self.backend.blockchain().info(); - Ok(self.backend.blockchain().header(BlockId::Hash(info.best_hash))? - .expect("Best block header must always exist")) + let info = self.backend.blockchain().info(); + let best_hash = self.best_containing(info.best_hash, None)? + .unwrap_or(info.best_hash); + + Ok(self.backend.blockchain().header(BlockId::Hash(best_hash))? + .expect("given block hash was fetched from block in db; qed")) } /// Get the most recent block hash of the best (longest) chains @@ -1600,7 +1646,7 @@ where } } - let (leaves, best_already_checked) = { + let leaves = { // ensure no blocks are imported during this code block. // an import could trigger a reorg which could change the canonical chain. // we depend on the canonical chain staying the same during this code block. @@ -1612,29 +1658,24 @@ where .ok_or_else(|| error::Error::from(format!("failed to get hash for block number {}", target_header.number())))?; if canon_hash == target_hash { - // if no block at the given max depth exists fallback to the best block + // if a `max_number` is given we try to fetch the block at the + // given depth, if it doesn't exist or `max_number` is not + // provided, we continue to search from all leaves below. if let Some(max_number) = maybe_max_number { if let Some(header) = self.backend.blockchain().hash(max_number)? { return Ok(Some(header)); } } - - return Ok(Some(info.best_hash)); } else if info.finalized_number >= *target_header.number() { // header is on a dead fork. return Ok(None); } - (self.backend.blockchain().leaves()?, info.best_hash) + self.backend.blockchain().leaves()? }; // for each chain. longest chain first. shortest last for leaf_hash in leaves { - // ignore canonical chain which we already checked above - if leaf_hash == best_already_checked { - continue; - } - // start at the leaf let mut current_hash = leaf_hash; @@ -2470,4 +2511,129 @@ pub(crate) mod tests { None, ); } + + #[test] + fn importing_diverged_finalized_block_should_trigger_reorg() { + use test_client::blockchain::HeaderBackend; + + let client = test_client::new(); + + // G -> A1 -> A2 + // \ + // -> B1 + let a1 = client.new_block_at(&BlockId::Number(0), Default::default()).unwrap().bake().unwrap(); + client.import(BlockOrigin::Own, a1.clone()).unwrap(); + + let a2 = client.new_block_at(&BlockId::Hash(a1.hash()), Default::default()).unwrap().bake().unwrap(); + client.import(BlockOrigin::Own, a2.clone()).unwrap(); + + let mut b1 = client.new_block_at(&BlockId::Number(0), Default::default()).unwrap(); + // needed to make sure B1 gets a different hash from A1 + b1.push_transfer(Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), + amount: 1, + nonce: 0, + }).unwrap(); + // create but don't import B1 just yet + let b1 = b1.bake().unwrap(); + + #[allow(deprecated)] + let blockchain = client.backend().blockchain(); + + // A2 is the current best since it's the longest chain + assert_eq!( + blockchain.info().best_hash, + a2.hash(), + ); + + // importing B1 as finalized should trigger a re-org and set it as new best + let justification = vec![1, 2, 3]; + client.import_justified(BlockOrigin::Own, b1.clone(), justification).unwrap(); + + assert_eq!( + blockchain.info().best_hash, + b1.hash(), + ); + + assert_eq!( + blockchain.info().finalized_hash, + b1.hash(), + ); + } + + #[test] + fn finalizing_diverged_block_should_trigger_reorg() { + use test_client::blockchain::HeaderBackend; + + let (client, select_chain) = TestClientBuilder::new().build_with_longest_chain(); + + // G -> A1 -> A2 + // \ + // -> B1 -> B2 + let a1 = client.new_block_at(&BlockId::Number(0), Default::default()).unwrap().bake().unwrap(); + client.import(BlockOrigin::Own, a1.clone()).unwrap(); + + let a2 = client.new_block_at(&BlockId::Hash(a1.hash()), Default::default()).unwrap().bake().unwrap(); + client.import(BlockOrigin::Own, a2.clone()).unwrap(); + + let mut b1 = client.new_block_at(&BlockId::Number(0), Default::default()).unwrap(); + // needed to make sure B1 gets a different hash from A1 + b1.push_transfer(Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), + amount: 1, + nonce: 0, + }).unwrap(); + let b1 = b1.bake().unwrap(); + client.import(BlockOrigin::Own, b1.clone()).unwrap(); + + let b2 = client.new_block_at(&BlockId::Hash(b1.hash()), Default::default()).unwrap().bake().unwrap(); + client.import(BlockOrigin::Own, b2.clone()).unwrap(); + + #[allow(deprecated)] + let blockchain = client.backend().blockchain(); + + // A2 is the current best since it's the longest chain + assert_eq!( + blockchain.info().best_hash, + a2.hash(), + ); + + // we finalize block B1 which is on a different branch from current best + // which should trigger a re-org. + client.finalize_block(BlockId::Hash(b1.hash()), None, false).unwrap(); + + // B1 should now be the latest finalized + assert_eq!( + blockchain.info().finalized_hash, + b1.hash(), + ); + + // and B1 should be the new best block (`finalize_block` as no way of + // knowing about B2) + assert_eq!( + blockchain.info().best_hash, + b1.hash(), + ); + + // `SelectChain` should report B2 as best block though + assert_eq!( + select_chain.best_chain().unwrap().hash(), + b2.hash(), + ); + + // after we build B3 on top of B2 and import it + // it should be the new best block, + let b3 = client.new_block_at( + &BlockId::Hash(b2.hash()), + Default::default(), + ).unwrap().bake().unwrap(); + client.import(BlockOrigin::Own, b3.clone()).unwrap(); + + assert_eq!( + blockchain.info().best_hash, + b3.hash(), + ); + } } diff --git a/core/client/src/error.rs b/core/client/src/error.rs index b807d5e11cc5dddaff2d3b93b71b4e14855478f8..2de5a427819219ac910c19fb839e5b68b44122cf 100644 --- a/core/client/src/error.rs +++ b/core/client/src/error.rs @@ -94,6 +94,9 @@ pub enum Error { /// Hash that is required for building CHT is missing. #[display(fmt = "Failed to get hash of block for building CHT")] MissingHashRequiredForCHT, + /// Invalid calculated state root on block import. + #[display(fmt = "Calculated state root does not match.")] + InvalidStateRoot, /// A convenience variant for String #[display(fmt = "{}", _0)] Msg(String), diff --git a/core/client/src/genesis.rs b/core/client/src/genesis.rs index 73bd1e03680bc7649a2d8bf5fd4424fba65472da..8843ec84bc763e2f87c5c1bd360f121f956588db 100644 --- a/core/client/src/genesis.rs +++ b/core/client/src/genesis.rs @@ -53,7 +53,12 @@ mod tests { use primitives::Blake2Hasher; use hex::*; - native_executor_instance!(Executor, test_client::runtime::api::dispatch, test_client::runtime::native_version, include_bytes!("../../test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm")); + native_executor_instance!( + Executor, + test_client::runtime::api::dispatch, + test_client::runtime::native_version, + test_client::runtime::WASM_BINARY + ); fn executor() -> executor::NativeExecutor { NativeExecutionDispatch::new(None) diff --git a/core/client/src/in_mem.rs b/core/client/src/in_mem.rs index 72e8f31863dc59bd7f7d834a8426a65cd5590741..1606c074be0fd59dd272bbad222f6cbe424ee16c 100644 --- a/core/client/src/in_mem.rs +++ b/core/client/src/in_mem.rs @@ -593,6 +593,7 @@ where type Blockchain = Blockchain; type State = InMemory; type ChangesTrieStorage = ChangesTrieStorage; + type OffchainStorage = OffchainStorage; fn begin_operation(&self) -> error::Result { let old_state = self.state_at(BlockId::Hash(Default::default()))?; @@ -669,6 +670,10 @@ where Some(&self.changes_trie_storage) } + fn offchain_storage(&self) -> Option { + None + } + fn state_at(&self, block: BlockId) -> error::Result { match block { BlockId::Hash(h) if h == Default::default() => { @@ -768,8 +773,50 @@ pub fn check_genesis_storage(top: &StorageOverlay, children: &ChildrenStorageOve Ok(()) } +/// In-memory storage for offchain workers. +#[derive(Debug, Clone, Default)] +pub struct OffchainStorage { + storage: HashMap, Vec>, +} + +impl backend::OffchainStorage for OffchainStorage { + fn set(&mut self, prefix: &[u8], key: &[u8], value: &[u8]) { + let key = prefix.iter().chain(key).cloned().collect(); + self.storage.insert(key, value.to_vec()); + } + + fn get(&self, prefix: &[u8], key: &[u8]) -> Option> { + let key: Vec = prefix.iter().chain(key).cloned().collect(); + self.storage.get(&key).cloned() + } + + fn compare_and_set( + &mut self, + prefix: &[u8], + key: &[u8], + old_value: Option<&[u8]>, + new_value: &[u8], + ) -> bool { + use std::collections::hash_map::Entry; + let key = prefix.iter().chain(key).cloned().collect(); + + match self.storage.entry(key) { + Entry::Vacant(entry) => if old_value.is_none() { + entry.insert(new_value.to_vec()); + true + } else { false }, + Entry::Occupied(ref mut entry) if Some(entry.get().as_slice()) == old_value => { + entry.insert(new_value.to_vec()); + true + }, + _ => false, + } + } +} + #[cfg(test)] mod tests { + use super::*; use std::sync::Arc; use test_client; use primitives::Blake2Hasher; @@ -789,4 +836,26 @@ mod tests { test_client::trait_tests::test_blockchain_query_by_number_gets_canonical(backend); } + + #[test] + fn in_memory_offchain_storage() { + use crate::backend::OffchainStorage as _; + + let mut storage = OffchainStorage::default(); + assert_eq!(storage.get(b"A", b"B"), None); + assert_eq!(storage.get(b"B", b"A"), None); + + storage.set(b"A", b"B", b"C"); + assert_eq!(storage.get(b"A", b"B"), Some(b"C".to_vec())); + assert_eq!(storage.get(b"B", b"A"), None); + + storage.compare_and_set(b"A", b"B", Some(b"X"), b"D"); + assert_eq!(storage.get(b"A", b"B"), Some(b"C".to_vec())); + storage.compare_and_set(b"A", b"B", Some(b"C"), b"D"); + assert_eq!(storage.get(b"A", b"B"), Some(b"D".to_vec())); + + assert!(!storage.compare_and_set(b"B", b"A", Some(b""), b"Y")); + assert!(storage.compare_and_set(b"B", b"A", None, b"X")); + assert_eq!(storage.get(b"B", b"A"), Some(b"X".to_vec())); + } } diff --git a/core/client/src/lib.rs b/core/client/src/lib.rs index 8062fae500199692810d2f79d401a3e1feeec663..67cfdd4a64d82fada5b97647c860df0045268417 100644 --- a/core/client/src/lib.rs +++ b/core/client/src/lib.rs @@ -58,7 +58,7 @@ pub use crate::client::{ new_with_backend, new_in_mem, BlockBody, BlockStatus, ImportNotifications, FinalityNotifications, BlockchainEvents, - BlockImportNotification, Client, ClientInfo, ExecutionStrategies, + BlockImportNotification, Client, ClientInfo, ExecutionStrategies, FinalityNotification, LongestChain, }; #[cfg(feature = "std")] diff --git a/core/client/src/light/backend.rs b/core/client/src/light/backend.rs index f71366808eccd146bb341ab69a6407806f714ada..6f6bde2418373c85f17d18e08cb1482a8daaa114 100644 --- a/core/client/src/light/backend.rs +++ b/core/client/src/light/backend.rs @@ -19,7 +19,6 @@ use std::collections::HashMap; use std::sync::{Arc, Weak}; -use futures::{Future, IntoFuture}; use parking_lot::{RwLock, Mutex}; use runtime_primitives::{generic::BlockId, Justification, StorageOverlay, ChildrenStorageOverlay}; @@ -38,7 +37,7 @@ use hash_db::Hasher; use trie::MemoryDB; use consensus::well_known_cache_keys; -const IN_MEMORY_EXPECT_PROOF: &str = "InMemory state backend has Void error type and always suceeds; qed"; +const IN_MEMORY_EXPECT_PROOF: &str = "InMemory state backend has Void error type and always succeeds; qed"; /// Light client backend. pub struct Backend { @@ -118,6 +117,7 @@ impl ClientBackend for Backend where type Blockchain = Blockchain; type State = OnDemandOrGenesisState; type ChangesTrieStorage = in_mem::ChangesTrieStorage; + type OffchainStorage = in_mem::OffchainStorage; fn begin_operation(&self) -> ClientResult { Ok(ImportOperation { @@ -195,6 +195,10 @@ impl ClientBackend for Backend where None } + fn offchain_storage(&self) -> Option { + None + } + fn state_at(&self, block: BlockId) -> ClientResult { let block_number = self.blockchain.expect_block_number_from_id(&block)?; @@ -354,14 +358,15 @@ where *self.cached_header.write() = Some(cached_header); } - self.fetcher.upgrade().ok_or(ClientError::NotAvailableOnLightClient)? - .remote_read(RemoteReadRequest { - block: self.block, - header: header.expect("if block above guarantees that header is_some(); qed"), - key: key.to_vec(), - retry_count: None, - }) - .into_future().wait() + futures::executor::block_on( + self.fetcher.upgrade().ok_or(ClientError::NotAvailableOnLightClient)? + .remote_read(RemoteReadRequest { + block: self.block, + header: header.expect("if block above guarantees that header is_some(); qed"), + key: key.to_vec(), + retry_count: None, + }) + ) } fn child_storage(&self, _storage_key: &[u8], _key: &[u8]) -> ClientResult>> { diff --git a/core/client/src/light/blockchain.rs b/core/client/src/light/blockchain.rs index e3d9c55a6a4633c0197debdd6ac9f93b2ee93ece..6bd4c787d50bd8d2fc0bc19b9fe76c131cacd4fe 100644 --- a/core/client/src/light/blockchain.rs +++ b/core/client/src/light/blockchain.rs @@ -18,7 +18,6 @@ //! blocks. CHT roots are stored for headers of ancient blocks. use std::{sync::{Weak, Arc}, collections::HashMap}; -use futures::{Future, IntoFuture}; use parking_lot::Mutex; use runtime_primitives::{Justification, generic::BlockId}; @@ -122,14 +121,15 @@ impl BlockchainHeaderBackend for Blockchain where Bloc return Ok(None); } - self.fetcher().upgrade().ok_or(ClientError::NotAvailableOnLightClient)? - .remote_header(RemoteHeaderRequest { - cht_root: self.storage.header_cht_root(cht::size(), number)?, - block: number, - retry_count: None, + futures::executor::block_on( + self.fetcher().upgrade() + .ok_or(ClientError::NotAvailableOnLightClient)? + .remote_header(RemoteHeaderRequest { + cht_root: self.storage.header_cht_root(cht::size(), number)?, + block: number, + retry_count: None, }) - .into_future().wait() - .map(Some) + ).map(Some) } } } @@ -158,13 +158,13 @@ impl BlockchainBackend for Blockchain where Block: Blo None => return Ok(None), }; - self.fetcher().upgrade().ok_or(ClientError::NotAvailableOnLightClient)? - .remote_body(RemoteBodyRequest { - header, - retry_count: None, - }) - .into_future().wait() - .map(Some) + futures::executor::block_on( + self.fetcher().upgrade().ok_or(ClientError::NotAvailableOnLightClient)? + .remote_body(RemoteBodyRequest { + header, + retry_count: None, + }) + ).map(Some) } fn justification(&self, _id: BlockId) -> ClientResult> { diff --git a/core/client/src/light/call_executor.rs b/core/client/src/light/call_executor.rs index 4dba803921527d836f2a9acab7fbe7b40290dbc8..faa7c10def0702b2f52735704113e16168b3d2d6 100644 --- a/core/client/src/light/call_executor.rs +++ b/core/client/src/light/call_executor.rs @@ -21,7 +21,6 @@ use std::{ collections::HashSet, sync::Arc, panic::UnwindSafe, result, marker::PhantomData, cell::RefCell, rc::Rc, }; -use futures::{IntoFuture, Future}; use parity_codec::{Encode, Decode}; use primitives::{offchain, H256, Blake2Hasher, convert_hash, NativeOrEncoded}; @@ -100,13 +99,13 @@ where let block_hash = self.blockchain.expect_block_hash_from_id(id)?; let block_header = self.blockchain.expect_header(id.clone())?; - self.fetcher.remote_call(RemoteCallRequest { + futures::executor::block_on(self.fetcher.remote_call(RemoteCallRequest { block: block_hash, header: block_header, method: method.into(), call_data: call_data.to_vec(), retry_count: None, - }).into_future().wait() + })) } fn contextual_call< @@ -170,7 +169,11 @@ where _m: ExecutionManager, _native_call: Option, _side_effects_handler: Option<&mut O>, - ) -> ClientResult<(NativeOrEncoded, S::Transaction, Option>)> { + ) -> ClientResult<( + NativeOrEncoded, + (S::Transaction, ::Out), + Option>, + )> { Err(ClientError::NotAvailableOnLightClient.into()) } @@ -343,7 +346,11 @@ impl CallExecutor for _manager: ExecutionManager, native_call: Option, side_effects_handler: Option<&mut O>, - ) -> ClientResult<(NativeOrEncoded, S::Transaction, Option>)> { + ) -> ClientResult<( + NativeOrEncoded, + (S::Transaction, ::Out), + Option>, + )> { // there's no actual way/need to specify native/wasm execution strategy on light node // => we can safely ignore passed values diff --git a/core/client/src/light/fetcher.rs b/core/client/src/light/fetcher.rs index c77ebcd0fdd3a8b96eed66a05f930ff862303513..dd718001cd265e431e6ef84f570c8fb9f6c7c33e 100644 --- a/core/client/src/light/fetcher.rs +++ b/core/client/src/light/fetcher.rs @@ -19,7 +19,7 @@ use std::sync::Arc; use std::collections::BTreeMap; use std::marker::PhantomData; -use futures::IntoFuture; +use std::future::Future; use hash_db::{HashDB, Hasher}; use parity_codec::{Decode, Encode}; @@ -141,15 +141,15 @@ pub struct RemoteBodyRequest { /// is correct (see FetchedDataChecker) and return already checked data. pub trait Fetcher: Send + Sync { /// Remote header future. - type RemoteHeaderResult: IntoFuture; + type RemoteHeaderResult: Future>; /// Remote storage read future. - type RemoteReadResult: IntoFuture>, Error = ClientError>; + type RemoteReadResult: Future>, ClientError>>; /// Remote call result future. - type RemoteCallResult: IntoFuture, Error = ClientError>; + type RemoteCallResult: Future, ClientError>>; /// Remote changes result future. - type RemoteChangesResult: IntoFuture, u32)>, Error = ClientError>; + type RemoteChangesResult: Future, u32)>, ClientError>>; /// Remote block body result future. - type RemoteBodyResult: IntoFuture, Error = ClientError>; + type RemoteBodyResult: Future, ClientError>>; /// Fetch remote header. fn remote_header(&self, request: RemoteHeaderRequest) -> Self::RemoteHeaderResult; @@ -484,7 +484,7 @@ impl<'a, H, Number, Hash> ChangesTrieRootsStorage for RootsStorage<'a #[cfg(test)] pub mod tests { - use futures::future::{ok, err, FutureResult}; + use futures::future::Ready; use parking_lot::Mutex; use parity_codec::Decode; use crate::client::tests::prepare_client_with_key_changes; @@ -508,19 +508,19 @@ pub mod tests { pub type OkCallFetcher = Mutex>; - fn not_implemented_in_tests() -> FutureResult + fn not_implemented_in_tests() -> Ready> where E: std::convert::From<&'static str>, { - err("Not implemented on test node".into()) + futures::future::ready(Err("Not implemented on test node".into())) } impl Fetcher for OkCallFetcher { - type RemoteHeaderResult = FutureResult; - type RemoteReadResult = FutureResult>, ClientError>; - type RemoteCallResult = FutureResult, ClientError>; - type RemoteChangesResult = FutureResult, u32)>, ClientError>; - type RemoteBodyResult = FutureResult, ClientError>; + type RemoteHeaderResult = Ready>; + type RemoteReadResult = Ready>, ClientError>>; + type RemoteCallResult = Ready, ClientError>>; + type RemoteChangesResult = Ready, u32)>, ClientError>>; + type RemoteBodyResult = Ready, ClientError>>; fn remote_header(&self, _request: RemoteHeaderRequest
) -> Self::RemoteHeaderResult { not_implemented_in_tests() @@ -535,7 +535,7 @@ pub mod tests { } fn remote_call(&self, _request: RemoteCallRequest
) -> Self::RemoteCallResult { - ok((*self.lock()).clone()) + futures::future::ready(Ok((*self.lock()).clone())) } fn remote_changes(&self, _request: RemoteChangesRequest
) -> Self::RemoteChangesResult { diff --git a/core/client/src/notifications.rs b/core/client/src/notifications.rs index 931a40f20d37e39750e22366084ff321380b785d..bfd97df95c12d808663923550e50e568f7de6e2e 100644 --- a/core/client/src/notifications.rs +++ b/core/client/src/notifications.rs @@ -22,7 +22,7 @@ use std::{ }; use fnv::{FnvHashSet, FnvHashMap}; -use futures::sync::mpsc; +use futures::channel::mpsc; use primitives::storage::{StorageKey, StorageData}; use runtime_primitives::traits::Block as BlockT; @@ -309,7 +309,6 @@ impl StorageNotifications { mod tests { use runtime_primitives::testing::{H256 as Hash, Block as RawBlock, ExtrinsicWrapper}; use super::*; - use futures::Stream; use std::iter::{empty, Empty}; type TestChangeSet = ( @@ -348,7 +347,9 @@ mod tests { // given let mut notifications = StorageNotifications::::default(); let child_filter = [(StorageKey(vec![4]), None)]; - let mut recv = notifications.listen(None, Some(&child_filter[..])).wait(); + let mut recv = futures::executor::block_on_stream( + notifications.listen(None, Some(&child_filter[..])) + ); // when let changeset = vec![ @@ -367,13 +368,13 @@ mod tests { ); // then - assert_eq!(recv.next().unwrap(), Ok((Hash::from_low_u64_be(1), (vec![ + assert_eq!(recv.next().unwrap(), (Hash::from_low_u64_be(1), (vec![ (StorageKey(vec![2]), Some(StorageData(vec![3]))), (StorageKey(vec![3]), None), ], vec![(StorageKey(vec![4]), vec![ (StorageKey(vec![5]), Some(StorageData(vec![4]))), (StorageKey(vec![6]), None), - ])]).into()))); + ])]).into())); } #[test] @@ -381,9 +382,15 @@ mod tests { // given let mut notifications = StorageNotifications::::default(); let child_filter = [(StorageKey(vec![4]), Some(vec![StorageKey(vec![5])]))]; - let mut recv1 = notifications.listen(Some(&[StorageKey(vec![1])]), None).wait(); - let mut recv2 = notifications.listen(Some(&[StorageKey(vec![2])]), None).wait(); - let mut recv3 = notifications.listen(Some(&[]), Some(&child_filter)).wait(); + let mut recv1 = futures::executor::block_on_stream( + notifications.listen(Some(&[StorageKey(vec![1])]), None) + ); + let mut recv2 = futures::executor::block_on_stream( + notifications.listen(Some(&[StorageKey(vec![2])]), None) + ); + let mut recv3 = futures::executor::block_on_stream( + notifications.listen(Some(&[]), Some(&child_filter)) + ); // when let changeset = vec![ @@ -403,16 +410,16 @@ mod tests { ); // then - assert_eq!(recv1.next().unwrap(), Ok((Hash::from_low_u64_be(1), (vec![ + assert_eq!(recv1.next().unwrap(), (Hash::from_low_u64_be(1), (vec![ (StorageKey(vec![1]), None), - ], vec![]).into()))); - assert_eq!(recv2.next().unwrap(), Ok((Hash::from_low_u64_be(1), (vec![ + ], vec![]).into())); + assert_eq!(recv2.next().unwrap(), (Hash::from_low_u64_be(1), (vec![ (StorageKey(vec![2]), Some(StorageData(vec![3]))), - ], vec![]).into()))); - assert_eq!(recv3.next().unwrap(), Ok((Hash::from_low_u64_be(1), (vec![], + ], vec![]).into())); + assert_eq!(recv3.next().unwrap(), (Hash::from_low_u64_be(1), (vec![], vec![ (StorageKey(vec![4]), vec![(StorageKey(vec![5]), Some(StorageData(vec![4])))]), - ]).into()))); + ]).into())); } @@ -422,10 +429,18 @@ mod tests { let mut notifications = StorageNotifications::::default(); { let child_filter = [(StorageKey(vec![4]), Some(vec![StorageKey(vec![5])]))]; - let _recv1 = notifications.listen(Some(&[StorageKey(vec![1])]), None).wait(); - let _recv2 = notifications.listen(Some(&[StorageKey(vec![2])]), None).wait(); - let _recv3 = notifications.listen(None, None).wait(); - let _recv4 = notifications.listen(None, Some(&child_filter)).wait(); + let _recv1 = futures::executor::block_on_stream( + notifications.listen(Some(&[StorageKey(vec![1])]), None) + ); + let _recv2 = futures::executor::block_on_stream( + notifications.listen(Some(&[StorageKey(vec![2])]), None) + ); + let _recv3 = futures::executor::block_on_stream( + notifications.listen(None, None) + ); + let _recv4 = futures::executor::block_on_stream( + notifications.listen(None, Some(&child_filter)) + ); assert_eq!(notifications.listeners.len(), 2); assert_eq!(notifications.wildcard_listeners.len(), 2); assert_eq!(notifications.child_listeners.len(), 1); @@ -450,7 +465,7 @@ mod tests { // given let mut recv = { let mut notifications = StorageNotifications::::default(); - let recv = notifications.listen(None, None).wait(); + let recv = futures::executor::block_on_stream(notifications.listen(None, None)); // when let changeset = vec![]; diff --git a/core/consensus/aura/Cargo.toml b/core/consensus/aura/Cargo.toml index 400f209a9b7c36b712c7bf5bc72659074ca84763..03ddf79be3418fde50053aa48fdf9ba1de15d51a 100644 --- a/core/consensus/aura/Cargo.toml +++ b/core/consensus/aura/Cargo.toml @@ -6,7 +6,7 @@ description = "Aura consensus algorithm for substrate" edition = "2018" [dependencies] -parity-codec = "3.4" +parity-codec = "4.1.1" primitives = { package = "substrate-primitives", path = "../../primitives" } runtime_support = { package = "srml-support", path = "../../../srml/support" } runtime_version = { package = "sr-version", path = "../../sr-version" } @@ -25,6 +25,7 @@ parking_lot = "0.8.0" log = "0.4" [dev-dependencies] +futures03 = { package = "futures-preview", version = "0.3.0-alpha.17", features = ["compat"] } keyring = { package = "substrate-keyring", path = "../../keyring" } substrate-executor = { path = "../../executor" } network = { package = "substrate-network", path = "../../network", features = ["test-helpers"]} diff --git a/core/consensus/aura/primitives/Cargo.toml b/core/consensus/aura/primitives/Cargo.toml index 74f678a6c0bc9f64ebf8100b7b2462e64408c7fd..bc51c90d8c7e0450c15fc62cb20a29382778c01c 100644 --- a/core/consensus/aura/primitives/Cargo.toml +++ b/core/consensus/aura/primitives/Cargo.toml @@ -6,7 +6,7 @@ description = "Primitives for Aura consensus" edition = "2018" [dependencies] -parity-codec = { version = "3.5", default-features = false } +parity-codec = { version = "4.1.1", default-features = false } substrate-client = { path = "../../../client", default-features = false } substrate-primitives = { path = "../../../primitives", default-features = false } rstd = { package = "sr-std", path = "../../../sr-std", default-features = false } diff --git a/core/consensus/aura/primitives/src/lib.rs b/core/consensus/aura/primitives/src/lib.rs index 9bdf39d29337d5d4e2ae0766a34216821f77626c..47b1399a677f420fcc18f5efad733d10d3cb82f0 100644 --- a/core/consensus/aura/primitives/src/lib.rs +++ b/core/consensus/aura/primitives/src/lib.rs @@ -26,11 +26,18 @@ use runtime_primitives::ConsensusEngineId; /// The `ConsensusEngineId` of AuRa. pub const AURA_ENGINE_ID: ConsensusEngineId = [b'a', b'u', b'r', b'a']; +/// The index of an authority. +pub type AuthorityIndex = u64; + /// An consensus log item for Aura. #[derive(Decode, Encode)] pub enum ConsensusLog { /// The authorities have changed. + #[codec(index = "1")] AuthoritiesChange(Vec), + /// Disable the authority with given index. + #[codec(index = "2")] + OnDisabled(AuthorityIndex), } decl_runtime_apis! { diff --git a/core/consensus/aura/src/lib.rs b/core/consensus/aura/src/lib.rs index 896b2d4b00d232834a7af56f0008b891666bb142..94b5f97ffc212e605a209c9f861cdda3b2ccd2c7 100644 --- a/core/consensus/aura/src/lib.rs +++ b/core/consensus/aura/src/lib.rs @@ -36,8 +36,7 @@ use consensus_common::{self, BlockImport, Environment, Proposer, SelectChain, well_known_cache_keys::{self, Id as CacheKeyId} }; use consensus_common::import_queue::{ - Verifier, BasicQueue, SharedBlockImport, SharedJustificationImport, SharedFinalityProofImport, - SharedFinalityProofRequestBuilder, + Verifier, BasicQueue, BoxBlockImport, BoxJustificationImport, BoxFinalityProofImport, }; use client::{ block_builder::api::BlockBuilder as BlockBuilderApi, @@ -54,6 +53,7 @@ use primitives::Pair; use inherents::{InherentDataProviders, InherentData}; use futures::{Future, IntoFuture, future}; +use parking_lot::Mutex; use tokio_timer::Timeout; use log::{error, warn, debug, info, trace}; @@ -63,7 +63,8 @@ use srml_aura::{ }; use substrate_telemetry::{telemetry, CONSENSUS_TRACE, CONSENSUS_DEBUG, CONSENSUS_WARN, CONSENSUS_INFO}; -use slots::{CheckedHeader, SlotData, SlotWorker, SlotInfo, SlotCompatible, slot_now, check_equivocation}; +use slots::{CheckedHeader, SlotData, SlotWorker, SlotInfo, SlotCompatible}; +use slots::{SignedDuration, check_equivocation}; pub use aura_primitives::*; pub use consensus_common::SyncOracle; @@ -116,12 +117,14 @@ struct AuraSlotCompatible; impl SlotCompatible for AuraSlotCompatible { fn extract_timestamp_and_slot( + &self, data: &InherentData - ) -> Result<(TimestampInherent, AuraInherent), consensus_common::Error> { + ) -> Result<(TimestampInherent, AuraInherent, std::time::Duration), consensus_common::Error> { data.timestamp_inherent_data() .and_then(|t| data.aura_inherent_data().map(|a| (t, a))) .map_err(Into::into) .map_err(consensus_common::Error::InherentData) + .map(|(x, y)| (x, y, Default::default())) } } @@ -131,7 +134,7 @@ pub fn start_aura( local_key: Arc

, client: Arc, select_chain: SC, - block_import: Arc, + block_import: I, env: Arc, sync_oracle: SO, inherent_data_providers: InherentDataProviders, @@ -154,7 +157,7 @@ pub fn start_aura( { let worker = AuraWorker { client: client.clone(), - block_import, + block_import: Arc::new(Mutex::new(block_import)), env, local_key, sync_oracle: sync_oracle.clone(), @@ -169,13 +172,14 @@ pub fn start_aura( select_chain, worker, sync_oracle, - inherent_data_providers + inherent_data_providers, + AuraSlotCompatible, )) } struct AuraWorker { client: Arc, - block_import: Arc, + block_import: Arc>, env: Arc, local_key: Arc

, sync_oracle: SO, @@ -283,8 +287,8 @@ impl SlotWorker for AuraWorker w Box::new(proposal_work.map(move |b| { // minor hack since we don't have access to the timestamp // that is actually set by the proposer. - let slot_after_building = slot_now(slot_duration); - if slot_after_building != Some(slot_num) { + let slot_after_building = SignedDuration::default().slot_now(slot_duration); + if slot_after_building != slot_num { info!( "Discarding proposal for slot {}; block production took too long", slot_num @@ -335,7 +339,7 @@ impl SlotWorker for AuraWorker w "hash_previously" => ?header_hash ); - if let Err(e) = block_import.import_block(import_block, Default::default()) { + if let Err(e) = block_import.lock().import_block(import_block, Default::default()) { warn!(target: "aura", "Error with block built on {:?}: {:?}", parent_hash, e); telemetry!(CONSENSUS_WARN; "aura.err_with_block_built_on"; @@ -513,7 +517,7 @@ impl Verifier for AuraVerifier where mut body: Option>, ) -> Result<(ImportBlock, Option)>>), String> { let mut inherent_data = self.inherent_data_providers.create_inherent_data().map_err(String::from)?; - let (timestamp_now, slot_now) = AuraSlotCompatible::extract_timestamp_and_slot(&inherent_data) + let (timestamp_now, slot_now, _) = AuraSlotCompatible.extract_timestamp_and_slot(&inherent_data) .map_err(|e| format!("Could not extract timestamp and slot: {:?}", e))?; let hash = header.hash(); let parent_hash = *header.parent_hash(); @@ -560,14 +564,19 @@ impl Verifier for AuraVerifier where trace!(target: "aura", "Checked {:?}; importing.", pre_header); telemetry!(CONSENSUS_TRACE; "aura.checked_and_importing"; "pre_header" => ?pre_header); - // `Consensus` is the Aura-specific authorities change log. + // Look for an authorities-change log. let maybe_keys = pre_header.digest() - .convert_first(|l| l.try_to::>>( + .logs() + .iter() + .filter_map(|l| l.try_to::>>( OpaqueDigestItemId::Consensus(&AURA_ENGINE_ID) )) - .map(|ConsensusLog::AuthoritiesChange(a)| - vec![(well_known_cache_keys::AUTHORITIES, a.encode())] - ); + .find_map(|l| match l { + ConsensusLog::AuthoritiesChange(a) => Some( + vec![(well_known_cache_keys::AUTHORITIES, a.encode())] + ), + _ => None, + }); let import_block = ImportBlock { origin, @@ -664,10 +673,9 @@ fn register_aura_inherent_data_provider( /// Start an import queue for the Aura consensus algorithm. pub fn import_queue( slot_duration: SlotDuration, - block_import: SharedBlockImport, - justification_import: Option>, - finality_proof_import: Option>, - finality_proof_request_builder: Option>, + block_import: BoxBlockImport, + justification_import: Option>, + finality_proof_import: Option>, client: Arc, inherent_data_providers: InherentDataProviders, ) -> Result, consensus_common::Error> where @@ -694,14 +702,14 @@ pub fn import_queue( block_import, justification_import, finality_proof_import, - finality_proof_request_builder, )) } #[cfg(test)] mod tests { use super::*; - use futures::stream::Stream as _; + use futures::{Async, stream::Stream as _}; + use futures03::{StreamExt as _, TryStreamExt as _}; use consensus_common::NoNetwork as DummyOracle; use network::test::*; use network::test::{Block as TestBlock, PeersClient, PeersFullClient}; @@ -752,11 +760,9 @@ mod tests { } const SLOT_DURATION: u64 = 1; - const TEST_ROUTING_INTERVAL: Duration = Duration::from_millis(50); pub struct AuraTestNet { - peers: Vec>>, - started: bool, + peers: Vec>, } impl TestNetFactory for AuraTestNet { @@ -768,7 +774,6 @@ mod tests { fn from_config(_config: &ProtocolConfig) -> Self { AuraTestNet { peers: Vec::new(), - started: false, } } @@ -796,38 +801,24 @@ mod tests { } } - fn uses_tokio(&self) -> bool { - true + fn peer(&mut self, i: usize) -> &mut Peer { + &mut self.peers[i] } - fn peer(&self, i: usize) -> &Peer { - &self.peers[i] - } - - fn peers(&self) -> &Vec>> { + fn peers(&self) -> &Vec> { &self.peers } - fn mut_peers>>)>(&mut self, closure: F) { + fn mut_peers>)>(&mut self, closure: F) { closure(&mut self.peers); } - - fn started(&self) -> bool { - self.started - } - - fn set_started(&mut self, new: bool) { - self.started = new; - } } #[test] #[allow(deprecated)] fn authoring_blocks() { let _ = ::env_logger::try_init(); - let mut net = AuraTestNet::new(3); - - net.start(); + let net = AuraTestNet::new(3); let peers = &[ (0, Keyring::Alice), @@ -848,6 +839,7 @@ mod tests { let environ = Arc::new(DummyFactory(client.clone())); import_notifications.push( client.import_notification_stream() + .map(|v| Ok::<_, ()>(v)).compat() .take_while(|n| Ok(!(n.origin != BlockOrigin::Own && n.header.number() < &5))) .for_each(move |_| Ok(())) ); @@ -880,15 +872,7 @@ mod tests { .map(|_| ()) .map_err(|_| ()); - let drive_to_completion = ::tokio_timer::Interval::new_interval(TEST_ROUTING_INTERVAL) - .for_each(move |_| { - net.lock().send_import_notifications(); - net.lock().sync_without_disconnects(); - Ok(()) - }) - .map(|_| ()) - .map_err(|_| ()); - + let drive_to_completion = futures::future::poll_fn(|| { net.lock().poll(); Ok(Async::NotReady) }); let _ = runtime.block_on(wait_for.select(drive_to_completion).map_err(|_| ())).unwrap(); } diff --git a/core/consensus/babe/Cargo.toml b/core/consensus/babe/Cargo.toml index a20b7de00149d17a636286903cb6677ba36b1601..29c706dd132c49b60d1b496012196a3e0d88afbd 100644 --- a/core/consensus/babe/Cargo.toml +++ b/core/consensus/babe/Cargo.toml @@ -6,8 +6,7 @@ description = "BABE consensus algorithm for substrate" edition = "2018" [dependencies] -parity-codec = "3.4.0" -parity-codec-derive = "3.3.0" +parity-codec = { version = "4.1.1", features = ["derive"] } babe_primitives = { package = "substrate-consensus-babe-primitives", path = "primitives" } primitives = { package = "substrate-primitives", path = "../../primitives" } runtime_support = { package = "srml-support", path = "../../../srml/support" } @@ -29,6 +28,7 @@ rand = "0.6.5" merlin = "1.0.3" [dev-dependencies] +futures03 = { package = "futures-preview", version = "0.3.0-alpha.17", features = ["compat"] } keyring = { package = "substrate-keyring", path = "../../keyring" } substrate-executor = { path = "../../executor" } network = { package = "substrate-network", path = "../../network", features = ["test-helpers"]} diff --git a/core/consensus/babe/primitives/Cargo.toml b/core/consensus/babe/primitives/Cargo.toml index fd45f6470a27e236aa95a33d6cf342d897d21647..a41fdeac5acf7bf7d82f26ee036862671bb3a0dc 100644 --- a/core/consensus/babe/primitives/Cargo.toml +++ b/core/consensus/babe/primitives/Cargo.toml @@ -11,7 +11,7 @@ rstd = { package = "sr-std", path = "../../../sr-std", default-features = false runtime_primitives = { package = "sr-primitives", path = "../../../sr-primitives", default-features = false } substrate-primitives = { path = "../../../primitives", default-features = false } slots = { package = "substrate-consensus-slots", path = "../../slots", optional = true } -parity-codec = { version = "3.5.1", default-features = false } +parity-codec = { version = "4.1.1", default-features = false } [features] default = ["std"] diff --git a/core/consensus/babe/primitives/src/lib.rs b/core/consensus/babe/primitives/src/lib.rs index cd056544e6a5b3214846258f5da7c12d054a5821..655751b7633b68b9f5ac0ad769e9be70f56a814a 100644 --- a/core/consensus/babe/primitives/src/lib.rs +++ b/core/consensus/babe/primitives/src/lib.rs @@ -31,6 +31,38 @@ pub type AuthorityId = Public; /// The `ConsensusEngineId` of BABE. pub const BABE_ENGINE_ID: ConsensusEngineId = *b"BABE"; +/// The length of the VRF output +pub const VRF_OUTPUT_LENGTH: usize = 32; + +/// The length of the VRF proof +pub const VRF_PROOF_LENGTH: usize = 64; + +/// The length of the public key +pub const PUBLIC_KEY_LENGTH: usize = 32; + +/// The index of an authority. +pub type AuthorityIndex = u64; + +/// A slot number. +pub type SlotNumber = u64; + +/// The weight of an authority. +pub type Weight = u64; + +/// An consensus log item for BABE. +#[derive(Decode, Encode)] +pub enum ConsensusLog { + /// The epoch has changed. This provides information about the + /// epoch _after_ next: what slot number it will start at, who are the authorities (and their weights) + /// and the next epoch randomness. The information for the _next_ epoch should already + /// be available. + #[codec(index = "1")] + NextEpochData(SlotNumber, Vec<(AuthorityId, Weight)>, [u8; VRF_OUTPUT_LENGTH]), + /// Disable the authority with given index. + #[codec(index = "2")] + OnDisabled(AuthorityIndex), +} + /// Configuration data used by the BABE consensus engine. #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Encode, Decode)] pub struct BabeConfiguration { @@ -51,6 +83,15 @@ pub struct BabeConfiguration { /// /// Dynamic thresholds may be supported in the future. pub threshold: u64, + + /// The minimum number of blocks that must be received before running the + /// median algorithm to compute the offset between the on-chain time and the + /// local time. Currently, only the value provided by this type at genesis + /// will be used, but this is subject to change. + /// + /// Blocks less than `self.median_required_blocks` must be generated by an + /// *initial validator* ― that is, a node that was a validator at genesis. + pub median_required_blocks: u64, } #[cfg(feature = "std")] diff --git a/core/consensus/babe/src/digest.rs b/core/consensus/babe/src/digest.rs index 7356001cf798843bd9216d36c0482038db68f7c2..37ba27a309eb28d4c62391453188d1b34a0046d2 100644 --- a/core/consensus/babe/src/digest.rs +++ b/core/consensus/babe/src/digest.rs @@ -14,17 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! Private mplementation details of BABE digests. +//! Private implementation details of BABE digests. -use primitives::sr25519::{Public, Signature}; -use babe_primitives::BABE_ENGINE_ID; +use primitives::sr25519::Signature; +use babe_primitives::{self, BABE_ENGINE_ID, SlotNumber}; use runtime_primitives::{DigestItem, generic::OpaqueDigestItemId}; use std::fmt::Debug; use parity_codec::{Decode, Encode, Codec, Input}; -use schnorrkel::{ - vrf::{VRFProof, VRFOutput, VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH}, - PUBLIC_KEY_LENGTH, -}; +use schnorrkel::{vrf::{VRFProof, VRFOutput, VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH}}; /// A BABE pre-digest. It includes: /// @@ -36,26 +33,26 @@ use schnorrkel::{ pub struct BabePreDigest { pub(super) vrf_output: VRFOutput, pub(super) proof: VRFProof, - pub(super) author: Public, - pub(super) slot_num: u64, + pub(super) index: babe_primitives::AuthorityIndex, + pub(super) slot_num: SlotNumber, } /// The prefix used by BABE for its VRF keys. pub const BABE_VRF_PREFIX: &'static [u8] = b"substrate-babe-vrf"; -type TmpDecode = ( +type RawBabePreDigest = ( [u8; VRF_OUTPUT_LENGTH], [u8; VRF_PROOF_LENGTH], - [u8; PUBLIC_KEY_LENGTH], + u64, u64, ); impl Encode for BabePreDigest { fn encode(&self) -> Vec { - let tmp: TmpDecode = ( + let tmp: RawBabePreDigest = ( *self.vrf_output.as_bytes(), self.proof.to_bytes(), - self.author.0, + self.index, self.slot_num, ); parity_codec::Encode::encode(&tmp) @@ -64,11 +61,15 @@ impl Encode for BabePreDigest { impl Decode for BabePreDigest { fn decode(i: &mut R) -> Option { - let (output, proof, public_key, slot_num): TmpDecode = Decode::decode(i)?; + let (output, proof, index, slot_num): RawBabePreDigest = Decode::decode(i)?; + + // Verify (at compile time) that the sizes in babe_primitives are correct + let _: [u8; babe_primitives::VRF_OUTPUT_LENGTH] = output; + let _: [u8; babe_primitives::VRF_PROOF_LENGTH] = proof; Some(BabePreDigest { proof: VRFProof::from_bytes(&proof).ok()?, vrf_output: VRFOutput::from_bytes(&output).ok()?, - author: Public(public_key), + index, slot_num, }) } diff --git a/core/consensus/babe/src/lib.rs b/core/consensus/babe/src/lib.rs index 3e1f38077f8d824e75b1d7a5b0ab58b9d6db3dcb..454b356f7c28245d84898ca01c6c95434fabc1cf 100644 --- a/core/consensus/babe/src/lib.rs +++ b/core/consensus/babe/src/lib.rs @@ -23,23 +23,28 @@ //! This crate is highly unstable and experimental. Breaking changes may //! happen at any point. This crate is also missing features, such as banning //! of malicious validators, that are essential for a production network. -#![forbid(unsafe_code, missing_docs)] +#![forbid(unsafe_code, missing_docs, unused_must_use)] +#![cfg_attr(not(test), forbid(dead_code))] extern crate core; mod digest; use digest::CompatibleDigestItem; pub use digest::{BabePreDigest, BABE_VRF_PREFIX}; pub use babe_primitives::*; pub use consensus_common::SyncOracle; +use consensus_common::import_queue::{ + BoxBlockImport, BoxJustificationImport, BoxFinalityProofImport, +}; use consensus_common::well_known_cache_keys::Id as CacheKeyId; use runtime_primitives::{generic, generic::{BlockId, OpaqueDigestItemId}, Justification}; use runtime_primitives::traits::{ Block, Header, DigestItemFor, ProvideRuntimeApi, - SimpleBitOps, + SimpleBitOps, Zero, }; -use std::{sync::Arc, u64, fmt::{Debug, Display}}; +use std::{sync::Arc, u64, fmt::{Debug, Display}, time::{Instant, Duration}}; use runtime_support::serde::{Serialize, Deserialize}; use parity_codec::{Decode, Encode}; -use primitives::{crypto::Pair, sr25519}; +use parking_lot::Mutex; +use primitives::{Pair, Public, sr25519}; use merlin::Transcript; use inherents::{InherentDataProviders, InherentData}; use substrate_telemetry::{ @@ -77,7 +82,7 @@ use futures::{Future, IntoFuture, future}; use tokio_timer::Timeout; use log::{error, warn, debug, info, trace}; -use slots::{SlotWorker, SlotData, SlotInfo, SlotCompatible, slot_now}; +use slots::{SlotWorker, SlotData, SlotInfo, SlotCompatible, SignedDuration}; pub use babe_primitives::AuthorityId; @@ -92,7 +97,7 @@ impl Config { /// state. pub fn get_or_compute(client: &C) -> CResult where - C: AuxStore, C: ProvideRuntimeApi, C::Api: BabeApi, + C: AuxStore + ProvideRuntimeApi, C::Api: BabeApi, { trace!(target: "babe", "Getting slot duration"); match slots::SlotDuration::get_or_compute(client, |a, b| a.startup_data(b)).map(Self) { @@ -115,17 +120,17 @@ impl Config { } } -struct BabeSlotCompatible; - -impl SlotCompatible for BabeSlotCompatible { +impl SlotCompatible for BabeLink { fn extract_timestamp_and_slot( - data: &InherentData - ) -> Result<(TimestampInherent, u64), consensus_common::Error> { + &self, + data: &InherentData, + ) -> Result<(TimestampInherent, u64, std::time::Duration), consensus_common::Error> { trace!(target: "babe", "extract timestamp"); data.timestamp_inherent_data() .and_then(|t| data.babe_inherent_data().map(|a| (t, a))) .map_err(Into::into) .map_err(consensus_common::Error::InherentData) + .map(|(x, y)| (x, y, self.0.lock().0.take().unwrap_or_default())) } } @@ -146,7 +151,7 @@ pub struct BabeParams { pub select_chain: SC, /// A block importer - pub block_import: Arc, + pub block_import: I, /// The environment pub env: Arc, @@ -159,6 +164,9 @@ pub struct BabeParams { /// Force authoring of blocks even if we are offline pub force_authoring: bool, + + /// The source of timestamps for relative slots + pub time_source: BabeLink, } /// Start the babe worker. The returned future should be run in a tokio runtime. @@ -172,6 +180,7 @@ pub fn start_babe(BabeParams { sync_oracle, inherent_data_providers, force_authoring, + time_source, }: BabeParams) -> Result< impl Future, consensus_common::Error, @@ -190,7 +199,7 @@ pub fn start_babe(BabeParams { { let worker = BabeWorker { client: client.clone(), - block_import, + block_import: Arc::new(Mutex::new(block_import)), env, local_key, sync_oracle: sync_oracle.clone(), @@ -198,18 +207,19 @@ pub fn start_babe(BabeParams { threshold: config.threshold(), }; register_babe_inherent_data_provider(&inherent_data_providers, config.0.slot_duration())?; - Ok(slots::start_slot_worker::<_, _, _, _, _, BabeSlotCompatible>( + Ok(slots::start_slot_worker::<_, _, _, _, _, _>( config.0, select_chain, worker, sync_oracle, - inherent_data_providers + inherent_data_providers, + time_source, )) } struct BabeWorker { client: Arc, - block_import: Arc, + block_import: Arc>, env: Arc, local_key: Arc, sync_oracle: SO, @@ -274,7 +284,7 @@ impl SlotWorker for BabeWorker w // FIXME replace the dummy empty slices with real data // https://github.com/paritytech/substrate/issues/2435 // https://github.com/paritytech/substrate/issues/2436 - let proposal_work = if let Some((inout, proof, _batchable_proof)) = claim_slot( + let proposal_work = if let Some(((inout, proof, _batchable_proof), index)) = claim_slot( &[0u8; 0], slot_info.number, &[0u8; 0], @@ -307,7 +317,7 @@ impl SlotWorker for BabeWorker w let inherent_digest = BabePreDigest { proof, vrf_output: inout.to_output(), - author: pair.public(), + index: index as u64, slot_num, }; @@ -332,8 +342,8 @@ impl SlotWorker for BabeWorker w Box::new(proposal_work.map(move |b| { // minor hack since we don't have access to the timestamp // that is actually set by the proposer. - let slot_after_building = slot_now(slot_duration); - if slot_after_building != Some(slot_num) { + let slot_after_building = SignedDuration::default().slot_now(slot_duration); + if slot_after_building != slot_num { info!( target: "babe", "Discarding proposal for slot {}; block production took too long", @@ -386,7 +396,7 @@ impl SlotWorker for BabeWorker w "hash_previously" => ?header_hash, ); - if let Err(e) = block_import.import_block(import_block, Default::default()) { + if let Err(e) = block_import.lock().import_block(import_block, Default::default()) { warn!(target: "babe", "Error with block built on {:?}: {:?}", parent_hash, e); telemetry!(CONSENSUS_WARN; "babe.err_with_block_built_on"; @@ -454,17 +464,17 @@ fn check_header( })?; let pre_digest = find_pre_digest::(&header)?; - let BabePreDigest { slot_num, ref author, ref proof, ref vrf_output } = pre_digest; + let BabePreDigest { slot_num, index, ref proof, ref vrf_output } = pre_digest; if slot_num > slot_now { header.digest_mut().push(seal); Ok(CheckedHeader::Deferred(header, slot_num)) - } else if !authorities.contains(&author) { + } else if index > authorities.len() as u64 { Err(babe_err!("Slot author not found")) } else { - let pre_hash = header.hash(); + let (pre_hash, author): (_, &sr25519::Public) = (header.hash(), &authorities[index as usize]); - if sr25519::Pair::verify(&sig, pre_hash, author) { + if sr25519::Pair::verify(&sig, pre_hash, author.clone()) { let (inout, _batchable_proof) = { let transcript = make_transcript( Default::default(), @@ -508,11 +518,16 @@ fn check_header( } } +/// State that must be shared between the import queue and the authoring logic. +#[derive(Default, Clone, Debug)] +pub struct BabeLink(Arc, Vec<(Instant, u64)>)>>); + /// A verifier for Babe blocks. pub struct BabeVerifier { client: Arc, inherent_data_providers: inherents::InherentDataProviders, - threshold: u64, + config: Config, + time_source: BabeLink, } impl BabeVerifier { @@ -540,6 +555,38 @@ impl BabeVerifier { } } +fn median_algorithm( + median_required_blocks: u64, + slot_duration: u64, + slot_num: u64, + slot_now: u64, + time_source: &mut (Option, Vec<(Instant, u64)>), +) { + let num_timestamps = time_source.1.len(); + if num_timestamps as u64 >= median_required_blocks && median_required_blocks > 0 { + let mut new_list: Vec<_> = time_source.1.iter().map(|&(t, sl)| { + let offset: u128 = u128::from(slot_duration) + .checked_mul(1_000_000u128) // self.config.get() returns *milliseconds* + .and_then(|x| x.checked_mul(u128::from(slot_num).saturating_sub(u128::from(sl)))) + .expect("we cannot have timespans long enough for this to overflow; qed"); + const NANOS_PER_SEC: u32 = 1_000_000_000; + let nanos = (offset % u128::from(NANOS_PER_SEC)) as u32; + let secs = (offset / u128::from(NANOS_PER_SEC)) as u64; + t + Duration::new(secs, nanos) + }).collect(); + // FIXME #2926: use a selection algorithm instead of a full sorting algorithm. + new_list.sort_unstable(); + let &median = new_list + .get(num_timestamps / 2) + .expect("we have at least one timestamp, so this is a valid index; qed"); + time_source.1.clear(); + // FIXME #2927: pass this to the block authoring logic somehow + time_source.0.replace(Instant::now() - median); + } else { + time_source.1.push((Instant::now(), slot_now)) + } +} + impl Verifier for BabeVerifier where C: ProvideRuntimeApi + Send + Sync + AuxStore + ProvideCache, C::Api: BlockBuilderApi + BabeApi, @@ -566,7 +613,7 @@ impl Verifier for BabeVerifier where .inherent_data_providers .create_inherent_data() .map_err(String::from)?; - let (_, slot_now) = BabeSlotCompatible::extract_timestamp_and_slot(&inherent_data) + let (_, slot_now, _) = self.time_source.extract_timestamp_and_slot(&inherent_data) .map_err(|e| format!("Could not extract timestamp and slot: {:?}", e))?; let hash = header.hash(); let parent_hash = *header.parent_hash(); @@ -582,7 +629,7 @@ impl Verifier for BabeVerifier where header, hash, &authorities[..], - self.threshold, + self.config.threshold(), )?; match checked_header { CheckedHeader::Checked(pre_header, (pre_digest, seal)) => { @@ -629,7 +676,13 @@ impl Verifier for BabeVerifier where auxiliary: Vec::new(), fork_choice: ForkChoiceStrategy::LongestChain, }; - + median_algorithm( + self.config.0.median_required_blocks, + self.config.get(), + slot_num, + slot_now, + &mut *self.time_source.0.lock(), + ); // FIXME #1019 extract authorities Ok((import_block, maybe_keys)) } @@ -721,8 +774,9 @@ fn claim_slot( authorities: &[AuthorityId], key: &sr25519::Pair, threshold: u64, -) -> Option<(VRFInOut, VRFProof, VRFProofBatchable)> { - if !authorities.contains(&key.public()) { return None } +) -> Option<((VRFInOut, VRFProof, VRFProofBatchable), usize)> { + let public = &key.public(); + let index = authorities.iter().position(|s| s == public)?; let transcript = make_transcript( randomness, slot_number, @@ -736,14 +790,79 @@ fn claim_slot( // be empty. Therefore, this division is safe. let threshold = threshold / authorities.len() as u64; - get_keypair(key).vrf_sign_n_check(transcript, |inout| check(inout, threshold)) + get_keypair(key) + .vrf_sign_n_check(transcript, |inout| check(inout, threshold)) + .map(|s|(s, index)) +} + +fn initialize_authorities_cache(client: &C) -> Result<(), ConsensusError> where + B: Block, + C: ProvideRuntimeApi + ProvideCache, + C::Api: BabeApi, +{ + // no cache => no initialization + let cache = match client.cache() { + Some(cache) => cache, + None => return Ok(()), + }; + + // check if we already have initialized the cache + let genesis_id = BlockId::Number(Zero::zero()); + let genesis_authorities: Option> = cache + .get_at(&well_known_cache_keys::AUTHORITIES, &genesis_id) + .and_then(|v| Decode::decode(&mut &v[..])); + if genesis_authorities.is_some() { + return Ok(()); + } + + let map_err = |error| consensus_common::Error::from(consensus_common::Error::ClientImport( + format!( + "Error initializing authorities cache: {}", + error, + ))); + let genesis_authorities = authorities(client, &genesis_id)?; + cache.initialize(&well_known_cache_keys::AUTHORITIES, genesis_authorities.encode()) + .map_err(map_err) +} + +/// Start an import queue for the Babe consensus algorithm. +pub fn import_queue( + config: Config, + block_import: BoxBlockImport, + justification_import: Option>, + finality_proof_import: Option>, + client: Arc, + inherent_data_providers: InherentDataProviders, +) -> Result<(BabeImportQueue, BabeLink), consensus_common::Error> where + B: Block, + C: 'static + ProvideRuntimeApi + ProvideCache + Send + Sync + AuxStore, + C::Api: BlockBuilderApi + BabeApi, + DigestItemFor: CompatibleDigestItem, + E: 'static, +{ + register_babe_inherent_data_provider(&inherent_data_providers, config.get())?; + initialize_authorities_cache(&*client)?; + + let verifier = BabeVerifier { + client: client, + inherent_data_providers, + time_source: Default::default(), + config, + }; + let timestamp_core = verifier.time_source.clone(); + Ok((BasicQueue::new( + Arc::new(verifier), + block_import, + justification_import, + finality_proof_import, + ), timestamp_core)) } -#[cfg(test)] -#[allow(dead_code, unused_imports, deprecated)] // FIXME #2532: need to allow deprecated until refactor is done // https://github.com/paritytech/substrate/issues/2532 - +#[cfg(test)] +#[allow(unused_imports, deprecated)] +#[cfg_attr(test, allow(dead_code))] mod tests { use super::*; @@ -753,13 +872,13 @@ mod tests { use network::test::{Block as TestBlock, PeersClient}; use runtime_primitives::traits::{Block as BlockT, DigestFor}; use network::config::ProtocolConfig; - use parking_lot::Mutex; use tokio::runtime::current_thread; use keyring::sr25519::Keyring; use super::generic::DigestItem; use client::BlockchainEvents; use test_client; - use futures::stream::Stream; + use futures::{Async, stream::Stream as _}; + use futures03::{StreamExt as _, TryStreamExt as _}; use log::debug; use std::time::Duration; type Item = generic::DigestItem; @@ -798,11 +917,9 @@ mod tests { } const SLOT_DURATION: u64 = 1; - const TEST_ROUTING_INTERVAL: Duration = Duration::from_millis(50); pub struct BabeTestNet { - peers: Vec>>, - started: bool, + peers: Vec>, } impl TestNetFactory for BabeTestNet { @@ -815,7 +932,6 @@ mod tests { debug!(target: "babe", "Creating test network from config"); BabeTestNet { peers: Vec::new(), - started: false, } } @@ -837,38 +953,27 @@ mod tests { Arc::new(BabeVerifier { client, inherent_data_providers, - threshold: config.threshold(), + config, + time_source: Default::default(), }) } - fn uses_tokio(&self) -> bool { - true - } - - fn peer(&self, i: usize) -> &Peer { + fn peer(&mut self, i: usize) -> &mut Peer { trace!(target: "babe", "Retreiving a peer"); - &self.peers[i] + &mut self.peers[i] } - fn peers(&self) -> &Vec>> { + fn peers(&self) -> &Vec> { trace!(target: "babe", "Retreiving peers"); &self.peers } - fn mut_peers>>)>( + fn mut_peers>)>( &mut self, closure: F, ) { closure(&mut self.peers); } - - fn started(&self) -> bool { - self.started - } - - fn set_started(&mut self, new: bool) { - self.started = new; - } } #[test] @@ -881,10 +986,9 @@ mod tests { fn authoring_blocks() { drop(env_logger::try_init()); debug!(target: "babe", "checkpoint 1"); - let mut net = BabeTestNet::new(3); + let net = BabeTestNet::new(3); debug!(target: "babe", "checkpoint 2"); - net.start(); debug!(target: "babe", "checkpoint 3"); let peers = &[ @@ -902,6 +1006,7 @@ mod tests { let environ = Arc::new(DummyFactory(client.clone())); import_notifications.push( client.import_notification_stream() + .map(|v| Ok::<_, ()>(v)).compat() .take_while(|n| Ok(!(n.origin != BlockOrigin::Own && n.header.number() < &5))) .for_each(move |_| Ok(())) ); @@ -918,7 +1023,7 @@ mod tests { #[allow(deprecated)] let select_chain = LongestChain::new(client.backend().clone()); - let babe = start_babe(BabeParams { + runtime.spawn(start_babe(BabeParams { config, local_key: Arc::new(key.clone().into()), block_import: client.clone(), @@ -928,9 +1033,8 @@ mod tests { sync_oracle: DummyOracle, inherent_data_providers, force_authoring: false, - }).expect("Starts babe"); - - runtime.spawn(babe); + time_source: Default::default(), + }).expect("Starts babe")); } debug!(target: "babe", "checkpoint 5"); @@ -939,15 +1043,7 @@ mod tests { .map(drop) .map_err(drop); - let drive_to_completion = ::tokio_timer::Interval::new_interval(TEST_ROUTING_INTERVAL) - .for_each(move |_| { - net.lock().send_import_notifications(); - net.lock().sync_without_disconnects(); - Ok(()) - }) - .map(drop) - .map_err(drop); - + let drive_to_completion = futures::future::poll_fn(|| { net.lock().poll(); Ok(Async::NotReady) }); let _ = runtime.block_on(wait_for.select(drive_to_completion).map_err(drop)).unwrap(); } diff --git a/core/consensus/common/Cargo.toml b/core/consensus/common/Cargo.toml index 2852f4aa0fe8e22092814049eb652d8475f2ddd3..c6da0c682e705c072c1f0b200ecb27ddf14a6ab5 100644 --- a/core/consensus/common/Cargo.toml +++ b/core/consensus/common/Cargo.toml @@ -7,8 +7,7 @@ edition = "2018" [dependencies] derive_more = "0.14.0" -crossbeam-channel = "0.3.4" -libp2p = { version = "0.9.0", default-features = false } +libp2p = { version = "0.10.0", default-features = false } log = "0.4" primitives = { package = "substrate-primitives", path= "../../primitives" } inherents = { package = "substrate-inherents", path = "../../inherents" } @@ -16,8 +15,9 @@ futures = "0.1" rstd = { package = "sr-std", path = "../../sr-std" } runtime_version = { package = "sr-version", path = "../../sr-version" } runtime_primitives = { package = "sr-primitives", path = "../../sr-primitives" } +tokio-executor = "0.1.6" tokio-timer = "0.2" -parity-codec = { version = "3.3", features = ["derive"] } +parity-codec = { version = "4.1.1", features = ["derive"] } parking_lot = "0.8.0" [dev-dependencies] @@ -25,4 +25,3 @@ test-client = { package = "substrate-test-runtime-client", path = "../../test-ru [features] default = [] -test-helpers = [] diff --git a/core/consensus/common/src/block_import.rs b/core/consensus/common/src/block_import.rs index 6ce4acdf3941a64e1155af82c5ac3ea9927563a5..8afdd31b3f538a4a1c6a997cfa05cae133aad243 100644 --- a/core/consensus/common/src/block_import.rs +++ b/core/consensus/common/src/block_import.rs @@ -20,6 +20,7 @@ use runtime_primitives::traits::{Block as BlockT, DigestItemFor, Header as Heade use runtime_primitives::Justification; use std::borrow::Cow; use std::collections::HashMap; +use std::sync::Arc; use crate::well_known_cache_keys; use crate::import_queue::Verifier; @@ -175,7 +176,7 @@ pub trait BlockImport { /// Check block preconditions. fn check_block( - &self, + &mut self, hash: B::Hash, parent_hash: B::Hash, ) -> Result; @@ -184,22 +185,45 @@ pub trait BlockImport { /// /// Cached data can be accessed through the blockchain cache. fn import_block( - &self, + &mut self, block: ImportBlock, cache: HashMap>, ) -> Result; } +impl BlockImport for Arc +where for<'r> &'r T: BlockImport +{ + type Error = E; + + fn check_block( + &mut self, + hash: B::Hash, + parent_hash: B::Hash, + ) -> Result { + (&**self).check_block(hash, parent_hash) + } + + fn import_block( + &mut self, + block: ImportBlock, + cache: HashMap>, + ) -> Result { + (&**self).import_block(block, cache) + } +} + /// Justification import trait pub trait JustificationImport { type Error: ::std::error::Error + Send + 'static; - /// Called by the import queue when it is started. - fn on_start(&self, _link: &mut dyn crate::import_queue::Link) { } + /// Called by the import queue when it is started. Returns a list of justifications to request + /// from the network. + fn on_start(&mut self) -> Vec<(B::Hash, NumberFor)> { Vec::new() } /// Import a Block justification and finalize the given block. fn import_justification( - &self, + &mut self, hash: B::Hash, number: NumberFor, justification: Justification, @@ -210,21 +234,16 @@ pub trait JustificationImport { pub trait FinalityProofImport { type Error: std::error::Error + Send + 'static; - /// Called by the import queue when it is started. - fn on_start(&self, _link: &mut dyn crate::import_queue::Link) { } + /// Called by the import queue when it is started. Returns a list of finality proofs to request + /// from the network. + fn on_start(&mut self) -> Vec<(B::Hash, NumberFor)> { Vec::new() } /// Import a Block justification and finalize the given block. Returns finalized block or error. fn import_finality_proof( - &self, + &mut self, hash: B::Hash, number: NumberFor, finality_proof: Vec, verifier: &dyn Verifier, ) -> Result<(B::Hash, NumberFor), Self::Error>; } - -/// Finality proof request builder. -pub trait FinalityProofRequestBuilder: Send { - /// Build data blob, associated with the request. - fn build_request_data(&self, hash: &B::Hash) -> Vec; -} diff --git a/core/consensus/common/src/import_queue.rs b/core/consensus/common/src/import_queue.rs index 1753d63ff0c0b78bcd0be0bbc6a2309a1ddfa949..f8041ae99bf94ad981d9e7addf3b12416e6cdfa6 100644 --- a/core/consensus/common/src/import_queue.rs +++ b/core/consensus/common/src/import_queue.rs @@ -25,37 +25,27 @@ //! instantiated. The `BasicQueue` and `BasicVerifier` traits allow serial //! queues to be instantiated simply. -use std::{sync::Arc, thread, collections::HashMap}; -use crossbeam_channel::{self as channel, Sender}; -use futures::{prelude::*, sync::mpsc}; -use runtime_primitives::{Justification, traits::{ - Block as BlockT, Header as HeaderT, NumberFor, -}}; -use crate::{error::Error as ConsensusError, well_known_cache_keys::Id as CacheKeyId, block_import::{ - BlockImport, BlockOrigin, ImportBlock, ImportedAux, ImportResult, JustificationImport, - FinalityProofImport, FinalityProofRequestBuilder, -}}; +use std::{sync::Arc, collections::HashMap}; +use runtime_primitives::{Justification, traits::{Block as BlockT, Header as _, NumberFor}}; +use crate::{error::Error as ConsensusError, well_known_cache_keys::Id as CacheKeyId}; +use crate::block_import::{ + BlockImport, BlockOrigin, ImportBlock, ImportedAux, JustificationImport, ImportResult, + FinalityProofImport, +}; -/// Reputation change for peers which send us a block with an incomplete header. -const INCOMPLETE_HEADER_REPUTATION_CHANGE: i32 = -(1 << 20); -/// Reputation change for peers which send us a block which we fail to verify. -const VERIFICATION_FAIL_REPUTATION_CHANGE: i32 = -(1 << 20); -/// Reputation change for peers which send us a bad block. -const BAD_BLOCK_REPUTATION_CHANGE: i32 = -(1 << 29); -/// Reputation change for peers which send us a block with bad justifications. -const BAD_JUSTIFICATION_REPUTATION_CHANGE: i32 = -(1 << 16); +pub use basic_queue::BasicQueue; + +mod basic_queue; +pub mod buffered_link; /// Shared block import struct used by the queue. -pub type SharedBlockImport = Arc + Send + Sync>; +pub type BoxBlockImport = Box + Send + Sync>; /// Shared justification import struct used by the queue. -pub type SharedJustificationImport = Arc + Send + Sync>; +pub type BoxJustificationImport = Box + Send + Sync>; /// Shared finality proof import struct used by the queue. -pub type SharedFinalityProofImport = Arc + Send + Sync>; - -/// Shared finality proof request builder struct used by the queue. -pub type SharedFinalityProofRequestBuilder = Arc + Send + Sync>; +pub type BoxFinalityProofImport = Box + Send + Sync>; /// Maps to the Origin used by the network. pub type Origin = libp2p::PeerId; @@ -120,320 +110,18 @@ pub trait ImportQueue: Send { fn poll_actions(&mut self, link: &mut dyn Link); } -/// Interface to a basic block import queue that is importing blocks sequentially in a separate -/// thread, with pluggable verification. -pub struct BasicQueue { - /// Channel to send messages to the background thread. - sender: Option>>, - /// Results coming from the worker thread. - result_port: BufferedLinkReceiver, - /// Sent through the link as soon as possible. - finality_proof_request_builder: Option>, -} - -impl Drop for BasicQueue { - fn drop(&mut self) { - if let Some(sender) = self.sender.take() { - let (shutdown_sender, shutdown_receiver) = channel::unbounded(); - if sender.send(ToWorkerMsg::Shutdown(shutdown_sender)).is_ok() { - let _ = shutdown_receiver.recv(); - } - } - } -} - -impl BasicQueue { - /// Instantiate a new basic queue, with given verifier. - /// - /// This creates a background thread, and calls `on_start` on the justification importer and - /// finality proof importer. - pub fn new>( - verifier: Arc, - block_import: SharedBlockImport, - justification_import: Option>, - finality_proof_import: Option>, - finality_proof_request_builder: Option>, - ) -> Self { - let (result_sender, result_port) = buffered_link(); - let worker_sender = BlockImportWorker::new( - result_sender, - verifier, - block_import, - justification_import, - finality_proof_import, - ); - - Self { - sender: Some(worker_sender), - result_port, - finality_proof_request_builder, - } - } - - /// Send synchronization request to the block import channel. - /// - /// The caller should wait for Link::synchronized() call to ensure that it - /// has synchronized with ImportQueue. - #[cfg(any(test, feature = "test-helpers"))] - pub fn synchronize(&self) { - if let Some(ref sender) = self.sender { - let _ = sender.send(ToWorkerMsg::Synchronize); - } - } -} - -impl ImportQueue for BasicQueue { - fn import_blocks(&mut self, origin: BlockOrigin, blocks: Vec>) { - if blocks.is_empty() { - return; - } - - if let Some(ref sender) = self.sender { - trace!(target: "sync", "Scheduling {} blocks for import", blocks.len()); - let _ = sender.send(ToWorkerMsg::ImportBlocks(origin, blocks)); - } - } - - fn import_justification( - &mut self, - who: Origin, - hash: B::Hash, - number: NumberFor, - justification: Justification - ) { - if let Some(ref sender) = self.sender { - let _ = sender.send(ToWorkerMsg::ImportJustification(who.clone(), hash, number, justification)); - } - } - - fn import_finality_proof(&mut self, who: Origin, hash: B::Hash, number: NumberFor, finality_proof: Vec) { - if let Some(ref sender) = self.sender { - trace!(target: "sync", "Scheduling finality proof of {}/{} for import", number, hash); - let _ = sender.send(ToWorkerMsg::ImportFinalityProof(who, hash, number, finality_proof)); - } - } - - fn poll_actions(&mut self, link: &mut dyn Link) { - if let Some(fprb) = self.finality_proof_request_builder.take() { - link.set_finality_proof_request_builder(fprb); - } - - self.result_port.poll_actions(link); - } -} - -/// Message destinated to the background worker. -#[derive(Debug)] -enum ToWorkerMsg { - ImportBlocks(BlockOrigin, Vec>), - ImportJustification(Origin, B::Hash, NumberFor, Justification), - ImportFinalityProof(Origin, B::Hash, NumberFor, Vec), - Shutdown(Sender<()>), - #[cfg(any(test, feature = "test-helpers"))] - Synchronize, -} - -struct BlockImportWorker> { - result_sender: BufferedLinkSender, - block_import: SharedBlockImport, - justification_import: Option>, - finality_proof_import: Option>, - verifier: Arc, -} - -impl> BlockImportWorker { - fn new( - result_sender: BufferedLinkSender, - verifier: Arc, - block_import: SharedBlockImport, - justification_import: Option>, - finality_proof_import: Option>, - ) -> Sender> { - let (sender, port) = channel::bounded(4); - let _ = thread::Builder::new() - .name("ImportQueueWorker".into()) - .spawn(move || { - let mut worker = BlockImportWorker { - result_sender, - verifier, - justification_import, - block_import, - finality_proof_import, - }; - if let Some(justification_import) = worker.justification_import.as_ref() { - justification_import.on_start(&mut worker.result_sender); - } - if let Some(finality_proof_import) = worker.finality_proof_import.as_ref() { - finality_proof_import.on_start(&mut worker.result_sender); - } - for msg in port.iter() { - // Working until all senders have been dropped... - match msg { - ToWorkerMsg::ImportBlocks(origin, blocks) => { - worker.import_a_batch_of_blocks(origin, blocks); - }, - ToWorkerMsg::ImportFinalityProof(who, hash, number, proof) => { - worker.import_finality_proof(who, hash, number, proof); - }, - ToWorkerMsg::ImportJustification(who, hash, number, justification) => { - worker.import_justification(who, hash, number, justification); - } - ToWorkerMsg::Shutdown(result_sender) => { - let _ = result_sender.send(()); - break; - }, - #[cfg(any(test, feature = "test-helpers"))] - ToWorkerMsg::Synchronize => { - trace!(target: "sync", "Sending sync message"); - worker.result_sender.synchronized(); - }, - } - } - }) - .expect("ImportQueueWorker thread spawning failed"); - sender - } - - fn import_a_batch_of_blocks(&mut self, origin: BlockOrigin, blocks: Vec>) { - let (imported, count, results) = import_many_blocks( - &*self.block_import, - origin, - blocks, - self.verifier.clone(), - ); - - trace!(target: "sync", "Imported {} of {}", imported, count); - - let mut has_error = false; - let mut hashes = vec![]; - for (result, hash) in results { - hashes.push(hash); - - if has_error { - continue; - } - - if result.is_err() { - has_error = true; - } - - match result { - Ok(BlockImportResult::ImportedKnown(number)) => self.result_sender.block_imported(&hash, number), - Ok(BlockImportResult::ImportedUnknown(number, aux, who)) => { - self.result_sender.block_imported(&hash, number); - - if aux.clear_justification_requests { - trace!( - target: "sync", - "Block imported clears all pending justification requests {}: {:?}", - number, - hash - ); - self.result_sender.clear_justification_requests(); - } - - if aux.needs_justification { - trace!(target: "sync", "Block imported but requires justification {}: {:?}", number, hash); - self.result_sender.request_justification(&hash, number); - } - - if aux.bad_justification { - if let Some(peer) = who { - info!("Sent block with bad justification to import"); - self.result_sender.report_peer(peer, BAD_JUSTIFICATION_REPUTATION_CHANGE); - } - } - - if aux.needs_finality_proof { - trace!(target: "sync", "Block imported but requires finality proof {}: {:?}", number, hash); - self.result_sender.request_finality_proof(&hash, number); - } - }, - Err(BlockImportError::IncompleteHeader(who)) => { - if let Some(peer) = who { - info!("Peer sent block with incomplete header to import"); - self.result_sender.report_peer(peer, INCOMPLETE_HEADER_REPUTATION_CHANGE); - self.result_sender.restart(); - } - }, - Err(BlockImportError::VerificationFailed(who, e)) => { - if let Some(peer) = who { - info!("Verification failed from peer: {}", e); - self.result_sender.report_peer(peer, VERIFICATION_FAIL_REPUTATION_CHANGE); - self.result_sender.restart(); - } - }, - Err(BlockImportError::BadBlock(who)) => { - if let Some(peer) = who { - info!("Bad block"); - self.result_sender.report_peer(peer, BAD_BLOCK_REPUTATION_CHANGE); - self.result_sender.restart(); - } - }, - Err(BlockImportError::UnknownParent) | Err(BlockImportError::Error) => { - self.result_sender.restart(); - }, - }; - } - - self.result_sender.blocks_processed(hashes, has_error); - } - - fn import_finality_proof(&mut self, who: Origin, hash: B::Hash, number: NumberFor, finality_proof: Vec) { - let result = self.finality_proof_import.as_ref().map(|finality_proof_import| { - finality_proof_import.import_finality_proof(hash, number, finality_proof, &*self.verifier) - .map_err(|e| { - debug!( - "Finality proof import failed with {:?} for hash: {:?} number: {:?} coming from node: {:?}", - e, - hash, - number, - who, - ); - }) - }).unwrap_or(Err(())); - - trace!(target: "sync", "Imported finality proof for {}/{}", number, hash); - self.result_sender.finality_proof_imported(who, (hash, number), result); - } - - fn import_justification( - &mut self, - who: Origin, - hash: B::Hash, - number: NumberFor, - justification: Justification - ) { - let success = self.justification_import.as_ref().map(|justification_import| { - justification_import.import_justification(hash, number, justification) - .map_err(|e| { - debug!( - target: "sync", - "Justification import failed with {:?} for hash: {:?} number: {:?} coming from node: {:?}", - e, - hash, - number, - who, - ); - e - }).is_ok() - }).unwrap_or(false); - - self.result_sender.justification_imported(who, &hash, number, success); - } -} - /// Hooks that the verification queue can use to influence the synchronization /// algorithm. pub trait Link: Send { - /// Block imported. - fn block_imported(&mut self, _hash: &B::Hash, _number: NumberFor) {} /// Batch of blocks imported, with or without error. - fn blocks_processed(&mut self, _processed_blocks: Vec, _has_error: bool) {} + fn blocks_processed( + &mut self, + _imported: usize, + _count: usize, + _results: Vec<(Result>, BlockImportError>, B::Hash)> + ) {} /// Justification import result. fn justification_imported(&mut self, _who: Origin, _hash: &B::Hash, _number: NumberFor, _success: bool) {} - /// Clear all pending justification requests. - fn clear_justification_requests(&mut self) {} /// Request a justification for the given block. fn request_justification(&mut self, _hash: &B::Hash, _number: NumberFor) {} /// Finality proof import result. @@ -449,155 +137,6 @@ pub trait Link: Send { ) {} /// Request a finality proof for the given block. fn request_finality_proof(&mut self, _hash: &B::Hash, _number: NumberFor) {} - /// Remember finality proof request builder on start. - fn set_finality_proof_request_builder(&mut self, _request_builder: SharedFinalityProofRequestBuilder) {} - /// Adjusts the reputation of the given peer. - fn report_peer(&mut self, _who: Origin, _reputation_change: i32) {} - /// Restart sync. - fn restart(&mut self) {} - /// Synchronization request has been processed. - #[cfg(any(test, feature = "test-helpers"))] - fn synchronized(&mut self) {} -} - -/// Wraps around an unbounded channel from the `futures` crate. The sender implements `Link` and -/// can be used to buffer commands, and the receiver can be used to poll said commands and transfer -/// them to another link. -pub fn buffered_link() -> (BufferedLinkSender, BufferedLinkReceiver) { - let (tx, rx) = mpsc::unbounded(); - let tx = BufferedLinkSender { tx }; - let rx = BufferedLinkReceiver { rx }; - (tx, rx) -} - -/// See [`buffered_link`]. -pub struct BufferedLinkSender { - tx: mpsc::UnboundedSender>, -} - -/// Internal buffered message. -enum BlockImportWorkerMsg { - BlockImported(B::Hash, NumberFor), - BlocksProcessed(Vec, bool), - JustificationImported(Origin, B::Hash, NumberFor, bool), - ClearJustificationRequests, - RequestJustification(B::Hash, NumberFor), - FinalityProofImported(Origin, (B::Hash, NumberFor), Result<(B::Hash, NumberFor), ()>), - RequestFinalityProof(B::Hash, NumberFor), - SetFinalityProofRequestBuilder(SharedFinalityProofRequestBuilder), - ReportPeer(Origin, i32), - Restart, - #[cfg(any(test, feature = "test-helpers"))] - Synchronized, -} - -impl Link for BufferedLinkSender { - fn block_imported(&mut self, hash: &B::Hash, number: NumberFor) { - let _ = self.tx.unbounded_send(BlockImportWorkerMsg::BlockImported(hash.clone(), number)); - } - - fn blocks_processed(&mut self, processed_blocks: Vec, has_error: bool) { - let _ = self.tx.unbounded_send(BlockImportWorkerMsg::BlocksProcessed(processed_blocks, has_error)); - } - - fn justification_imported( - &mut self, - who: Origin, - hash: &B::Hash, - number: NumberFor, - success: bool - ) { - let msg = BlockImportWorkerMsg::JustificationImported(who, hash.clone(), number, success); - let _ = self.tx.unbounded_send(msg); - } - - fn clear_justification_requests(&mut self) { - let _ = self.tx.unbounded_send(BlockImportWorkerMsg::ClearJustificationRequests); - } - - fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { - let _ = self.tx.unbounded_send(BlockImportWorkerMsg::RequestJustification(hash.clone(), number)); - } - - fn finality_proof_imported( - &mut self, - who: Origin, - request_block: (B::Hash, NumberFor), - finalization_result: Result<(B::Hash, NumberFor), ()>, - ) { - let msg = BlockImportWorkerMsg::FinalityProofImported(who, request_block, finalization_result); - let _ = self.tx.unbounded_send(msg); - } - - fn request_finality_proof(&mut self, hash: &B::Hash, number: NumberFor) { - let _ = self.tx.unbounded_send(BlockImportWorkerMsg::RequestFinalityProof(hash.clone(), number)); - } - - fn set_finality_proof_request_builder(&mut self, request_builder: SharedFinalityProofRequestBuilder) { - let _ = self.tx.unbounded_send(BlockImportWorkerMsg::SetFinalityProofRequestBuilder(request_builder)); - } - - fn report_peer(&mut self, who: Origin, reputation_change: i32) { - let _ = self.tx.unbounded_send(BlockImportWorkerMsg::ReportPeer(who, reputation_change)); - } - - fn restart(&mut self) { - let _ = self.tx.unbounded_send(BlockImportWorkerMsg::Restart); - } - - #[cfg(any(test, feature = "test-helpers"))] - fn synchronized(&mut self) { - let _ = self.tx.unbounded_send(BlockImportWorkerMsg::Synchronized); - } -} - -/// See [`buffered_link`]. -pub struct BufferedLinkReceiver { - rx: mpsc::UnboundedReceiver>, -} - -impl BufferedLinkReceiver { - /// Polls for the buffered link actions. Any enqueued action will be propagated to the link - /// passed as parameter. - /// - /// This method should behave in a way similar to `Future::poll`. It can register the current - /// task and notify later when more actions are ready to be polled. To continue the comparison, - /// it is as if this method always returned `Ok(Async::NotReady)`. - pub fn poll_actions(&mut self, link: &mut dyn Link) { - loop { - let msg = if let Ok(Async::Ready(Some(msg))) = self.rx.poll() { - msg - } else { - break - }; - - match msg { - BlockImportWorkerMsg::BlockImported(hash, number) => - link.block_imported(&hash, number), - BlockImportWorkerMsg::BlocksProcessed(blocks, has_error) => - link.blocks_processed(blocks, has_error), - BlockImportWorkerMsg::JustificationImported(who, hash, number, success) => - link.justification_imported(who, &hash, number, success), - BlockImportWorkerMsg::ClearJustificationRequests => - link.clear_justification_requests(), - BlockImportWorkerMsg::RequestJustification(hash, number) => - link.request_justification(&hash, number), - BlockImportWorkerMsg::FinalityProofImported(who, block, result) => - link.finality_proof_imported(who, block, result), - BlockImportWorkerMsg::RequestFinalityProof(hash, number) => - link.request_finality_proof(&hash, number), - BlockImportWorkerMsg::SetFinalityProofRequestBuilder(builder) => - link.set_finality_proof_request_builder(builder), - BlockImportWorkerMsg::ReportPeer(who, reput) => - link.report_peer(who, reput), - BlockImportWorkerMsg::Restart => - link.restart(), - #[cfg(any(test, feature = "test-helpers"))] - BlockImportWorkerMsg::Synchronized => - link.synchronized(), - } - } - } } /// Block import successful result. @@ -610,7 +149,7 @@ pub enum BlockImportResult { } /// Block import error. -#[derive(Debug, PartialEq)] +#[derive(Debug)] pub enum BlockImportError { /// Block missed header, can't be imported IncompleteHeader(Option), @@ -620,66 +159,15 @@ pub enum BlockImportError { BadBlock(Option), /// Block has an unknown parent UnknownParent, - /// Other Error. - Error, -} - -/// Import several blocks at once, returning import result for each block. -fn import_many_blocks>( - import_handle: &dyn BlockImport, - blocks_origin: BlockOrigin, - blocks: Vec>, - verifier: Arc, -) -> (usize, usize, Vec<( - Result>, BlockImportError>, - B::Hash, -)>) { - let count = blocks.len(); - let mut imported = 0; - - let blocks_range = match ( - blocks.first().and_then(|b| b.header.as_ref().map(|h| h.number())), - blocks.last().and_then(|b| b.header.as_ref().map(|h| h.number())), - ) { - (Some(first), Some(last)) if first != last => format!(" ({}..{})", first, last), - (Some(first), Some(_)) => format!(" ({})", first), - _ => Default::default(), - }; - - trace!(target: "sync", "Starting import of {} blocks {}", count, blocks_range); - - let mut results = vec![]; - - let mut has_error = false; - - // Blocks in the response/drain should be in ascending order. - for block in blocks { - let block_hash = block.hash; - let import_result = if has_error { - Err(BlockImportError::Error) - } else { - import_single_block( - import_handle, - blocks_origin.clone(), - block, - verifier.clone(), - ) - }; - let was_ok = import_result.is_ok(); - results.push((import_result, block_hash)); - if was_ok { - imported += 1; - } else { - has_error = true; - } - } - - (imported, count, results) + /// Block import has been cancelled. This can happen if the parent block fails to be imported. + Cancelled, + /// Other error. + Other(ConsensusError), } /// Single block import function. pub fn import_single_block>( - import_handle: &dyn BlockImport, + import_handle: &mut dyn BlockImport, block_origin: BlockOrigin, block: IncomingBlock, verifier: Arc, @@ -721,7 +209,7 @@ pub fn import_single_block>( }, Err(e) => { debug!(target: "sync", "Error importing block {}: {:?}: {:?}", number, hash, e); - Err(BlockImportError::Error) + Err(BlockImportError::Other(e)) } } }; diff --git a/core/consensus/common/src/import_queue/basic_queue.rs b/core/consensus/common/src/import_queue/basic_queue.rs new file mode 100644 index 0000000000000000000000000000000000000000..51d30cddbb729d93379a055077864ba5862865c8 --- /dev/null +++ b/core/consensus/common/src/import_queue/basic_queue.rs @@ -0,0 +1,315 @@ +// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +use std::sync::Arc; +use futures::{prelude::*, future::Executor, sync::mpsc}; +use runtime_primitives::{Justification, traits::{Block as BlockT, Header as HeaderT, NumberFor}}; + +use crate::error::Error as ConsensusError; +use crate::block_import::{BlockImport, BlockOrigin}; +use crate::import_queue::{ + BlockImportResult, BlockImportError, Verifier, BoxBlockImport, BoxFinalityProofImport, + BoxJustificationImport, ImportQueue, Link, Origin, + IncomingBlock, import_single_block, + buffered_link::{self, BufferedLinkSender, BufferedLinkReceiver} +}; + +/// Interface to a basic block import queue that is importing blocks sequentially in a separate +/// task, with pluggable verification. +pub struct BasicQueue { + /// Channel to send messages to the background task. + sender: mpsc::UnboundedSender>, + /// Results coming from the worker task. + result_port: BufferedLinkReceiver, + /// Since we have to be in a tokio context in order to spawn background tasks, we first store + /// the task to spawn here, then extract it as soon as we are in a tokio context. + /// If `Some`, contains the task to spawn in the background. If `None`, the future has already + /// been spawned. + future_to_spawn: Option + Send>>, + /// If it isn't possible to spawn the future in `future_to_spawn` (which is notably the case in + /// "no std" environment), we instead put it in `manual_poll`. It is then polled manually from + /// `poll_actions`. + manual_poll: Option + Send>>, +} + +impl BasicQueue { + /// Instantiate a new basic queue, with given verifier. + /// + /// This creates a background task, and calls `on_start` on the justification importer and + /// finality proof importer. + pub fn new>( + verifier: Arc, + block_import: BoxBlockImport, + justification_import: Option>, + finality_proof_import: Option>, + ) -> Self { + let (result_sender, result_port) = buffered_link::buffered_link(); + let (future, worker_sender) = BlockImportWorker::new( + result_sender, + verifier, + block_import, + justification_import, + finality_proof_import, + ); + + Self { + sender: worker_sender, + result_port, + future_to_spawn: Some(Box::new(future)), + manual_poll: None, + } + } +} + +impl ImportQueue for BasicQueue { + fn import_blocks(&mut self, origin: BlockOrigin, blocks: Vec>) { + if blocks.is_empty() { + return; + } + + trace!(target: "sync", "Scheduling {} blocks for import", blocks.len()); + let _ = self.sender.unbounded_send(ToWorkerMsg::ImportBlocks(origin, blocks)); + } + + fn import_justification( + &mut self, + who: Origin, + hash: B::Hash, + number: NumberFor, + justification: Justification + ) { + let _ = self.sender.unbounded_send(ToWorkerMsg::ImportJustification(who.clone(), hash, number, justification)); + } + + fn import_finality_proof(&mut self, who: Origin, hash: B::Hash, number: NumberFor, finality_proof: Vec) { + trace!(target: "sync", "Scheduling finality proof of {}/{} for import", number, hash); + let _ = self.sender.unbounded_send(ToWorkerMsg::ImportFinalityProof(who, hash, number, finality_proof)); + } + + fn poll_actions(&mut self, link: &mut dyn Link) { + // Try to spawn the future in `future_to_spawn`. + if let Some(future) = self.future_to_spawn.take() { + if let Err(err) = tokio_executor::DefaultExecutor::current().execute(future) { + debug_assert!(self.manual_poll.is_none()); + self.manual_poll = Some(err.into_future()); + } + } + + // As a backup mechanism, if we failed to spawn the `future_to_spawn`, we instead poll + // manually here. + if let Some(manual_poll) = self.manual_poll.as_mut() { + match manual_poll.poll() { + Ok(Async::NotReady) => {} + _ => self.manual_poll = None, + } + } + + self.result_port.poll_actions(link); + } +} + +/// Message destinated to the background worker. +#[derive(Debug)] +enum ToWorkerMsg { + ImportBlocks(BlockOrigin, Vec>), + ImportJustification(Origin, B::Hash, NumberFor, Justification), + ImportFinalityProof(Origin, B::Hash, NumberFor, Vec), +} + +struct BlockImportWorker> { + result_sender: BufferedLinkSender, + block_import: BoxBlockImport, + justification_import: Option>, + finality_proof_import: Option>, + verifier: Arc, +} + +impl> BlockImportWorker { + fn new( + result_sender: BufferedLinkSender, + verifier: Arc, + block_import: BoxBlockImport, + justification_import: Option>, + finality_proof_import: Option>, + ) -> (impl Future + Send, mpsc::UnboundedSender>) { + let (sender, mut port) = mpsc::unbounded(); + + let mut worker = BlockImportWorker { + result_sender, + verifier, + justification_import, + block_import, + finality_proof_import, + }; + + if let Some(justification_import) = worker.justification_import.as_mut() { + for (hash, number) in justification_import.on_start() { + worker.result_sender.request_justification(&hash, number); + } + } + + if let Some(finality_proof_import) = worker.finality_proof_import.as_mut() { + for (hash, number) in finality_proof_import.on_start() { + worker.result_sender.request_finality_proof(&hash, number); + } + } + + let future = futures::future::poll_fn(move || { + loop { + let msg = match port.poll() { + Ok(Async::Ready(Some(msg))) => msg, + Err(_) | Ok(Async::Ready(None)) => return Ok(Async::Ready(())), + Ok(Async::NotReady) => return Ok(Async::NotReady), + }; + + match msg { + ToWorkerMsg::ImportBlocks(origin, blocks) => { + worker.import_a_batch_of_blocks(origin, blocks); + }, + ToWorkerMsg::ImportFinalityProof(who, hash, number, proof) => { + worker.import_finality_proof(who, hash, number, proof); + }, + ToWorkerMsg::ImportJustification(who, hash, number, justification) => { + worker.import_justification(who, hash, number, justification); + } + } + } + }); + + (future, sender) + } + + fn import_a_batch_of_blocks(&mut self, origin: BlockOrigin, blocks: Vec>) { + let result_sender = &self.result_sender; + let (imported, count, results) = import_many_blocks( + &mut *self.block_import, + origin, + blocks, + self.verifier.clone(), + || !result_sender.is_closed(), + ); + + self.result_sender.blocks_processed(imported, count, results); + } + + fn import_finality_proof(&mut self, who: Origin, hash: B::Hash, number: NumberFor, finality_proof: Vec) { + let verifier = &*self.verifier; + let result = self.finality_proof_import.as_mut().map(|finality_proof_import| { + finality_proof_import.import_finality_proof(hash, number, finality_proof, verifier) + .map_err(|e| { + debug!( + "Finality proof import failed with {:?} for hash: {:?} number: {:?} coming from node: {:?}", + e, + hash, + number, + who, + ); + }) + }).unwrap_or(Err(())); + + trace!(target: "sync", "Imported finality proof for {}/{}", number, hash); + self.result_sender.finality_proof_imported(who, (hash, number), result); + } + + fn import_justification( + &mut self, + who: Origin, + hash: B::Hash, + number: NumberFor, + justification: Justification + ) { + let success = self.justification_import.as_mut().map(|justification_import| { + justification_import.import_justification(hash, number, justification) + .map_err(|e| { + debug!( + target: "sync", + "Justification import failed with {:?} for hash: {:?} number: {:?} coming from node: {:?}", + e, + hash, + number, + who, + ); + e + }).is_ok() + }).unwrap_or(false); + + self.result_sender.justification_imported(who, &hash, number, success); + } +} + +/// Import several blocks at once, returning import result for each block. +/// +/// The `keep_going` closure will be called regularly. If it returns false, then the function will +/// end prematurely. +fn import_many_blocks>( + import_handle: &mut dyn BlockImport, + blocks_origin: BlockOrigin, + blocks: Vec>, + verifier: Arc, + keep_going: impl Fn() -> bool, +) -> (usize, usize, Vec<( + Result>, BlockImportError>, + B::Hash, +)>) { + let count = blocks.len(); + let mut imported = 0; + + let blocks_range = match ( + blocks.first().and_then(|b| b.header.as_ref().map(|h| h.number())), + blocks.last().and_then(|b| b.header.as_ref().map(|h| h.number())), + ) { + (Some(first), Some(last)) if first != last => format!(" ({}..{})", first, last), + (Some(first), Some(_)) => format!(" ({})", first), + _ => Default::default(), + }; + + trace!(target: "sync", "Starting import of {} blocks {}", count, blocks_range); + + let mut results = vec![]; + + let mut has_error = false; + + // Blocks in the response/drain should be in ascending order. + for block in blocks { + if !keep_going() { + // Setting `has_error` to true cancels the rest of the import. + has_error = true; + } + + let block_number = block.header.as_ref().map(|h| h.number().clone()); + let block_hash = block.hash; + let import_result = if has_error { + Err(BlockImportError::Cancelled) + } else { + import_single_block( + import_handle, + blocks_origin.clone(), + block, + verifier.clone(), + ) + }; + let was_ok = import_result.is_ok(); + if was_ok { + trace!(target: "sync", "Block imported successfully {:?} ({})", block_number, block_hash); + imported += 1; + } else { + has_error = true; + } + results.push((import_result, block_hash)); + } + + (imported, count, results) +} diff --git a/core/consensus/common/src/import_queue/buffered_link.rs b/core/consensus/common/src/import_queue/buffered_link.rs new file mode 100644 index 0000000000000000000000000000000000000000..9c555ba9d964dfb82d1f34388ab55b9d3193b12d --- /dev/null +++ b/core/consensus/common/src/import_queue/buffered_link.rs @@ -0,0 +1,159 @@ +// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +//! Provides the `buffered_link` utility. +//! +//! The buffered link is a channel that allows buffering the method calls on `Link`. +//! +//! # Example +//! +//! ```no_run +//! use substrate_consensus_common::import_queue::Link; +//! # use substrate_consensus_common::import_queue::buffered_link::buffered_link; +//! # use test_client::runtime::Block; +//! # struct DummyLink; impl Link for DummyLink {} +//! # let mut my_link = DummyLink; +//! let (mut tx, mut rx) = buffered_link::(); +//! tx.blocks_processed(0, 0, vec![]); +//! rx.poll_actions(&mut my_link); // Calls `my_link.blocks_processed(0, 0, vec![])` +//! ``` +//! + +use futures::{prelude::*, sync::mpsc}; +use runtime_primitives::traits::{Block as BlockT, NumberFor}; +use crate::import_queue::{Origin, Link, BlockImportResult, BlockImportError}; + +/// Wraps around an unbounded channel from the `futures` crate. The sender implements `Link` and +/// can be used to buffer commands, and the receiver can be used to poll said commands and transfer +/// them to another link. +pub fn buffered_link() -> (BufferedLinkSender, BufferedLinkReceiver) { + let (tx, rx) = mpsc::unbounded(); + let tx = BufferedLinkSender { tx }; + let rx = BufferedLinkReceiver { rx }; + (tx, rx) +} + +/// See [`buffered_link`]. +pub struct BufferedLinkSender { + tx: mpsc::UnboundedSender>, +} + +impl BufferedLinkSender { + /// Returns true if the sender points to nowhere. + /// + /// Once `true` is returned, it is pointless to use the sender anymore. + pub fn is_closed(&self) -> bool { + self.tx.is_closed() + } +} + +/// Internal buffered message. +enum BlockImportWorkerMsg { + BlocksProcessed(usize, usize, Vec<(Result>, BlockImportError>, B::Hash)>), + JustificationImported(Origin, B::Hash, NumberFor, bool), + RequestJustification(B::Hash, NumberFor), + FinalityProofImported(Origin, (B::Hash, NumberFor), Result<(B::Hash, NumberFor), ()>), + RequestFinalityProof(B::Hash, NumberFor), +} + +impl Link for BufferedLinkSender { + fn blocks_processed( + &mut self, + imported: usize, + count: usize, + results: Vec<(Result>, BlockImportError>, B::Hash)> + ) { + let _ = self.tx.unbounded_send(BlockImportWorkerMsg::BlocksProcessed(imported, count, results)); + } + + fn justification_imported( + &mut self, + who: Origin, + hash: &B::Hash, + number: NumberFor, + success: bool + ) { + let msg = BlockImportWorkerMsg::JustificationImported(who, hash.clone(), number, success); + let _ = self.tx.unbounded_send(msg); + } + + fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { + let _ = self.tx.unbounded_send(BlockImportWorkerMsg::RequestJustification(hash.clone(), number)); + } + + fn finality_proof_imported( + &mut self, + who: Origin, + request_block: (B::Hash, NumberFor), + finalization_result: Result<(B::Hash, NumberFor), ()>, + ) { + let msg = BlockImportWorkerMsg::FinalityProofImported(who, request_block, finalization_result); + let _ = self.tx.unbounded_send(msg); + } + + fn request_finality_proof(&mut self, hash: &B::Hash, number: NumberFor) { + let _ = self.tx.unbounded_send(BlockImportWorkerMsg::RequestFinalityProof(hash.clone(), number)); + } +} + +/// See [`buffered_link`]. +pub struct BufferedLinkReceiver { + rx: mpsc::UnboundedReceiver>, +} + +impl BufferedLinkReceiver { + /// Polls for the buffered link actions. Any enqueued action will be propagated to the link + /// passed as parameter. + /// + /// This method should behave in a way similar to `Future::poll`. It can register the current + /// task and notify later when more actions are ready to be polled. To continue the comparison, + /// it is as if this method always returned `Ok(Async::NotReady)`. + pub fn poll_actions(&mut self, link: &mut dyn Link) { + loop { + let msg = if let Ok(Async::Ready(Some(msg))) = self.rx.poll() { + msg + } else { + break + }; + + match msg { + BlockImportWorkerMsg::BlocksProcessed(imported, count, results) => + link.blocks_processed(imported, count, results), + BlockImportWorkerMsg::JustificationImported(who, hash, number, success) => + link.justification_imported(who, &hash, number, success), + BlockImportWorkerMsg::RequestJustification(hash, number) => + link.request_justification(&hash, number), + BlockImportWorkerMsg::FinalityProofImported(who, block, result) => + link.finality_proof_imported(who, block, result), + BlockImportWorkerMsg::RequestFinalityProof(hash, number) => + link.request_finality_proof(&hash, number), + } + } + } +} + +#[cfg(test)] +mod tests { + use test_client::runtime::Block; + + #[test] + fn is_closed() { + let (tx, rx) = super::buffered_link::(); + assert!(!tx.is_closed()); + drop(rx); + assert!(tx.is_closed()); + } +} diff --git a/core/consensus/common/src/lib.rs b/core/consensus/common/src/lib.rs index 5982003c15ea62b85aadfbe028f073637a9267ca..e445d974d8a3545398c46ac37b894bc14725d04c 100644 --- a/core/consensus/common/src/lib.rs +++ b/core/consensus/common/src/lib.rs @@ -26,7 +26,6 @@ // our error-chain could potentially blow up otherwise #![recursion_limit="128"] -extern crate crossbeam_channel; #[macro_use] extern crate log; use std::sync::Arc; @@ -49,7 +48,7 @@ const MAX_BLOCK_SIZE: usize = 4 * 1024 * 1024 + 512; pub use self::error::Error; pub use block_import::{ BlockImport, BlockOrigin, ForkChoiceStrategy, ImportedAux, ImportBlock, ImportResult, - JustificationImport, FinalityProofImport, FinalityProofRequestBuilder, + JustificationImport, FinalityProofImport, }; pub use select_chain::SelectChain; diff --git a/core/consensus/rhd/Cargo.toml b/core/consensus/rhd/Cargo.toml index d9632bac8715e9e9dd8f9becae6177c187f789e5..7eda2d69045174e5e7e1ee618b63941b37247fd1 100644 --- a/core/consensus/rhd/Cargo.toml +++ b/core/consensus/rhd/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" [dependencies] derive_more = "0.14.0" futures = "0.1.17" -codec = { package = "parity-codec", version = "3.2", features = ["derive"] } +codec = { package = "parity-codec", version = "4.1.1", features = ["derive"] } primitives = { package = "substrate-primitives", path = "../../primitives" } consensus = { package = "substrate-consensus-common", path = "../common" } client = { package = "substrate-client", path = "../../client" } @@ -21,7 +21,7 @@ runtime_io = { package = "sr-io", path = "../../sr-io" } tokio = "0.1.7" parking_lot = "0.8.0" log = "0.4" -rhododendron = { version = "0.5.0", features = ["codec"] } +rhododendron = { version = "0.6.0", features = ["codec"] } exit-future = "0.1" [dev-dependencies] diff --git a/core/consensus/slots/Cargo.toml b/core/consensus/slots/Cargo.toml index 5c187024c9f49f70665c7aa015e306016b0436ee..fa856bbfbb8df53aaee5b150d4e47c945cf89008 100644 --- a/core/consensus/slots/Cargo.toml +++ b/core/consensus/slots/Cargo.toml @@ -6,7 +6,7 @@ description = "Generic slots-based utilities for consensus" edition = "2018" [dependencies] -codec = { package = "parity-codec", version = "3.2" } +codec = { package = "parity-codec", version = "4.1.1" } client = { package = "substrate-client", path = "../../client" } primitives = { package = "substrate-primitives", path = "../../primitives" } runtime_primitives = { package = "sr-primitives", path = "../../sr-primitives" } diff --git a/core/consensus/slots/src/lib.rs b/core/consensus/slots/src/lib.rs index 18ec2451beba818aa84429c7dc44f7211183a52a..b2651619232aa104c86510700a0dac5c98da2df2 100644 --- a/core/consensus/slots/src/lib.rs +++ b/core/consensus/slots/src/lib.rs @@ -25,7 +25,7 @@ mod slots; mod aux_schema; -pub use slots::{slot_now, SlotInfo, Slots}; +pub use slots::{SignedDuration, SlotInfo, Slots}; pub use aux_schema::{check_equivocation, MAX_SLOT_CAPACITY, PRUNING_BOUND}; use codec::{Decode, Encode}; @@ -48,10 +48,6 @@ pub trait SlotWorker { /// triggered. type OnSlot: IntoFuture; - /// Called when the proposer starts. - #[deprecated(note = "Not called. Please perform any initialization before calling start_slot_worker.")] - fn on_start(&self, _slot_duration: u64) -> Result<(), consensus_common::Error> { Ok(()) } - /// Called when a new slot is triggered. fn on_slot(&self, chain_head: B::Header, slot_info: SlotInfo) -> Self::OnSlot; } @@ -60,8 +56,13 @@ pub trait SlotWorker { pub trait SlotCompatible { /// Extract timestamp and slot from inherent data. fn extract_timestamp_and_slot( + &self, inherent: &InherentData, - ) -> Result<(u64, u64), consensus_common::Error>; + ) -> Result<(u64, u64, std::time::Duration), consensus_common::Error>; + + /// Get the difference between chain time and local time. Defaults to + /// always returning zero. + fn time_offset() -> SignedDuration { Default::default() } } /// Start a new slot worker. @@ -74,6 +75,7 @@ pub fn start_slot_worker( worker: W, sync_oracle: SO, inherent_data_providers: InherentDataProviders, + timestamp_extractor: SC, ) -> impl Future where B: Block, @@ -86,8 +88,11 @@ where let SlotDuration(slot_duration) = slot_duration; // rather than use a timer interval, we schedule our waits ourselves - let mut authorship = Slots::::new(slot_duration.slot_duration(), inherent_data_providers) - .map_err(|e| debug!(target: "slots", "Faulty timer: {:?}", e)) + let mut authorship = Slots::::new( + slot_duration.slot_duration(), + inherent_data_providers, + timestamp_extractor, + ).map_err(|e| debug!(target: "slots", "Faulty timer: {:?}", e)) .for_each(move |slot_info| { // only propose when we are not syncing. if sync_oracle.is_major_syncing() { diff --git a/core/consensus/slots/src/slots.rs b/core/consensus/slots/src/slots.rs index a848a967629a19de7f469691ba8ac4e51fce1c07..c35b252b4000ec0440869c059d5e392706597c09 100644 --- a/core/consensus/slots/src/slots.rs +++ b/core/consensus/slots/src/slots.rs @@ -23,29 +23,43 @@ use consensus_common::Error; use futures::prelude::*; use futures::try_ready; use inherents::{InherentData, InherentDataProviders}; -use log::warn; -use std::marker::PhantomData; + use std::time::{Duration, Instant}; use tokio_timer::Delay; /// Returns current duration since unix epoch. -pub fn duration_now() -> Option { +pub fn duration_now() -> Duration { use std::time::SystemTime; - let now = SystemTime::now(); - now.duration_since(SystemTime::UNIX_EPOCH) - .map_err(|e| { - warn!( - "Current time {:?} is before unix epoch. Something is wrong: {:?}", - now, e - ); - }) - .ok() + now.duration_since(SystemTime::UNIX_EPOCH).unwrap_or_else(|e| panic!( + "Current time {:?} is before unix epoch. Something is wrong: {:?}", + now, + e, + )) } -/// Get the slot for now. -pub fn slot_now(slot_duration: u64) -> Option { - duration_now().map(|s| s.as_secs() / slot_duration) + +/// A `Duration` with a sign (before or after). Immutable. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +pub struct SignedDuration { + offset: Duration, + is_positive: bool, +} + +impl SignedDuration { + /// Construct a `SignedDuration` + pub fn new(offset: Duration, is_positive: bool) -> Self { + Self { offset, is_positive } + } + + /// Get the slot for now. Panics if `slot_duration` is 0. + pub fn slot_now(&self, slot_duration: u64) -> u64 { + (if self.is_positive { + duration_now() + self.offset + } else { + duration_now() - self.offset + }.as_secs()) / slot_duration + } } /// Returns the duration until the next slot, based on current duration since @@ -87,18 +101,22 @@ pub struct Slots { slot_duration: u64, inner_delay: Option, inherent_data_providers: InherentDataProviders, - _marker: PhantomData, + timestamp_extractor: SC, } impl Slots { /// Create a new `Slots` stream. - pub fn new(slot_duration: u64, inherent_data_providers: InherentDataProviders) -> Self { + pub fn new( + slot_duration: u64, + inherent_data_providers: InherentDataProviders, + timestamp_extractor: SC, + ) -> Self { Slots { last_slot: 0, slot_duration, inner_delay: None, inherent_data_providers, - _marker: PhantomData, + timestamp_extractor, } } } @@ -108,53 +126,49 @@ impl Stream for Slots { type Error = Error; fn poll(&mut self) -> Poll, Self::Error> { - let slot_duration = self.slot_duration; - self.inner_delay = match self.inner_delay.take() { - None => { - // schedule wait. - let wait_until = match duration_now() { - None => return Ok(Async::Ready(None)), - Some(now) => Instant::now() + time_until_next(now, slot_duration), - }; - - Some(Delay::new(wait_until)) + loop { + let slot_duration = self.slot_duration; + self.inner_delay = match self.inner_delay.take() { + None => { + // schedule wait. + let wait_until = Instant::now() + time_until_next(duration_now(), slot_duration); + Some(Delay::new(wait_until)) + } + Some(d) => Some(d), + }; + + if let Some(ref mut inner_delay) = self.inner_delay { + try_ready!(inner_delay + .poll() + .map_err(Error::FaultyTimer)); } - Some(d) => Some(d), - }; - - if let Some(ref mut inner_delay) = self.inner_delay { - try_ready!(inner_delay - .poll() - .map_err(Error::FaultyTimer)); - } - // timeout has fired. - - let inherent_data = self - .inherent_data_providers - .create_inherent_data() - .map_err(|s| consensus_common::Error::InherentData(s.into_owned()))?; - let (timestamp, slot_num) = SC::extract_timestamp_and_slot(&inherent_data)?; - - // reschedule delay for next slot. - let ends_at = - Instant::now() + time_until_next(Duration::from_secs(timestamp), slot_duration); - self.inner_delay = Some(Delay::new(ends_at)); - - // never yield the same slot twice. - if slot_num > self.last_slot { - self.last_slot = slot_num; - - Ok(Async::Ready(Some(SlotInfo { - number: slot_num, - duration: self.slot_duration, - timestamp, - ends_at, - inherent_data, - }))) - } else { - // re-poll until we get a new slot. - self.poll() + // timeout has fired. + + let inherent_data = self + .inherent_data_providers + .create_inherent_data() + .map_err(|s| consensus_common::Error::InherentData(s.into_owned()))?; + let (timestamp, slot_num, offset) = self + .timestamp_extractor + .extract_timestamp_and_slot(&inherent_data)?; + // reschedule delay for next slot. + let ends_at = Instant::now() + offset + + time_until_next(Duration::from_secs(timestamp), slot_duration); + self.inner_delay = Some(Delay::new(ends_at)); + + // never yield the same slot twice. + if slot_num > self.last_slot { + self.last_slot = slot_num; + + break Ok(Async::Ready(Some(SlotInfo { + number: slot_num, + duration: self.slot_duration, + timestamp, + ends_at, + inherent_data, + }))) + } } } } diff --git a/core/executor/Cargo.toml b/core/executor/Cargo.toml index 9cc198557da0f1c57657e9a31f051fabca05c42d..50afe391db958ff096bfc10cbd1c0d9d4e940532 100644 --- a/core/executor/Cargo.toml +++ b/core/executor/Cargo.toml @@ -5,8 +5,8 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -derive_more = "0.14.0" -parity-codec = "3.3" +derive_more = "0.15.0" +parity-codec = "4.1.1" runtime_io = { package = "sr-io", path = "../sr-io" } primitives = { package = "substrate-primitives", path = "../primitives" } trie = { package = "substrate-trie", path = "../trie" } @@ -15,8 +15,8 @@ state_machine = { package = "substrate-state-machine", path = "../state-machine" runtime_version = { package = "sr-version", path = "../sr-version" } panic-handler = { package = "substrate-panic-handler", path = "../panic-handler" } wasmi = { version = "0.4.3" } -byteorder = "1.1" -lazy_static = "1.0" +byteorder = "1.3" +lazy_static = "1.3" parking_lot = "0.8.0" log = "0.4" libsecp256k1 = "0.2.1" @@ -26,6 +26,9 @@ tiny-keccak = "1.4.2" assert_matches = "1.1" wabt = "~0.7.4" hex-literal = "0.2.0" +runtime-test = { package = "substrate-runtime-test", path = "runtime-test" } +substrate-client = { path = "../client" } +substrate-offchain = { path = "../offchain/" } [features] default = [] diff --git a/core/executor/wasm/Cargo.toml b/core/executor/runtime-test/Cargo.toml similarity index 52% rename from core/executor/wasm/Cargo.toml rename to core/executor/runtime-test/Cargo.toml index e9f829746d49f0952c7da8d73e1f90bfbe17c516..26bf2f71bdcf2d25a9ef5169e73be3ced15fe5bc 100644 --- a/core/executor/wasm/Cargo.toml +++ b/core/executor/runtime-test/Cargo.toml @@ -1,20 +1,20 @@ [package] -name = "runtime-test" +name = "substrate-runtime-test" version = "2.0.0" authors = ["Parity Technologies "] edition = "2018" - -[lib] -crate-type = ["cdylib"] +build = "build.rs" [dependencies] +rstd = { package = "sr-std", path = "../../sr-std", default-features = false } runtime_io = { package = "sr-io", path = "../../sr-io", default-features = false } sandbox = { package = "sr-sandbox", path = "../../sr-sandbox", default-features = false } substrate-primitives = { path = "../../primitives", default-features = false } -[profile.release] -panic = "abort" -lto = true +[build-dependencies] +wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.2", path = "../../utils/wasm-builder-runner" } -[workspace] -members = [] +[features] +default = [ "std" ] +std = [] +no_std = [] diff --git a/core/executor/runtime-test/build.rs b/core/executor/runtime-test/build.rs new file mode 100644 index 0000000000000000000000000000000000000000..a8a5e1cba54f6a2e6836220a7462a42c4a5c1038 --- /dev/null +++ b/core/executor/runtime-test/build.rs @@ -0,0 +1,27 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +use wasm_builder_runner::{build_current_project, WasmBuilderSource}; + +fn main() { + build_current_project( + "wasm_binary.rs", + WasmBuilderSource::CratesOrPath { + path: "../../utils/wasm-builder", + version: "1.0.4", + }, + ); +} diff --git a/core/executor/wasm/src/lib.rs b/core/executor/runtime-test/src/lib.rs similarity index 72% rename from core/executor/wasm/src/lib.rs rename to core/executor/runtime-test/src/lib.rs index 41f071ca9fef4be361c0ca66eda83cd004021b46..bca220264642851069852722486f248dc727d4f7 100644 --- a/core/executor/wasm/src/lib.rs +++ b/core/executor/runtime-test/src/lib.rs @@ -1,9 +1,11 @@ -#![no_std] +#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(feature = "strict", deny(warnings))] -extern crate alloc; -use alloc::vec::Vec; -use alloc::slice; +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +use rstd::{vec::Vec, slice, vec}; use runtime_io::{ set_storage, storage, clear_prefix, print, blake2_128, blake2_256, @@ -11,7 +13,7 @@ use runtime_io::{ }; macro_rules! impl_stubs { - ( $( $new_name:ident => $invoke:expr ),* ) => { + ( $( $new_name:ident => $invoke:expr, )* ) => { $( impl_stubs!(@METHOD $new_name => $invoke); )* @@ -33,7 +35,7 @@ macro_rules! impl_stubs { // Leak the output vector to avoid it being freed. // This is fine in a WASM context since the heap // will be discarded after the call. - ::core::mem::forget(output); + rstd::mem::forget(output); res } }; @@ -134,7 +136,42 @@ impl_stubs!( Err(sandbox::Error::OutOfBounds) => 3, }; [code].to_vec() - } + }, + test_offchain_local_storage => |_| { + let kind = substrate_primitives::offchain::StorageKind::PERSISTENT; + assert_eq!(runtime_io::local_storage_get(kind, b"test"), None); + runtime_io::local_storage_set(kind, b"test", b"asd"); + assert_eq!(runtime_io::local_storage_get(kind, b"test"), Some(b"asd".to_vec())); + + let res = runtime_io::local_storage_compare_and_set(kind, b"test", b"asd", b""); + assert_eq!(res, true); + assert_eq!(runtime_io::local_storage_get(kind, b"test"), Some(b"".to_vec())); + + [0].to_vec() + }, + test_offchain_http => |_| { + use substrate_primitives::offchain::HttpRequestStatus; + let run = || -> Option<()> { + let id = runtime_io::http_request_start("POST", "http://localhost:12345", &[]).ok()?; + runtime_io::http_request_add_header(id, "X-Auth", "test").ok()?; + runtime_io::http_request_write_body(id, &[1, 2, 3, 4], None).ok()?; + runtime_io::http_request_write_body(id, &[], None).ok()?; + let status = runtime_io::http_response_wait(&[id], None); + assert!(status == vec![HttpRequestStatus::Finished(200)], "Expected Finished(200) status."); + let headers = runtime_io::http_response_headers(id); + assert_eq!(headers, vec![(b"X-Auth".to_vec(), b"hello".to_vec())]); + let mut buffer = vec![0; 64]; + let read = runtime_io::http_response_read_body(id, &mut buffer, None).ok()?; + assert_eq!(read, 3); + assert_eq!(&buffer[0..read], &[1, 2, 3]); + let read = runtime_io::http_response_read_body(id, &mut buffer, None).ok()?; + assert_eq!(read, 0); + + Some(()) + }; + + [if run().is_some() { 0 } else { 1 }].to_vec() + }, ); fn execute_sandboxed(code: &[u8], args: &[sandbox::TypedValue]) -> Result { diff --git a/core/executor/src/sandbox.rs b/core/executor/src/sandbox.rs index ceb5f44a260bb3bdf2a4077e549ee249c5268154..1ce300c38ad8168df3c401d8df4ee41032ab0823 100644 --- a/core/executor/src/sandbox.rs +++ b/core/executor/src/sandbox.rs @@ -341,11 +341,11 @@ impl SandboxInstance { } } -/// Error occured during instantiation of a sandboxed module. +/// Error occurred during instantiation of a sandboxed module. pub enum InstantiationError { /// Something wrong with the environment definition. It either can't /// be decoded, have a reference to a non-existent or torn down memory instance. - EnvironmentDefintionCorrupted, + EnvironmentDefinitionCorrupted, /// Provided module isn't recognized as a valid webassembly binary. ModuleDecoding, /// Module is a well-formed webassembly binary but could not be instantiated. This could @@ -361,7 +361,7 @@ fn decode_environment_definition( memories: &[Option], ) -> std::result::Result<(Imports, GuestToSupervisorFunctionMapping), InstantiationError> { let env_def = sandbox_primitives::EnvironmentDefinition::decode(&mut &raw_env_def[..]) - .ok_or_else(|| InstantiationError::EnvironmentDefintionCorrupted)?; + .ok_or_else(|| InstantiationError::EnvironmentDefinitionCorrupted)?; let mut func_map = HashMap::new(); let mut memories_map = HashMap::new(); @@ -381,8 +381,8 @@ fn decode_environment_definition( let memory_ref = memories .get(memory_idx as usize) .cloned() - .ok_or_else(|| InstantiationError::EnvironmentDefintionCorrupted)? - .ok_or_else(|| InstantiationError::EnvironmentDefintionCorrupted)?; + .ok_or_else(|| InstantiationError::EnvironmentDefinitionCorrupted)? + .ok_or_else(|| InstantiationError::EnvironmentDefinitionCorrupted)?; memories_map.insert((module, field), memory_ref); } } @@ -566,13 +566,14 @@ mod tests { use crate::wasm_executor::WasmExecutor; use state_machine::TestExternalities as CoreTestExternalities; use wabt; + use runtime_test::WASM_BINARY; type TestExternalities = CoreTestExternalities; #[test] fn sandbox_should_work() { let mut ext = TestExternalities::::default(); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" (module @@ -604,7 +605,7 @@ mod tests { #[test] fn sandbox_trap() { let mut ext = TestExternalities::::default(); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" (module @@ -625,7 +626,7 @@ mod tests { #[test] fn sandbox_should_trap_when_heap_exhausted() { let mut ext = TestExternalities::::default(); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" (module @@ -650,7 +651,7 @@ mod tests { #[test] fn start_called() { let mut ext = TestExternalities::::default(); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" (module @@ -688,7 +689,7 @@ mod tests { #[test] fn invoke_args() { let mut ext = TestExternalities::::default(); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" (module @@ -722,7 +723,7 @@ mod tests { #[test] fn return_val() { let mut ext = TestExternalities::::default(); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" (module @@ -744,7 +745,7 @@ mod tests { #[test] fn unlinkable_module() { let mut ext = TestExternalities::::default(); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" (module @@ -764,7 +765,7 @@ mod tests { #[test] fn corrupted_module() { let mut ext = TestExternalities::::default(); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; // Corrupted wasm file let code = &[0, 0, 0, 0, 1, 0, 0, 0]; @@ -778,7 +779,7 @@ mod tests { #[test] fn start_fn_ok() { let mut ext = TestExternalities::::default(); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" (module @@ -801,7 +802,7 @@ mod tests { #[test] fn start_fn_traps() { let mut ext = TestExternalities::::default(); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" (module diff --git a/core/executor/src/wasm_executor.rs b/core/executor/src/wasm_executor.rs index cbb47195de87baa5684aaa12e06a0709dc5bda33..83f1cf5a4befaccfc043254d993c6e3ce48d9b6c 100644 --- a/core/executor/src/wasm_executor.rs +++ b/core/executor/src/wasm_executor.rs @@ -729,18 +729,26 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, .ok_or_else(|| "Calling unavailable API ext_new_crypto_key: wasm")?; match res { - Ok(key_id) => Ok(key_id.0 as u32), + Ok(key_id) => Ok(key_id.into()), Err(()) => Ok(u32::max_value()), } }, - ext_encrypt(key: u32, data: *const u8, data_len: u32, msg_len: *mut u32) -> *mut u8 => { + ext_encrypt( + key: u32, + kind: u32, + data: *const u8, + data_len: u32, + msg_len: *mut u32 + ) -> *mut u8 => { let key = u32_to_key(key) .map_err(|_| "Key OOB while ext_encrypt: wasm")?; + let kind = offchain::CryptoKind::try_from(kind) + .map_err(|_| "crypto kind OOB while ext_encrypt: wasm")?; let message = this.memory.get(data, data_len as usize) .map_err(|_| "OOB while ext_encrypt: wasm")?; let res = this.ext.offchain() - .map(|api| api.encrypt(key, &*message)) + .map(|api| api.encrypt(key, kind, &*message)) .ok_or_else(|| "Calling unavailable API ext_encrypt: wasm")?; let (offset,len) = match res { @@ -759,14 +767,22 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, Ok(offset) }, - ext_decrypt(key: u32, data: *const u8, data_len: u32, msg_len: *mut u32) -> *mut u8 => { + ext_decrypt( + key: u32, + kind: u32, + data: *const u8, + data_len: u32, + msg_len: *mut u32 + ) -> *mut u8 => { let key = u32_to_key(key) .map_err(|_| "Key OOB while ext_decrypt: wasm")?; + let kind = offchain::CryptoKind::try_from(kind) + .map_err(|_| "crypto kind OOB while ext_decrypt: wasm")?; let message = this.memory.get(data, data_len as usize) .map_err(|_| "OOB while ext_decrypt: wasm")?; let res = this.ext.offchain() - .map(|api| api.decrypt(key, &*message)) + .map(|api| api.decrypt(key, kind, &*message)) .ok_or_else(|| "Calling unavailable API ext_decrypt: wasm")?; let (offset,len) = match res { @@ -785,14 +801,22 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, Ok(offset) }, - ext_sign(key: u32, data: *const u8, data_len: u32, sig_data_len: *mut u32) -> *mut u8 => { + ext_sign( + key: u32, + kind: u32, + data: *const u8, + data_len: u32, + sig_data_len: *mut u32 + ) -> *mut u8 => { let key = u32_to_key(key) .map_err(|_| "Key OOB while ext_sign: wasm")?; + let kind = offchain::CryptoKind::try_from(kind) + .map_err(|_| "crypto kind OOB while ext_sign: wasm")?; let message = this.memory.get(data, data_len as usize) .map_err(|_| "OOB while ext_sign: wasm")?; let res = this.ext.offchain() - .map(|api| api.sign(key, &*message)) + .map(|api| api.sign(key, kind, &*message)) .ok_or_else(|| "Calling unavailable API ext_sign: wasm")?; let (offset,len) = match res { @@ -813,6 +837,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, }, ext_verify( key: u32, + kind: u32, msg: *const u8, msg_len: u32, signature: *const u8, @@ -820,13 +845,15 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, ) -> u32 => { let key = u32_to_key(key) .map_err(|_| "Key OOB while ext_verify: wasm")?; + let kind = offchain::CryptoKind::try_from(kind) + .map_err(|_| "crypto kind OOB while ext_verify: wasm")?; let message = this.memory.get(msg, msg_len as usize) .map_err(|_| "OOB while ext_verify: wasm")?; let signature = this.memory.get(signature, signature_len as usize) .map_err(|_| "OOB while ext_verify: wasm")?; let res = this.ext.offchain() - .map(|api| api.verify(key, &*message, &*signature)) + .map(|api| api.verify(key, kind, &*message, &*signature)) .ok_or_else(|| "Calling unavailable API ext_verify: wasm")?; match res { @@ -857,24 +884,28 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, .map_err(|_| "Invalid attempt to set value in ext_random_seed")?; Ok(()) }, - ext_local_storage_set(key: *const u8, key_len: u32, value: *const u8, value_len: u32) => { + ext_local_storage_set(kind: u32, key: *const u8, key_len: u32, value: *const u8, value_len: u32) => { + let kind = offchain::StorageKind::try_from(kind) + .map_err(|_| "storage kind OOB while ext_local_storage_set: wasm")?; let key = this.memory.get(key, key_len as usize) .map_err(|_| "OOB while ext_local_storage_set: wasm")?; let value = this.memory.get(value, value_len as usize) .map_err(|_| "OOB while ext_local_storage_set: wasm")?; this.ext.offchain() - .map(|api| api.local_storage_set(&key, &value)) + .map(|api| api.local_storage_set(kind, &key, &value)) .ok_or_else(|| "Calling unavailable API ext_local_storage_set: wasm")?; Ok(()) }, - ext_local_storage_get(key: *const u8, key_len: u32, value_len: *mut u32) -> *mut u8 => { + ext_local_storage_get(kind: u32, key: *const u8, key_len: u32, value_len: *mut u32) -> *mut u8 => { + let kind = offchain::StorageKind::try_from(kind) + .map_err(|_| "storage kind OOB while ext_local_storage_get: wasm")?; let key = this.memory.get(key, key_len as usize) .map_err(|_| "OOB while ext_local_storage_get: wasm")?; let maybe_value = this.ext.offchain() - .map(|api| api.local_storage_get(&key)) + .map(|api| api.local_storage_get(kind, &key)) .ok_or_else(|| "Calling unavailable API ext_local_storage_get: wasm")?; let (offset, len) = if let Some(value) = maybe_value { @@ -891,6 +922,31 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, Ok(offset) }, + ext_local_storage_compare_and_set( + kind: u32, + key: *const u8, + key_len: u32, + old_value: *const u8, + old_value_len: u32, + new_value: *const u8, + new_value_len: u32 + ) -> u32 => { + let kind = offchain::StorageKind::try_from(kind) + .map_err(|_| "storage kind OOB while ext_local_storage_compare_and_set: wasm")?; + let key = this.memory.get(key, key_len as usize) + .map_err(|_| "OOB while ext_local_storage_compare_and_set: wasm")?; + let old_value = this.memory.get(old_value, old_value_len as usize) + .map_err(|_| "OOB while ext_local_storage_compare_and_set: wasm")?; + let new_value = this.memory.get(new_value, new_value_len as usize) + .map_err(|_| "OOB while ext_local_storage_compare_and_set: wasm")?; + + let res = this.ext.offchain() + .map(|api| api.local_storage_compare_and_set(kind, &key, &old_value, &new_value)) + .ok_or_else(|| "Calling unavailable API ext_local_storage_compare_andset: wasm")?; + + Ok(if res { 0 } else { 1 }) + + }, ext_http_request_start( method: *const u8, method_len: u32, @@ -916,7 +972,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, .ok_or_else(|| "Calling unavailable API ext_http_request_start: wasm")?; if let Ok(id) = id { - Ok(id.0 as u32) + Ok(id.into()) } else { Ok(u32::max_value()) } @@ -967,7 +1023,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, Ok(match res { Ok(()) => 0, - Err(e) => e as u8 as u32, + Err(e) => e.into(), }) }, ext_http_response_wait( @@ -1045,7 +1101,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, read as u32 }, Err(err) => { - u32::max_value() - err as u8 as u32 + 1 + u32::max_value() - u32::from(err) + 1 } }) }, @@ -1365,13 +1421,15 @@ mod tests { use state_machine::TestExternalities as CoreTestExternalities; use hex_literal::hex; use primitives::map; + use runtime_test::WASM_BINARY; + use substrate_offchain::testing; type TestExternalities = CoreTestExternalities; #[test] fn returning_should_work() { let mut ext = TestExternalities::default(); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; let output = WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_empty_return", &[]).unwrap(); assert_eq!(output, vec![0u8; 0]); @@ -1380,7 +1438,7 @@ mod tests { #[test] fn panicking_should_work() { let mut ext = TestExternalities::default(); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; let output = WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_panic", &[]); assert!(output.is_err()); @@ -1396,7 +1454,7 @@ mod tests { fn storage_should_work() { let mut ext = TestExternalities::default(); ext.set_storage(b"foo".to_vec(), b"bar".to_vec()); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; let output = WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_data_in", b"Hello world").unwrap(); @@ -1418,7 +1476,7 @@ mod tests { ext.set_storage(b"aba".to_vec(), b"3".to_vec()); ext.set_storage(b"abb".to_vec(), b"4".to_vec()); ext.set_storage(b"bbb".to_vec(), b"5".to_vec()); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; // This will clear all entries which prefix is "ab". let output = WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_clear_prefix", b"ab").unwrap(); @@ -1436,7 +1494,7 @@ mod tests { #[test] fn blake2_256_should_work() { let mut ext = TestExternalities::default(); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; assert_eq!( WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_blake2_256", &[]).unwrap(), blake2_256(&b""[..]).encode() @@ -1450,7 +1508,7 @@ mod tests { #[test] fn blake2_128_should_work() { let mut ext = TestExternalities::default(); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; assert_eq!( WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_blake2_128", &[]).unwrap(), blake2_128(&b""[..]).encode() @@ -1464,7 +1522,7 @@ mod tests { #[test] fn twox_256_should_work() { let mut ext = TestExternalities::default(); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; assert_eq!( WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_twox_256", &[]).unwrap(), hex!("99e9d85137db46ef4bbea33613baafd56f963c64b1f3685a4eb4abd67ff6203a") @@ -1478,7 +1536,7 @@ mod tests { #[test] fn twox_128_should_work() { let mut ext = TestExternalities::default(); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; assert_eq!( WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_twox_128", &[]).unwrap(), hex!("99e9d85137db46ef4bbea33613baafd5") @@ -1492,7 +1550,7 @@ mod tests { #[test] fn ed25519_verify_should_work() { let mut ext = TestExternalities::::default(); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; let key = ed25519::Pair::from_seed(&blake2_256(b"test")); let sig = key.sign(b"all ok!"); let mut calldata = vec![]; @@ -1518,7 +1576,7 @@ mod tests { #[test] fn sr25519_verify_should_work() { let mut ext = TestExternalities::::default(); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; let key = sr25519::Pair::from_seed(&blake2_256(b"test")); let sig = key.sign(b"all ok!"); let mut calldata = vec![]; @@ -1544,10 +1602,51 @@ mod tests { #[test] fn enumerated_trie_root_should_work() { let mut ext = TestExternalities::::default(); - let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let test_code = WASM_BINARY; assert_eq!( WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_enumerated_trie_root", &[]).unwrap(), ordered_trie_root::(vec![b"zero".to_vec(), b"one".to_vec(), b"two".to_vec()].iter()).as_fixed_bytes().encode() ); } + + #[test] + fn offchain_local_storage_should_work() { + use substrate_client::backend::OffchainStorage; + + let mut ext = TestExternalities::::default(); + let (offchain, state) = testing::TestOffchainExt::new(); + ext.set_offchain_externalities(offchain); + let test_code = WASM_BINARY; + assert_eq!( + WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_offchain_local_storage", &[]).unwrap(), + vec![0] + ); + assert_eq!(state.read().persistent_storage.get(b"", b"test"), Some(vec![])); + } + + #[test] + fn offchain_http_should_work() { + let mut ext = TestExternalities::::default(); + let (offchain, state) = testing::TestOffchainExt::new(); + ext.set_offchain_externalities(offchain); + state.write().expect_request( + 0, + testing::PendingRequest { + method: "POST".into(), + uri: "http://localhost:12345".into(), + body: vec![1, 2, 3, 4], + headers: vec![("X-Auth".to_owned(), "test".to_owned())], + sent: true, + response: vec![1, 2, 3], + response_headers: vec![("X-Auth".to_owned(), "hello".to_owned())], + ..Default::default() + }, + ); + + let test_code = WASM_BINARY; + assert_eq!( + WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_offchain_http", &[]).unwrap(), + vec![0] + ); + } } diff --git a/core/executor/wasm/Cargo.lock b/core/executor/wasm/Cargo.lock deleted file mode 100644 index 34cd17116c3c1708e76d2923a21fc47b15d598ee..0000000000000000000000000000000000000000 --- a/core/executor/wasm/Cargo.lock +++ /dev/null @@ -1,268 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "arrayvec" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "autocfg" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byteorder" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fixed-hash" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hash-db" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "hash256-std-hasher" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "impl-codec" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "nodrop" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "num-traits" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-codec" -version = "3.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-codec-derive" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "primitive-types" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fixed-hash 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-codec 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "uint 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro-crate" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quote" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "runtime-test" -version = "2.0.0" -dependencies = [ - "sr-io 2.0.0", - "sr-sandbox 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "rustc-hex" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "serde" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "sr-io" -version = "2.0.0" -dependencies = [ - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-std 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "sr-sandbox" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-std 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "sr-std" -version = "2.0.0" -dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "static_assertions" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "substrate-primitives" -version = "2.0.0" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hash256-std-hasher 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "primitive-types 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-std 2.0.0", -] - -[[package]] -name = "syn" -version = "0.15.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "toml" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "uint" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" -"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" -"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" -"checksum crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -"checksum fixed-hash 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d1a683d1234507e4f3bf2736eeddf0de1dc65996dc0164d57eba0a74bcf29489" -"checksum hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ba7fb417e5c470acdd61068c79767d0e65962e70836cf6c9dfd2409f06345ce0" -"checksum hash256-std-hasher 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b2027c19ec91eb304999abae7307d225cf93be42af53b0039f76e98ed5af86" -"checksum impl-codec 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2050d823639fbeae26b2b5ba09aca8907793117324858070ade0673c49f793b" -"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" -"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" -"checksum parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dcb43c05fb71c03b4ea7327bf15694da1e0f23f19d5b1e95bab6c6d74097e336" -"checksum parity-codec-derive 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "00a486fd383382ddcb2de928364b1f82571c1e48274fc43b7667a4738ee4056c" -"checksum primitive-types 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6e8612a8dc70f26276fed6131c153ca277cf275ee0a5e2a50cd8a69c697beb8f" -"checksum proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e" -"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" -"checksum rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "403bb3a286107a04825a5f82e1270acc1e14028d3d554d7a1e08914549575ab8" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)" = "a72e9b96fa45ce22a4bc23da3858dfccfd60acd28a25bcd328a98fdd6bea43fd" -"checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" -"checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe" -"checksum toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8c96d7873fa7ef8bdeb3a9cda3ac48389b4154f32b9803b4bc26220b677b039" -"checksum uint 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2143cded94692b156c356508d92888acc824db5bffc0b4089732264c6fcf86d4" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" diff --git a/core/executor/wasm/build.sh b/core/executor/wasm/build.sh deleted file mode 100755 index 9414c8037b57933d2da64d1f562ffbdfdab32e1f..0000000000000000000000000000000000000000 --- a/core/executor/wasm/build.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -set -e - -if cargo --version | grep -q "nightly"; then - CARGO_CMD="cargo" -else - CARGO_CMD="cargo +nightly" -fi -CARGO_INCREMENTAL=0 RUSTFLAGS="-C link-arg=--export-table" $CARGO_CMD build --target=wasm32-unknown-unknown --release "$@" -for i in test -do - wasm-gc target/wasm32-unknown-unknown/release/runtime_$i.wasm target/wasm32-unknown-unknown/release/runtime_$i.compact.wasm -done diff --git a/core/finality-grandpa/Cargo.toml b/core/finality-grandpa/Cargo.toml index bbd6297d3576e7048c6fcdabcf01f3ce2f2a51cb..3cbb56df81c11df9aacc6759282e6b593723277b 100644 --- a/core/finality-grandpa/Cargo.toml +++ b/core/finality-grandpa/Cargo.toml @@ -5,13 +5,15 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -fork-tree = { path = "../../core/util/fork-tree" } +fork-tree = { path = "../../core/utils/fork-tree" } futures = "0.1" +futures03 = { package = "futures-preview", version = "0.3.0-alpha.17", features = ["compat"] } log = "0.4" parking_lot = "0.8.0" -tokio = "0.1.7" +tokio-executor = "0.1.7" +tokio-timer = "0.2.11" rand = "0.6" -parity-codec = { version = "3.3", features = ["derive"] } +parity-codec = { version = "4.1.1", features = ["derive"] } runtime_primitives = { package = "sr-primitives", path = "../sr-primitives" } consensus_common = { package = "substrate-consensus-common", path = "../consensus/common" } substrate-primitives = { path = "../primitives" } @@ -23,14 +25,15 @@ network = { package = "substrate-network", path = "../network" } service = { package = "substrate-service", path = "../service", optional = true } srml-finality-tracker = { path = "../../srml/finality-tracker" } fg_primitives = { package = "substrate-finality-grandpa-primitives", path = "primitives" } -grandpa = { package = "finality-grandpa", version = "0.7.2", features = ["derive-codec"] } +grandpa = { package = "finality-grandpa", version = "0.8.1", features = ["derive-codec"] } [dev-dependencies] -consensus_common = { package = "substrate-consensus-common", path = "../consensus/common", features = ["test-helpers"] } +grandpa = { package = "finality-grandpa", version = "0.8.1", features = ["derive-codec", "test-helpers"] } network = { package = "substrate-network", path = "../network", features = ["test-helpers"] } keyring = { package = "substrate-keyring", path = "../keyring" } test-client = { package = "substrate-test-runtime-client", path = "../test-runtime/client"} env_logger = "0.6" +tokio = "0.1.17" [features] default = ["service-integration"] diff --git a/core/finality-grandpa/primitives/Cargo.toml b/core/finality-grandpa/primitives/Cargo.toml index 6a36d74b01788489e82407ebf6b62e96c4ac3cb5..4f3b469ca8f179ca27e5ee447727fd6df8947616 100644 --- a/core/finality-grandpa/primitives/Cargo.toml +++ b/core/finality-grandpa/primitives/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] client = { package = "substrate-client", path = "../../client", default-features = false } substrate-primitives = { path = "../../primitives", default-features = false } -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } sr-primitives = { path = "../../sr-primitives", default-features = false } rstd = { package = "sr-std", path = "../../sr-std", default-features = false } serde = { version = "1.0", optional = true, features = ["derive"] } diff --git a/core/finality-grandpa/primitives/src/lib.rs b/core/finality-grandpa/primitives/src/lib.rs index aded32efa36e188a3bf9838523bb06f5830bf59f..f3721d5dcc7ea93f8f180511d99a4f9ac54a4c7c 100644 --- a/core/finality-grandpa/primitives/src/lib.rs +++ b/core/finality-grandpa/primitives/src/lib.rs @@ -23,7 +23,7 @@ extern crate alloc; #[cfg(feature = "std")] use serde::Serialize; -use parity_codec::{Encode, Decode}; +use parity_codec::{Encode, Decode, Codec}; use sr_primitives::{ConsensusEngineId, traits::{DigestFor, NumberFor}}; use client::decl_runtime_apis; use rstd::vec::Vec; @@ -44,16 +44,75 @@ pub const GRANDPA_ENGINE_ID: ConsensusEngineId = *b"FRNK"; /// The weight of an authority. pub type AuthorityWeight = u64; +/// The index of an authority. +pub type AuthorityIndex = u64; + /// A scheduled change of authority set. #[cfg_attr(feature = "std", derive(Debug, Serialize))] #[derive(Clone, Eq, PartialEq, Encode, Decode)] pub struct ScheduledChange { /// The new authorities after the change, along with their respective weights. - pub next_authorities: Vec<(AuthorityId, u64)>, + pub next_authorities: Vec<(AuthorityId, AuthorityWeight)>, /// The number of blocks to delay. pub delay: N, } +/// An consensus log item for GRANDPA. +#[cfg_attr(feature = "std", derive(Serialize, Debug))] +#[derive(Decode, Encode, PartialEq, Eq, Clone)] +pub enum ConsensusLog { + /// Schedule an authority set change. + /// + /// Precedence towards earlier or later digest items can be given + /// based on the rules of the chain. + /// + /// No change should be scheduled if one is already and the delay has not + /// passed completely. + /// + /// This should be a pure function: i.e. as long as the runtime can interpret + /// the digest type it should return the same result regardless of the current + /// state. + #[codec(index = "1")] + ScheduledChange(ScheduledChange), + /// Force an authority set change. + /// + /// Forced changes are applied after a delay of _imported_ blocks, + /// while pending changes are applied after a delay of _finalized_ blocks. + /// + /// Precedence towards earlier or later digest items can be given + /// based on the rules of the chain. + /// + /// No change should be scheduled if one is already and the delay has not + /// passed completely. + /// + /// This should be a pure function: i.e. as long as the runtime can interpret + /// the digest type it should return the same result regardless of the current + /// state. + #[codec(index = "2")] + ForcedChange(N, ScheduledChange), + /// Note that the authority with given index is disabled until the next change. + #[codec(index = "3")] + OnDisabled(AuthorityIndex), +} + +impl ConsensusLog { + /// Try to cast the log entry as a contained signal. + pub fn try_into_change(self) -> Option> { + match self { + ConsensusLog::ScheduledChange(change) => Some(change), + ConsensusLog::ForcedChange(_, _) | ConsensusLog::OnDisabled(_) => None, + } + } + + /// Try to cast the log entry as a contained forced signal. + pub fn try_into_forced_change(self) -> Option<(N, ScheduledChange)> { + match self { + ConsensusLog::ForcedChange(median, change) => Some((median, change)), + ConsensusLog::ScheduledChange(_) | ConsensusLog::OnDisabled(_) => None, + } + } +} + /// WASM function call to check for pending changes. pub const PENDING_CHANGE_CALL: &str = "grandpa_pending_change"; /// WASM function call to get current GRANDPA authorities. diff --git a/core/finality-grandpa/src/communication/gossip.rs b/core/finality-grandpa/src/communication/gossip.rs index ca529125ec172bd2c5ed08a51fd904fe8f304fd2..dfaa96628f2dc43699bd7297247353e50112fdae 100644 --- a/core/finality-grandpa/src/communication/gossip.rs +++ b/core/finality-grandpa/src/communication/gossip.rs @@ -46,7 +46,7 @@ //! #### Propose //! //! This is a broadcast by a known voter of the last-round estimate. - +//! //! #### Commit //! //! These are used to announce past agreement of finality. @@ -58,6 +58,21 @@ //! Sending a commit is polite when it may finalize something that the receiving peer //! was not aware of. //! +//! #### Catch Up +//! +//! These allow a peer to request another peer, which they perceive to be in a +//! later round, to provide all the votes necessary to complete a given round +//! `R`. +//! +//! It is impolite to send a catch up request for a round `R` to a peer whose +//! announced view is behind `R`. It is also impolite to send a catch up request +//! to a peer in a new different Set ID. +//! +//! The logic for issuing and tracking pending catch up requests is implemented +//! in the `GossipValidator`. A catch up request is issued anytime we see a +//! neighbor packet from a peer at a round `CATCH_UP_THRESHOLD` higher than at +//! we are. +//! //! ## Expiration //! //! We keep some amount of recent rounds' messages, but do not accept new ones from rounds @@ -78,13 +93,20 @@ use log::{trace, debug, warn}; use futures::prelude::*; use futures::sync::mpsc; -use crate::{CompactCommit, SignedMessage}; +use crate::{environment, CatchUp, CompactCommit, SignedMessage}; use super::{cost, benefit, Round, SetId}; use std::collections::{HashMap, VecDeque}; use std::time::{Duration, Instant}; const REBROADCAST_AFTER: Duration = Duration::from_secs(60 * 5); +const CATCH_UP_REQUEST_TIMEOUT: Duration = Duration::from_secs(5); +const CATCH_UP_PROCESS_TIMEOUT: Duration = Duration::from_secs(15); +/// Maximum number of rounds we are behind a peer before issuing a +/// catch up request. +const CATCH_UP_THRESHOLD: u64 = 2; + +type Report = (PeerId, i32); /// An outcome of examining a message. #[derive(Debug, PartialEq, Clone, Copy)] @@ -230,6 +252,10 @@ pub(super) enum GossipMessage { Commit(FullCommitMessage), /// A neighbor packet. Not repropagated. Neighbor(VersionedNeighborPacket>), + /// Grandpa catch up request message with round and set info. Not repropagated. + CatchUpRequest(CatchUpRequestMessage), + /// Grandpa catch up message with round and set info. Not repropagated. + CatchUp(FullCatchUpMessage), } impl From>> for GossipMessage { @@ -264,9 +290,12 @@ pub(super) struct FullCommitMessage { /// and are not repropagated. These contain information about the node's state. #[derive(Debug, Encode, Decode, Clone)] pub(super) struct NeighborPacket { - round: Round, - set_id: SetId, - commit_finalized_height: N, + /// The round the node is currently at. + pub(super) round: Round, + /// The set ID the node is currently at. + pub(super) set_id: SetId, + /// The highest finalizing commit observed. + pub(super) commit_finalized_height: N, } /// A versioned neighbor packet. @@ -284,6 +313,24 @@ impl VersionedNeighborPacket { } } +/// A catch up request for a given round (or any further round) localized by set id. +#[derive(Clone, Debug, Encode, Decode)] +pub(super) struct CatchUpRequestMessage { + /// The round that we want to catch up to. + pub(super) round: Round, + /// The voter set ID this message is from. + pub(super) set_id: SetId, +} + +/// Network level catch up message with topic information. +#[derive(Debug, Encode, Decode)] +pub(super) struct FullCatchUpMessage { + /// The voter set ID this message is from. + pub(super) set_id: SetId, + /// The compact commit message. + pub(super) message: CatchUp, +} + /// Misbehavior that peers can perform. /// /// `cost` gives a cost that can be used to perform cost/benefit analysis of a @@ -294,6 +341,10 @@ pub(super) enum Misbehavior { InvalidViewChange, // could not decode neighbor message. bytes-length of the packet. UndecodablePacket(i32), + // Bad catch up message (invalid signatures). + BadCatchUpMessage { + signatures_checked: i32, + }, // Bad commit message BadCommitMessage { signatures_checked: i32, @@ -315,7 +366,9 @@ impl Misbehavior { match *self { InvalidViewChange => cost::INVALID_VIEW_CHANGE, - UndecodablePacket(bytes) => bytes.saturating_mul(cost::PER_UNDECODABLE_BYTE), + UndecodablePacket(bytes) => bytes.saturating_mul(cost::PER_UNDECODABLE_BYTE), + BadCatchUpMessage { signatures_checked } => + cost::PER_SIGNATURE_CHECKED.saturating_mul(signatures_checked), BadCommitMessage { signatures_checked, blocks_loaded, equivocations_caught } => { let cost = cost::PER_SIGNATURE_CHECKED .saturating_mul(signatures_checked) @@ -425,6 +478,23 @@ pub(super) enum Action { Discard(i32), } +/// State of catch up request handling. +#[derive(Debug)] +enum PendingCatchUp { + /// No pending catch up requests. + None, + /// Pending catch up request which has not been answered yet. + Requesting { + who: PeerId, + request: CatchUpRequestMessage, + instant: Instant, + }, + /// Pending catch up request that was answered and is being processed. + Processing { + instant: Instant, + }, +} + struct Inner { local_view: Option>>, peers: Peers>, @@ -432,6 +502,7 @@ struct Inner { authorities: Vec, config: crate::Config, next_rebroadcast: Instant, + pending_catch_up: PendingCatchUp, } type MaybeMessage = Option<(Vec, NeighborPacket>)>; @@ -444,6 +515,7 @@ impl Inner { live_topics: KeepTopics::new(), next_rebroadcast: Instant::now() + REBROADCAST_AFTER, authorities: Vec::new(), + pending_catch_up: PendingCatchUp::None, config, } } @@ -593,18 +665,201 @@ impl Inner { Action::ProcessAndDiscard(topic, benefit::BASIC_VALIDATED_COMMIT) } + fn validate_catch_up_message(&mut self, who: &PeerId, full: &FullCatchUpMessage) + -> Action + { + match &self.pending_catch_up { + PendingCatchUp::Requesting { who: peer, request, instant } => { + if peer != who { + return Action::Discard(Misbehavior::OutOfScopeMessage.cost()); + } + + if request.set_id != full.set_id { + return Action::Discard(cost::MALFORMED_CATCH_UP); + } + + if request.round.0 > full.message.round_number { + return Action::Discard(cost::MALFORMED_CATCH_UP); + } + + if full.message.prevotes.is_empty() || full.message.precommits.is_empty() { + return Action::Discard(cost::MALFORMED_CATCH_UP); + } + + // move request to pending processing state, we won't push out + // any catch up requests until we import this one (either with a + // success or failure). + self.pending_catch_up = PendingCatchUp::Processing { + instant: instant.clone(), + }; + + // always discard catch up messages, they're point-to-point + let topic = super::global_topic::(full.set_id.0); + Action::ProcessAndDiscard(topic, benefit::BASIC_VALIDATED_CATCH_UP) + }, + _ => Action::Discard(Misbehavior::OutOfScopeMessage.cost()), + } + } + + fn note_catch_up_message_processed(&mut self) { + match &self.pending_catch_up { + PendingCatchUp::Processing { .. } => { + self.pending_catch_up = PendingCatchUp::None; + }, + state => trace!(target: "afg", + "Noted processed catch up message when state was: {:?}", + state, + ), + } + } + + fn handle_catch_up_request( + &mut self, + who: &PeerId, + request: CatchUpRequestMessage, + set_state: &environment::SharedVoterSetState, + ) -> (Option>, Action) { + let local_view = match self.local_view { + None => return (None, Action::Discard(Misbehavior::OutOfScopeMessage.cost())), + Some(ref view) => view, + }; + + if request.set_id != local_view.set_id { + // NOTE: When we're close to a set change there is potentially a + // race where the peer sent us the request before it observed that + // we had transitioned to a new set. In this case we charge a lower + // cost. + if local_view.round.0.saturating_sub(CATCH_UP_THRESHOLD) == 0 { + return (None, Action::Discard(cost::HONEST_OUT_OF_SCOPE_CATCH_UP)); + } + + return (None, Action::Discard(Misbehavior::OutOfScopeMessage.cost())); + } + + match self.peers.peer(who) { + None => + return (None, Action::Discard(Misbehavior::OutOfScopeMessage.cost())), + Some(peer) if peer.view.round >= request.round => + return (None, Action::Discard(Misbehavior::OutOfScopeMessage.cost())), + _ => {}, + } + + let last_completed_round = set_state.read().last_completed_round(); + if last_completed_round.number < request.round.0 { + return (None, Action::Discard(Misbehavior::OutOfScopeMessage.cost())); + } + + trace!(target: "afg", "Replying to catch-up request for round {} from {} with round {}", + request.round.0, + who, + last_completed_round.number, + ); + + let mut prevotes = Vec::new(); + let mut precommits = Vec::new(); + + // NOTE: the set of votes stored in `LastCompletedRound` is a minimal + // set of votes, i.e. at most one equivocation is stored per voter. The + // code below assumes this invariant is maintained when creating the + // catch up reply since peers won't accept catch-up messages that have + // too many equivocations (we exceed the fault-tolerance bound). + for vote in last_completed_round.votes { + match vote.message { + grandpa::Message::Prevote(prevote) => { + prevotes.push(grandpa::SignedPrevote { + prevote, + signature: vote.signature, + id: vote.id, + }); + }, + grandpa::Message::Precommit(precommit) => { + precommits.push(grandpa::SignedPrecommit { + precommit, + signature: vote.signature, + id: vote.id, + }); + }, + _ => {}, + } + } + + let (base_hash, base_number) = last_completed_round.base; + + let catch_up = CatchUp:: { + round_number: last_completed_round.number, + prevotes, + precommits, + base_hash, + base_number, + }; + + let full_catch_up = GossipMessage::CatchUp::(FullCatchUpMessage { + set_id: request.set_id, + message: catch_up, + }); + + (Some(full_catch_up), Action::Discard(cost::CATCH_UP_REPLY)) + } + + fn try_catch_up(&mut self, who: &PeerId) -> (Option>, Option) { + let mut catch_up = None; + let mut report = None; + + // if the peer is on the same set and ahead of us by a margin bigger + // than `CATCH_UP_THRESHOLD` then we should ask it for a catch up + // message. + if let (Some(peer), Some(local_view)) = (self.peers.peer(who), &self.local_view) { + if peer.view.set_id == local_view.set_id && + peer.view.round.0.saturating_sub(CATCH_UP_THRESHOLD) > local_view.round.0 + { + // send catch up request if allowed + let round = peer.view.round.0 - 1; // peer.view.round is > 0 + let request = CatchUpRequestMessage { + set_id: peer.view.set_id, + round: Round(round), + }; + + let (catch_up_allowed, catch_up_report) = self.note_catch_up_request(who, &request); + + if catch_up_allowed { + trace!(target: "afg", "Sending catch-up request for round {} to {}", + round, + who, + ); + + catch_up = Some(GossipMessage::::CatchUpRequest(request)); + } + + report = catch_up_report; + } + } + + (catch_up, report) + } + fn import_neighbor_message(&mut self, who: &PeerId, update: NeighborPacket>) - -> (Vec, Action) + -> (Vec, Action, Option>, Option) { - let (cb, topics) = match self.peers.update_peer_state(who, update) { - Ok(view) => (100i32, view.map(|view| neighbor_topics::(view))), - Err(misbehavior) => (misbehavior.cost(), None) + let update_res = self.peers.update_peer_state(who, update); + + let (cost_benefit, topics) = match update_res { + Ok(view) => + (benefit::NEIGHBOR_MESSAGE, view.map(|view| neighbor_topics::(view))), + Err(misbehavior) => + (misbehavior.cost(), None), + }; + + let (catch_up, report) = match update_res { + Ok(_) => self.try_catch_up(who), + _ => (None, None), }; let neighbor_topics = topics.unwrap_or_default(); - // always discard, it's valid for one hop. - (neighbor_topics, Action::Discard(cb)) + // always discard neighbor messages, it's only valid for one hop. + let action = Action::Discard(cost_benefit); + + (neighbor_topics, action, catch_up, report) } fn multicast_neighbor_packet(&self) -> MaybeMessage { @@ -619,20 +874,55 @@ impl Inner { (peers, packet) }) } + + fn note_catch_up_request( + &mut self, + who: &PeerId, + catch_up_request: &CatchUpRequestMessage, + ) -> (bool, Option) { + let report = match &self.pending_catch_up { + PendingCatchUp::Requesting { who: peer, instant, .. } => + if instant.elapsed() <= CATCH_UP_REQUEST_TIMEOUT { + return (false, None); + } else { + // report peer for timeout + Some((peer.clone(), cost::CATCH_UP_REQUEST_TIMEOUT)) + }, + PendingCatchUp::Processing { instant, .. } => + if instant.elapsed() < CATCH_UP_PROCESS_TIMEOUT { + return (false, None); + } else { + None + }, + _ => None, + }; + + self.pending_catch_up = PendingCatchUp::Requesting { + who: who.clone(), + request: catch_up_request.clone(), + instant: Instant::now(), + }; + + (true, report) + } } /// A validator for GRANDPA gossip messages. pub(super) struct GossipValidator { inner: parking_lot::RwLock>, + set_state: environment::SharedVoterSetState, report_sender: mpsc::UnboundedSender, } impl GossipValidator { /// Create a new gossip-validator. This initialized the current set to 0. - pub(super) fn new(config: crate::Config) -> (GossipValidator, ReportStream) { + pub(super) fn new(config: crate::Config, set_state: environment::SharedVoterSetState) + -> (GossipValidator, ReportStream) + { let (tx, rx) = mpsc::unbounded(); let val = GossipValidator { inner: parking_lot::RwLock::new(Inner::new(config)), + set_state, report_sender: tx, }; @@ -670,26 +960,50 @@ impl GossipValidator { } } + /// Note that we've processed a catch up message. + pub(super) fn note_catch_up_message_processed(&self) { + self.inner.write().note_catch_up_message_processed(); + } + fn report(&self, who: PeerId, cost_benefit: i32) { let _ = self.report_sender.unbounded_send(PeerReport { who, cost_benefit }); } pub(super) fn do_validate(&self, who: &PeerId, mut data: &[u8]) - -> (Action, Vec) + -> (Action, Vec, Option>) { let mut broadcast_topics = Vec::new(); + let mut peer_reply = None; + let action = { match GossipMessage::::decode(&mut data) { Some(GossipMessage::VoteOrPrecommit(ref message)) => self.inner.write().validate_round_message(who, message), Some(GossipMessage::Commit(ref message)) => self.inner.write().validate_commit_message(who, message), Some(GossipMessage::Neighbor(update)) => { - let (topics, action) = self.inner.write().import_neighbor_message( + let (topics, action, catch_up, report) = self.inner.write().import_neighbor_message( who, update.into_neighbor_packet(), ); + if let Some((peer, cost_benefit)) = report { + self.report(peer, cost_benefit); + } + broadcast_topics = topics; + peer_reply = catch_up; + action + } + Some(GossipMessage::CatchUp(ref message)) + => self.inner.write().validate_catch_up_message(who, message), + Some(GossipMessage::CatchUpRequest(request)) => { + let (reply, action) = self.inner.write().handle_catch_up_request( + who, + request, + &self.set_state, + ); + + peer_reply = reply; action } None => { @@ -702,7 +1016,7 @@ impl GossipValidator { } }; - (action, broadcast_topics) + (action, broadcast_topics, peer_reply) } } @@ -734,9 +1048,13 @@ impl network_gossip::Validator for GossipValidator fn validate(&self, context: &mut dyn ValidatorContext, who: &PeerId, data: &[u8]) -> network_gossip::ValidationResult { - let (action, broadcast_topics) = self.do_validate(who, data); + let (action, broadcast_topics, peer_reply) = self.do_validate(who, data); // not with lock held! + if let Some(msg) = peer_reply { + context.send_message(who, msg.encode()); + } + for topic in broadcast_topics { context.send_topic(who, topic, false); } @@ -817,6 +1135,8 @@ impl network_gossip::Validator for GossipValidator && Some(full.message.target_number) > peer_best_commit } Some(GossipMessage::Neighbor(_)) => false, + Some(GossipMessage::CatchUpRequest(_)) => false, + Some(GossipMessage::CatchUp(_)) => false, Some(GossipMessage::VoteOrPrecommit(_)) => false, // should not be the case. } }) @@ -910,6 +1230,7 @@ impl> Future for ReportingTask { #[cfg(test)] mod tests { use super::*; + use super::environment::SharedVoterSetState; use network_gossip::Validator as GossipValidatorT; use network::test::Block; @@ -923,6 +1244,33 @@ mod tests { } } + // dummy voter set state + fn voter_set_state() -> SharedVoterSetState { + use crate::authorities::AuthoritySet; + use crate::environment::{CompletedRound, CompletedRounds, HasVoted, VoterSetState}; + use grandpa::round::State as RoundState; + use substrate_primitives::H256; + + let state = RoundState::genesis((H256::zero(), 0)); + let base = state.prevote_ghost.unwrap(); + let voters = AuthoritySet::genesis(Vec::new()); + let set_state = VoterSetState::Live { + completed_rounds: CompletedRounds::new( + CompletedRound { + state, + number: 0, + votes: Vec::new(), + base, + }, + 0, + &voters, + ), + current_round: HasVoted::No, + }; + + set_state.into() + } + #[test] fn view_vote_rules() { let view = View { round: Round(100), set_id: SetId(1), last_commit: Some(1000u64) }; @@ -1064,7 +1412,10 @@ mod tests { #[test] fn messages_not_expired_immediately() { - let (val, _) = GossipValidator::::new(config()); + let (val, _) = GossipValidator::::new( + config(), + voter_set_state(), + ); let set_id = 1; @@ -1096,7 +1447,10 @@ mod tests { fn message_from_unknown_authority_discarded() { assert!(cost::UNKNOWN_VOTER != cost::BAD_SIGNATURE); - let (val, _) = GossipValidator::::new(config()); + let (val, _) = GossipValidator::::new( + config(), + voter_set_state(), + ); let set_id = 1; let auth = AuthorityId::from_raw([1u8; 32]); let peer = PeerId::random(); @@ -1134,4 +1488,122 @@ mod tests { assert_eq!(unknown_voter, Action::Discard(cost::UNKNOWN_VOTER)); assert_eq!(bad_sig, Action::Discard(cost::BAD_SIGNATURE)); } + + #[test] + fn unsolicited_catch_up_messages_discarded() { + let (val, _) = GossipValidator::::new( + config(), + voter_set_state(), + ); + + let set_id = 1; + let auth = AuthorityId::from_raw([1u8; 32]); + let peer = PeerId::random(); + + val.note_set(SetId(set_id), vec![auth.clone()], |_, _| {}); + val.note_round(Round(0), |_, _| {}); + + let validate_catch_up = || { + let mut inner = val.inner.write(); + inner.validate_catch_up_message(&peer, &FullCatchUpMessage { + set_id: SetId(set_id), + message: grandpa::CatchUp { + round_number: 10, + prevotes: Default::default(), + precommits: Default::default(), + base_hash: Default::default(), + base_number: Default::default(), + } + }) + }; + + // the catch up is discarded because we have no pending request + assert_eq!(validate_catch_up(), Action::Discard(cost::OUT_OF_SCOPE_MESSAGE)); + + let noted = val.inner.write().note_catch_up_request( + &peer, + &CatchUpRequestMessage { + set_id: SetId(set_id), + round: Round(10), + } + ); + + assert!(noted.0); + + // catch up is allowed because we have requested it, but it's rejected + // because it's malformed (empty prevotes and precommits) + assert_eq!(validate_catch_up(), Action::Discard(cost::MALFORMED_CATCH_UP)); + } + + #[test] + fn unanswerable_catch_up_requests_discarded() { + // create voter set state with round 1 completed + let set_state: SharedVoterSetState = { + let mut completed_rounds = voter_set_state().read().completed_rounds(); + + assert!(completed_rounds.push(environment::CompletedRound { + number: 1, + state: grandpa::round::State::genesis(Default::default()), + base: Default::default(), + votes: Default::default(), + })); + + let set_state = environment::VoterSetState::::Live { + completed_rounds, + current_round: environment::HasVoted::No, + }; + + set_state.into() + }; + + let (val, _) = GossipValidator::::new( + config(), + set_state.clone(), + ); + + let set_id = 1; + let auth = AuthorityId::from_raw([1u8; 32]); + let peer = PeerId::random(); + + val.note_set(SetId(set_id), vec![auth.clone()], |_, _| {}); + val.note_round(Round(2), |_, _| {}); + + // add the peer making the request to the validator, + // otherwise it is discarded + let mut inner = val.inner.write(); + inner.peers.new_peer(peer.clone()); + + let res = inner.handle_catch_up_request( + &peer, + CatchUpRequestMessage { + set_id: SetId(set_id), + round: Round(10), + }, + &set_state, + ); + + // we're at round 2, a catch up request for round 10 is out of scope + assert!(res.0.is_none()); + assert_eq!(res.1, Action::Discard(cost::OUT_OF_SCOPE_MESSAGE)); + + let res = inner.handle_catch_up_request( + &peer, + CatchUpRequestMessage { + set_id: SetId(set_id), + round: Round(1), + }, + &set_state, + ); + + // a catch up request for round 1 should be answered successfully + match res.0.unwrap() { + GossipMessage::CatchUp(catch_up) => { + assert_eq!(catch_up.set_id, SetId(set_id)); + assert_eq!(catch_up.message.round_number, 1); + + assert_eq!(res.1, Action::Discard(cost::CATCH_UP_REPLY)); + }, + _ => panic!("expected catch up message"), + }; + } } diff --git a/core/finality-grandpa/src/communication/mod.rs b/core/finality-grandpa/src/communication/mod.rs index 0633fcec1f6df9c8995c914a3d1c0d44d62c328d..4707dede78d65cd6b3e618d367479c985f847c43 100644 --- a/core/finality-grandpa/src/communication/mod.rs +++ b/core/finality-grandpa/src/communication/mod.rs @@ -29,11 +29,12 @@ use std::sync::Arc; -use grandpa::voter_set::VoterSet; +use grandpa::{voter, voter_set::VoterSet}; use grandpa::Message::{Prevote, Precommit, PrimaryPropose}; use futures::prelude::*; use futures::sync::{oneshot, mpsc}; use log::{debug, trace}; +use tokio_executor::Executor; use parity_codec::{Encode, Decode}; use substrate_primitives::{ed25519, Pair}; use substrate_telemetry::{telemetry, CONSENSUS_DEBUG, CONSENSUS_INFO}; @@ -41,10 +42,13 @@ use runtime_primitives::traits::{Block as BlockT, Hash as HashT, Header as Heade use network::{consensus_gossip as network_gossip, NetworkService}; use network_gossip::ConsensusMessage; -use crate::{Error, Message, SignedMessage, Commit, CompactCommit}; +use crate::{ + CatchUp, Commit, CommunicationIn, CommunicationOut, CompactCommit, Error, + Message, SignedMessage, +}; use crate::environment::HasVoted; use gossip::{ - GossipMessage, FullCommitMessage, VoteOrPrecommitMessage, GossipValidator + GossipMessage, FullCatchUpMessage, FullCommitMessage, VoteOrPrecommitMessage, GossipValidator }; use substrate_primitives::ed25519::{Public as AuthorityId, Signature as AuthoritySignature}; @@ -60,6 +64,7 @@ pub use fg_primitives::GRANDPA_ENGINE_ID; mod cost { pub(super) const PAST_REJECTION: i32 = -50; pub(super) const BAD_SIGNATURE: i32 = -100; + pub(super) const MALFORMED_CATCH_UP: i32 = -1000; pub(super) const MALFORMED_COMMIT: i32 = -1000; pub(super) const FUTURE_MESSAGE: i32 = -500; pub(super) const UNKNOWN_VOTER: i32 = -150; @@ -68,13 +73,21 @@ mod cost { pub(super) const PER_UNDECODABLE_BYTE: i32 = -5; pub(super) const PER_SIGNATURE_CHECKED: i32 = -25; pub(super) const PER_BLOCK_LOADED: i32 = -10; + pub(super) const INVALID_CATCH_UP: i32 = -5000; pub(super) const INVALID_COMMIT: i32 = -5000; pub(super) const OUT_OF_SCOPE_MESSAGE: i32 = -500; + pub(super) const CATCH_UP_REQUEST_TIMEOUT: i32 = -200; + + // cost of answering a catch up request + pub(super) const CATCH_UP_REPLY: i32 = -200; + pub(super) const HONEST_OUT_OF_SCOPE_CATCH_UP: i32 = -200; } // benefit scalars for reporting peers. mod benefit { + pub(super) const NEIGHBOR_MESSAGE: i32 = 100; pub(super) const ROUND_MESSAGE: i32 = 100; + pub(super) const BASIC_VALIDATED_CATCH_UP: i32 = 200; pub(super) const BASIC_VALIDATED_COMMIT: i32 = 100; pub(super) const PER_EQUIVOCATION: i32 = 10; } @@ -125,9 +138,10 @@ pub(crate) fn global_topic(set_id: u64) -> B::Hash { <::Hashing as HashT>::hash(format!("{}-GLOBAL", set_id).as_bytes()) } -impl Network for Arc> where +impl Network for Arc> where B: BlockT, S: network::specialization::NetworkSpecialization, + H: network::ExHashT, { type In = NetworkStream; @@ -212,12 +226,6 @@ impl Stream for NetworkStream { } } -/// The result of processing a commit. -pub(crate) enum CommitProcessingOutcome { - Good, - Bad, -} - /// Bridge between the underlying network service, gossiping consensus messages and Grandpa pub(crate) struct NetworkBridge> { service: N, @@ -233,21 +241,21 @@ impl> NetworkBridge { pub(crate) fn new( service: N, config: crate::Config, - set_state: Option<&crate::environment::VoterSetState>, + set_state: crate::environment::SharedVoterSetState, on_exit: impl Future + Clone + Send + 'static, ) -> ( Self, impl futures::Future + Send + 'static, ) { - let (validator, report_stream) = GossipValidator::new(config); + let (validator, report_stream) = GossipValidator::new(config, set_state.clone()); let validator = Arc::new(validator); service.register_validator(validator.clone()); - if let Some(set_state) = set_state { + { // register all previous votes with the gossip service so that they're // available to peers potentially stuck on a previous round. - let completed = set_state.completed_rounds(); + let completed = set_state.read().completed_rounds(); let (set_id, voters) = completed.set_info(); validator.note_set(SetId(set_id), voters.to_vec(), |_, _| {}); for round in completed.iter() { @@ -290,25 +298,23 @@ impl> NetworkBridge { let startup_work = futures::future::lazy(move || { // lazily spawn these jobs onto their own tasks. the lazy future has access // to tokio globals, which aren't available outside. - tokio::spawn(rebroadcast_job.select(on_exit.clone()).then(|_| Ok(()))); - tokio::spawn(reporting_job.select(on_exit.clone()).then(|_| Ok(()))); + let mut executor = tokio_executor::DefaultExecutor::current(); + executor.spawn(Box::new(rebroadcast_job.select(on_exit.clone()).then(|_| Ok(())))) + .expect("failed to spawn grandpa rebroadcast job task"); + executor.spawn(Box::new(reporting_job.select(on_exit.clone()).then(|_| Ok(())))) + .expect("failed to spawn grandpa reporting job task"); Ok(()) }); (bridge, startup_work) } - /// Get the round messages for a round in the current set ID. These are signature-checked. - pub(crate) fn round_communication( + /// Note the beginning of a new round to the `GossipValidator`. + pub(crate) fn note_round( &self, round: Round, set_id: SetId, - voters: Arc>, - local_key: Option>, - has_voted: HasVoted, - ) -> ( - impl Stream,Error=Error>, - impl Sink,SinkError=Error>, + voters: &VoterSet, ) { // is a no-op if currently in that set. self.validator.note_set( @@ -327,6 +333,25 @@ impl> NetworkBridge { GossipMessage::::from(neighbor).encode() ), ); + } + + /// Get the round messages for a round in the current set ID. These are signature-checked. + pub(crate) fn round_communication( + &self, + round: Round, + set_id: SetId, + voters: Arc>, + local_key: Option>, + has_voted: HasVoted, + ) -> ( + impl Stream,Error=Error>, + impl Sink,SinkError=Error>, + ) { + self.note_round( + round, + set_id, + &*voters, + ); let locals = local_key.and_then(|pair| { let public = pair.public(); @@ -417,8 +442,8 @@ impl> NetworkBridge { voters: Arc>, is_voter: bool, ) -> ( - impl Stream, impl FnMut(CommitProcessingOutcome)), Error = Error>, - impl Sink), SinkError = Error>, + impl Stream, Error = Error>, + impl Sink, SinkError = Error>, ) { self.validator.note_set( set_id, @@ -437,16 +462,123 @@ impl> NetworkBridge { self.validator.clone(), ); + let outgoing = outgoing.with(|out| { + let voter::CommunicationOut::Commit(round, commit) = out; + Ok((round, commit)) + }); + (incoming, outgoing) } } fn incoming_global>( - service: N, + mut service: N, topic: B::Hash, voters: Arc>, gossip_validator: Arc>, -) -> impl Stream, impl FnMut(CommitProcessingOutcome)), Error = Error> { +) -> impl Stream, Error = Error> { + let process_commit = move | + msg: FullCommitMessage, + mut notification: network_gossip::TopicNotification, + service: &mut N, + gossip_validator: &Arc>, + voters: &VoterSet, + | { + let precommits_signed_by: Vec = + msg.message.auth_data.iter().map(move |(_, a)| { + format!("{}", a) + }).collect(); + + telemetry!(CONSENSUS_INFO; "afg.received_commit"; + "contains_precommits_signed_by" => ?precommits_signed_by, + "target_number" => ?msg.message.target_number.clone(), + "target_hash" => ?msg.message.target_hash.clone(), + ); + + if let Err(cost) = check_compact_commit::( + &msg.message, + voters, + msg.round, + msg.set_id, + ) { + if let Some(who) = notification.sender { + service.report(who, cost); + } + + return None; + } + + let round = msg.round.0; + let commit = msg.message; + let finalized_number = commit.target_number; + let gossip_validator = gossip_validator.clone(); + let service = service.clone(); + let cb = move |outcome| match outcome { + voter::CommitProcessingOutcome::Good(_) => { + // if it checks out, gossip it. not accounting for + // any discrepancy between the actual ghost and the claimed + // finalized number. + gossip_validator.note_commit_finalized( + finalized_number, + |to, neighbor_msg| service.send_message( + to, + GossipMessage::::from(neighbor_msg).encode(), + ), + ); + + service.gossip_message(topic, notification.message.clone(), false); + } + voter::CommitProcessingOutcome::Bad(_) => { + // report peer and do not gossip. + if let Some(who) = notification.sender.take() { + service.report(who, cost::INVALID_COMMIT); + } + } + }; + + let cb = voter::Callback::Work(Box::new(cb)); + + Some(voter::CommunicationIn::Commit(round, commit, cb)) + }; + + let process_catch_up = move | + msg: FullCatchUpMessage, + mut notification: network_gossip::TopicNotification, + service: &mut N, + gossip_validator: &Arc>, + voters: &VoterSet, + | { + let gossip_validator = gossip_validator.clone(); + let service = service.clone(); + + if let Err(cost) = check_catch_up::( + &msg.message, + voters, + msg.set_id, + ) { + if let Some(who) = notification.sender { + service.report(who, cost); + } + + return None; + } + + let cb = move |outcome| { + if let voter::CatchUpProcessingOutcome::Bad(_) = outcome { + // report peer + if let Some(who) = notification.sender.take() { + service.report(who, cost::INVALID_CATCH_UP); + } + } + + gossip_validator.note_catch_up_message_processed(); + }; + + let cb = voter::Callback::Work(Box::new(cb)); + + Some(voter::CommunicationIn::CatchUp(msg.message, cb)) + }; + service.messages_for(topic) .filter_map(|notification| { // this could be optimized by decoding piecewise. @@ -458,66 +590,16 @@ fn incoming_global>( }) .filter_map(move |(notification, msg)| { match msg { - GossipMessage::Commit(msg) => { - let precommits_signed_by: Vec = - msg.message.auth_data.iter().map(move |(_, a)| { - format!("{}", a) - }).collect(); - telemetry!(CONSENSUS_INFO; "afg.received_commit"; - "contains_precommits_signed_by" => ?precommits_signed_by, - "target_number" => ?msg.message.target_number.clone(), - "target_hash" => ?msg.message.target_hash.clone(), - ); - if let Err(cost) = check_compact_commit::( - &msg.message, - &*voters, - msg.round, - msg.set_id, - ) { - if let Some(who) = notification.sender { - service.report(who, cost); - } - None - } else { - Some((msg, notification, service.clone())) - } - }, + GossipMessage::Commit(msg) => + process_commit(msg, notification, &mut service, &gossip_validator, &*voters), + GossipMessage::CatchUp(msg) => + process_catch_up(msg, notification, &mut service, &gossip_validator, &*voters), _ => { debug!(target: "afg", "Skipping unknown message type"); return None; } } }) - .map(move |(msg, mut notification, service)| { - let round = msg.round.0; - let commit = msg.message; - let finalized_number = commit.target_number; - let gossip_validator = gossip_validator.clone(); - let cb = move |outcome| match outcome { - CommitProcessingOutcome::Good => { - // if it checks out, gossip it. not accounting for - // any discrepancy between the actual ghost and the claimed - // finalized number. - gossip_validator.note_commit_finalized( - finalized_number, - |to, neighbor_msg| service.send_message( - to, - GossipMessage::::from(neighbor_msg).encode(), - ), - ); - - service.gossip_message(topic, notification.message.clone(), false); - } - CommitProcessingOutcome::Bad => { - // report peer and do not gossip. - if let Some(who) = notification.sender.take() { - service.report(who, cost::INVALID_COMMIT); - } - } - }; - - (round, commit, cb) - }) .map_err(|()| Error::Network(format!("Failed to receive message on unbounded stream"))) } @@ -652,7 +734,8 @@ impl> Sink for OutgoingMessages } } -// checks a compact commit. returns `None` if it was bad and +// checks a compact commit. returns the cost associated with processing it if +// the commit was bad. fn check_compact_commit( msg: &CompactCommit, voters: &VoterSet, @@ -711,6 +794,114 @@ fn check_compact_commit( Ok(()) } +// checks a catch up. returns the cost associated with processing it if +// the catch up was bad. +fn check_catch_up( + msg: &CatchUp, + voters: &VoterSet, + set_id: SetId, +) -> Result<(), i32> { + // 4f + 1 = equivocations from f voters. + let f = voters.total_weight() - voters.threshold(); + let full_threshold = voters.total_weight() + f; + + // check total weight is not out of range for a set of votes. + fn check_weight<'a>( + voters: &'a VoterSet, + votes: impl Iterator, + full_threshold: u64, + ) -> Result<(), i32> { + let mut total_weight = 0; + + for id in votes { + if let Some(weight) = voters.info(&id).map(|info| info.weight()) { + total_weight += weight; + if total_weight > full_threshold { + return Err(cost::MALFORMED_CATCH_UP); + } + } else { + debug!(target: "afg", "Skipping catch up message containing unknown voter {}", id); + return Err(cost::MALFORMED_CATCH_UP); + } + } + + if total_weight < voters.threshold() { + return Err(cost::MALFORMED_CATCH_UP); + } + + Ok(()) + }; + + check_weight( + voters, + msg.prevotes.iter().map(|vote| &vote.id), + full_threshold, + )?; + + check_weight( + voters, + msg.precommits.iter().map(|vote| &vote.id), + full_threshold, + )?; + + fn check_signatures<'a, B, I>( + messages: I, + round: u64, + set_id: u64, + mut signatures_checked: usize, + ) -> Result where + B: BlockT, + I: Iterator, &'a AuthorityId, &'a AuthoritySignature)>, + { + use crate::communication::gossip::Misbehavior; + + for (msg, id, sig) in messages { + signatures_checked += 1; + + if let Err(()) = check_message_sig::( + &msg, + id, + sig, + round, + set_id, + ) { + debug!(target: "afg", "Bad catch up message signature {}", id); + telemetry!(CONSENSUS_DEBUG; "afg.bad_catch_up_msg_signature"; "id" => ?id); + + let cost = Misbehavior::BadCatchUpMessage { + signatures_checked: signatures_checked as i32, + }.cost(); + + return Err(cost); + } + } + + Ok(signatures_checked) + } + + // check signatures on all contained prevotes. + let signatures_checked = check_signatures::( + msg.prevotes.iter().map(|vote| { + (grandpa::Message::Prevote(vote.prevote.clone()), &vote.id, &vote.signature) + }), + msg.round_number, + set_id.0, + 0, + )?; + + // check signatures on all contained precommits. + let _ = check_signatures::( + msg.precommits.iter().map(|vote| { + (grandpa::Message::Precommit(vote.precommit.clone()), &vote.id, &vote.signature) + }), + msg.round_number, + set_id.0, + signatures_checked, + )?; + + Ok(()) +} + /// An output sink for commit messages. struct CommitsOut> { network: N, diff --git a/core/finality-grandpa/src/communication/periodic.rs b/core/finality-grandpa/src/communication/periodic.rs index c6121370421bccefffb524e5afb3c9929a36e6f6..8490ff2f794ebcd789b8cb05ec46c029b7771838 100644 --- a/core/finality-grandpa/src/communication/periodic.rs +++ b/core/finality-grandpa/src/communication/periodic.rs @@ -21,7 +21,7 @@ use futures::prelude::*; use futures::sync::mpsc; use runtime_primitives::traits::{NumberFor, Block as BlockT}; use network::PeerId; -use tokio::timer::Delay; +use tokio_timer::Delay; use log::warn; use parity_codec::Encode; diff --git a/core/finality-grandpa/src/communication/tests.rs b/core/finality-grandpa/src/communication/tests.rs index f2b50ab80c2b6288db97a6416da27612b67f9a74..5760b3936cd987ea79c65cc07b781be2205d5a93 100644 --- a/core/finality-grandpa/src/communication/tests.rs +++ b/core/finality-grandpa/src/communication/tests.rs @@ -26,6 +26,7 @@ use std::sync::Arc; use keyring::AuthorityKeyring; use parity_codec::Encode; +use crate::environment::SharedVoterSetState; use super::gossip::{self, GossipValidator}; use super::{AuthorityId, VoterSet, Round, SetId}; @@ -92,6 +93,18 @@ impl super::Network for TestNetwork { } } +impl network_gossip::ValidatorContext for TestNetwork { + fn broadcast_topic(&mut self, _: Hash, _: bool) { } + + fn broadcast_message(&mut self, _: Hash, _: Vec, _: bool) { } + + fn send_message(&mut self, who: &network::PeerId, data: Vec) { + >::send_message(self, vec![who.clone()], data); + } + + fn send_topic(&mut self, _: &network::PeerId, _: Hash, _: bool) { } +} + struct Tester { net_handle: super::NetworkBridge, gossip_validator: Arc>, @@ -125,8 +138,38 @@ fn config() -> crate::Config { } } +// dummy voter set state +fn voter_set_state() -> SharedVoterSetState { + use crate::authorities::AuthoritySet; + use crate::environment::{CompletedRound, CompletedRounds, HasVoted, VoterSetState}; + use grandpa::round::State as RoundState; + use substrate_primitives::H256; + + let state = RoundState::genesis((H256::zero(), 0)); + let base = state.prevote_ghost.unwrap(); + let voters = AuthoritySet::genesis(Vec::new()); + let set_state = VoterSetState::Live { + completed_rounds: CompletedRounds::new( + CompletedRound { + state, + number: 0, + votes: Vec::new(), + base, + }, + 0, + &voters, + ), + current_round: HasVoted::No, + }; + + set_state.into() +} + // needs to run in a tokio runtime. -fn make_test_network() -> impl Future { +fn make_test_network() -> ( + impl Future, + TestNetwork, +) { let (tx, rx) = mpsc::unbounded(); let net = TestNetwork { sender: tx }; @@ -145,15 +188,18 @@ fn make_test_network() -> impl Future { let (bridge, startup_work) = super::NetworkBridge::new( net.clone(), config(), - None, + voter_set_state(), Exit, ); - startup_work.map(move |()| Tester { - gossip_validator: bridge.validator.clone(), - net_handle: bridge, - events: rx, - }) + ( + startup_work.map(move |()| Tester { + gossip_validator: bridge.validator.clone(), + net_handle: bridge, + events: rx, + }), + net, + ) } fn make_ids(keys: &[AuthorityKeyring]) -> Vec<(AuthorityId, u64)> { @@ -217,7 +263,7 @@ fn good_commit_leads_to_relay() { let id = network::PeerId::random(); let global_topic = super::global_topic::(set_id); - let test = make_test_network() + let test = make_test_network().0 .and_then(move |tester| { // register a peer. tester.gossip_validator.new_peer(&mut NoopContext, &id, network::config::Roles::FULL); @@ -228,7 +274,7 @@ fn good_commit_leads_to_relay() { let (commits_in, _) = tester.net_handle.global_communication(SetId(1), voter_set, false); { - let (action, _) = tester.gossip_validator.do_validate(&id, &encoded_commit[..]); + let (action, ..) = tester.gossip_validator.do_validate(&id, &encoded_commit[..]); match action { gossip::Action::ProcessAndDiscard(t, _) => assert_eq!(t, global_topic), _ => panic!("wrong expected outcome from initial commit validation"), @@ -257,8 +303,12 @@ fn good_commit_leads_to_relay() { // when the commit comes in, we'll tell the callback it was good. let handle_commit = commits_in.into_future() .map(|(item, _)| { - let (_, _, mut callback) = item.unwrap(); - (callback)(super::CommitProcessingOutcome::Good); + match item.unwrap() { + grandpa::voter::CommunicationIn::Commit(_, _, mut callback) => { + callback.run(grandpa::voter::CommitProcessingOutcome::good()); + }, + _ => panic!("commit expected"), + } }) .map_err(|_| panic!("could not process commit")); @@ -328,7 +378,7 @@ fn bad_commit_leads_to_report() { let id = network::PeerId::random(); let global_topic = super::global_topic::(set_id); - let test = make_test_network() + let test = make_test_network().0 .and_then(move |tester| { // register a peer. tester.gossip_validator.new_peer(&mut NoopContext, &id, network::config::Roles::FULL); @@ -339,7 +389,7 @@ fn bad_commit_leads_to_report() { let (commits_in, _) = tester.net_handle.global_communication(SetId(1), voter_set, false); { - let (action, _) = tester.gossip_validator.do_validate(&id, &encoded_commit[..]); + let (action, ..) = tester.gossip_validator.do_validate(&id, &encoded_commit[..]); match action { gossip::Action::ProcessAndDiscard(t, _) => assert_eq!(t, global_topic), _ => panic!("wrong expected outcome from initial commit validation"), @@ -368,8 +418,12 @@ fn bad_commit_leads_to_report() { // when the commit comes in, we'll tell the callback it was good. let handle_commit = commits_in.into_future() .map(|(item, _)| { - let (_, _, mut callback) = item.unwrap(); - (callback)(super::CommitProcessingOutcome::Bad); + match item.unwrap() { + grandpa::voter::CommunicationIn::Commit(_, _, mut callback) => { + callback.run(grandpa::voter::CommitProcessingOutcome::bad()); + }, + _ => panic!("commit expected"), + } }) .map_err(|_| panic!("could not process commit")); @@ -393,3 +447,61 @@ fn bad_commit_leads_to_report() { current_thread::block_on_all(test).unwrap(); } + +#[test] +fn peer_with_higher_view_leads_to_catch_up_request() { + let id = network::PeerId::random(); + + let (tester, mut net) = make_test_network(); + let test = tester + .and_then(move |tester| { + // register a peer. + tester.gossip_validator.new_peer(&mut NoopContext, &id, network::config::Roles::FULL); + Ok((tester, id)) + }) + .and_then(move |(tester, id)| { + // send neighbor message at round 10 and height 50 + let result = tester.gossip_validator.validate( + &mut net, + &id, + &gossip::GossipMessage::::from(gossip::NeighborPacket { + set_id: SetId(0), + round: Round(10), + commit_finalized_height: 50, + }).encode(), + ); + + // neighbor packets are always discard + match result { + network_gossip::ValidationResult::Discard => {}, + _ => panic!("wrong expected outcome from neighbor validation"), + } + + // a catch up request should be sent to the peer for round - 1 + tester.filter_network_events(move |event| match event { + Event::SendMessage(peers, message) => { + assert_eq!( + peers, + vec![id.clone()], + ); + + assert_eq!( + message, + gossip::GossipMessage::::CatchUpRequest( + gossip::CatchUpRequestMessage { + set_id: SetId(0), + round: Round(9), + } + ).encode(), + ); + + true + }, + _ => false, + }) + .map_err(|_| panic!("could not watch for peer send message")) + .map(|_| ()) + }); + + current_thread::block_on_all(test).unwrap(); +} diff --git a/core/finality-grandpa/src/environment.rs b/core/finality-grandpa/src/environment.rs index 2c6217c81701837b1019c4c11ef1d34e1ab119cc..7289c77e4df04a2b5bf2e7b70e59c21b4f6fc3bf 100644 --- a/core/finality-grandpa/src/environment.rs +++ b/core/finality-grandpa/src/environment.rs @@ -22,7 +22,7 @@ use std::time::{Duration, Instant}; use log::{debug, warn, info}; use parity_codec::{Decode, Encode}; use futures::prelude::*; -use tokio::timer::Delay; +use tokio_timer::Delay; use parking_lot::RwLock; use client::{ @@ -50,9 +50,17 @@ use crate::authorities::{AuthoritySet, SharedAuthoritySet}; use crate::consensus_changes::SharedConsensusChanges; use crate::justification::GrandpaJustification; use crate::until_imported::UntilVoteTargetImported; -use fg_primitives::AuthorityId; +use fg_primitives::{AuthorityId, AuthoritySignature}; -/// Data about a completed round. +type HistoricalVotes = grandpa::HistoricalVotes< + ::Hash, + NumberFor, + AuthoritySignature, + AuthorityId, +>; + +/// Data about a completed round. The set of votes that is stored must be +/// minimal, i.e. at most one equivocation is stored per voter. #[derive(Debug, Clone, Decode, Encode, PartialEq)] pub struct CompletedRound { /// The round number. @@ -177,6 +185,16 @@ impl VoterSetState { completed_rounds.clone(), } } + + /// Returns the last completed round. + pub(crate) fn last_completed_round(&self) -> CompletedRound { + match self { + VoterSetState::Live { completed_rounds, .. } => + completed_rounds.last().clone(), + VoterSetState::Paused { completed_rounds } => + completed_rounds.last().clone(), + } + } } /// Whether we've voted already during a prior run of the program. @@ -635,7 +653,7 @@ where round: u64, state: RoundState>, base: (Block::Hash, NumberFor), - votes: Vec>, + historical_votes: &HistoricalVotes, ) -> Result<(), Self::Error> { debug!( target: "afg", "Voter {} completed round {} in set {}. Estimate = {:?}, Finalized in round = {:?}", @@ -649,6 +667,9 @@ where self.update_voter_set_state(|voter_set_state| { let mut completed_rounds = voter_set_state.completed_rounds(); + // TODO: Future integration will store the prevote and precommit index. See #2611. + let votes = historical_votes.seen().clone(); + // NOTE: the Environment assumes that rounds are *always* completed in-order. if !completed_rounds.push(CompletedRound { number: round, diff --git a/core/finality-grandpa/src/import.rs b/core/finality-grandpa/src/import.rs index eaa131b7bf36bd2d6724b3a149f0b7edc4f418e7..9a9e4e906229b893a257d4b9107988a8ab5d9295 100644 --- a/core/finality-grandpa/src/import.rs +++ b/core/finality-grandpa/src/import.rs @@ -63,6 +63,21 @@ pub struct GrandpaBlockImport, RA, PRA, SC> { api: Arc, } +impl, RA, PRA, SC: Clone> Clone for + GrandpaBlockImport +{ + fn clone(&self) -> Self { + GrandpaBlockImport { + inner: self.inner.clone(), + select_chain: self.select_chain.clone(), + authority_set: self.authority_set.clone(), + send_voter_commands: self.send_voter_commands.clone(), + consensus_changes: self.consensus_changes.clone(), + api: self.api.clone(), + } + } +} + impl, RA, PRA, SC> JustificationImport for GrandpaBlockImport where NumberFor: grandpa::BlockNumberOps, @@ -76,7 +91,8 @@ impl, RA, PRA, SC> JustificationImport { type Error = ConsensusError; - fn on_start(&self, link: &mut dyn consensus_common::import_queue::Link) { + fn on_start(&mut self) -> Vec<(Block::Hash, NumberFor)> { + let mut out = Vec::new(); let chain_info = self.inner.info().chain; // request justifications for all pending changes for which change blocks have already been imported @@ -94,16 +110,18 @@ impl, RA, PRA, SC> JustificationImport if let Ok(Some(hash)) = effective_block_hash { if let Ok(Some(header)) = self.inner.header(&BlockId::Hash(hash)) { if *header.number() == pending_change.effective_number() { - link.request_justification(&header.hash(), *header.number()); + out.push((header.hash(), *header.number())); } } } } } + + out } fn import_justification( - &self, + &mut self, hash: Block::Hash, number: NumberFor, justification: Justification, @@ -387,7 +405,7 @@ impl, RA, PRA, SC> BlockImport { type Error = ConsensusError; - fn import_block(&self, mut block: ImportBlock, new_cache: HashMap>) + fn import_block(&mut self, mut block: ImportBlock, new_cache: HashMap>) -> Result { let hash = block.post_header().hash(); @@ -407,7 +425,7 @@ impl, RA, PRA, SC> BlockImport // we don't want to finalize on `inner.import_block` let mut justification = block.justification.take(); let enacts_consensus_change = !new_cache.is_empty(); - let import_result = self.inner.import_block(block, new_cache); + let import_result = (&*self.inner).import_block(block, new_cache); let mut imported_aux = { match import_result { @@ -501,7 +519,7 @@ impl, RA, PRA, SC> BlockImport } fn check_block( - &self, + &mut self, hash: Block::Hash, parent_hash: Block::Hash, ) -> Result { @@ -545,7 +563,7 @@ where /// If `enacts_change` is set to true, then finalizing this block *must* /// enact an authority set change, the function will panic otherwise. fn import_justification( - &self, + &mut self, hash: Block::Hash, number: NumberFor, justification: Justification, diff --git a/core/finality-grandpa/src/lib.rs b/core/finality-grandpa/src/lib.rs index dbdc08715fcfb049b1ecd3fc06879df42885e99b..c704691b70fad47027ec39771d7b0bbbb9667263 100644 --- a/core/finality-grandpa/src/lib.rs +++ b/core/finality-grandpa/src/lib.rs @@ -28,9 +28,9 @@ //! must pass through this wrapper, otherwise consensus is likely to break in //! unexpected ways. //! -//! Next, use the `LinkHalf` and a local configuration to `run_grandpa`. This requires a -//! `Network` implementation. The returned future should be driven to completion and -//! will finalize blocks in the background. +//! Next, use the `LinkHalf` and a local configuration to `run_grandpa_voter`. +//! This requires a `Network` implementation. The returned future should be +//! driven to completion and will finalize blocks in the background. //! //! # Changing authority sets //! @@ -102,7 +102,7 @@ pub use observer::run_grandpa_observer; use aux_schema::PersistentData; use environment::{CompletedRound, CompletedRounds, Environment, HasVoted, SharedVoterSetState, VoterSetState}; use import::GrandpaBlockImport; -use until_imported::UntilCommitBlocksImported; +use until_imported::UntilGlobalMessageBlocksImported; use communication::NetworkBridge; use service::TelemetryOnConnect; use fg_primitives::AuthoritySignature; @@ -129,19 +129,64 @@ pub type PrimaryPropose = grandpa::PrimaryPropose<::Hash pub type Prevote = grandpa::Prevote<::Hash, NumberFor>; /// A precommit message for this chain's block type. pub type Precommit = grandpa::Precommit<::Hash, NumberFor>; +/// A catch up message for this chain's block type. +pub type CatchUp = grandpa::CatchUp< + ::Hash, + NumberFor, + AuthoritySignature, + AuthorityId, +>; /// A commit message for this chain's block type. pub type Commit = grandpa::Commit< ::Hash, NumberFor, AuthoritySignature, - AuthorityId + AuthorityId, >; /// A compact commit message for this chain's block type. pub type CompactCommit = grandpa::CompactCommit< ::Hash, NumberFor, AuthoritySignature, - AuthorityId + AuthorityId, +>; +/// A global communication input stream for commits and catch up messages. Not +/// exposed publicly, used internally to simplify types in the communication +/// layer. +type CommunicationIn = grandpa::voter::CommunicationIn< + ::Hash, + NumberFor, + AuthoritySignature, + AuthorityId, +>; + +/// Global communication input stream for commits and catch up messages, with +/// the hash type not being derived from the block, useful for forcing the hash +/// to some type (e.g. `H256`) when the compiler can't do the inference. +type CommunicationInH = grandpa::voter::CommunicationIn< + H, + NumberFor, + AuthoritySignature, + AuthorityId, +>; + +/// A global communication sink for commits. Not exposed publicly, used +/// internally to simplify types in the communication layer. +type CommunicationOut = grandpa::voter::CommunicationOut< + ::Hash, + NumberFor, + AuthoritySignature, + AuthorityId, +>; + +/// Global communication sink for commits with the hash type not being derived +/// from the block, useful for forcing the hash to some type (e.g. `H256`) when +/// the compiler can't do the inference. +type CommunicationOutH = grandpa::voter::CommunicationOut< + H, + NumberFor, + AuthoritySignature, + AuthorityId, >; /// Configuration for the GRANDPA service. @@ -179,7 +224,7 @@ pub enum Error { /// An invariant has been violated (e.g. not finalizing pending change blocks in-order) Safety(String), /// A timer failed to fire. - Timer(::tokio::timer::Error), + Timer(tokio_timer::Error), } impl From for Error { @@ -358,11 +403,11 @@ fn global_communication, B, E, N, RA>( network: &NetworkBridge, ) -> ( impl Stream< - Item = voter::CommunicationIn, AuthoritySignature, AuthorityId>, + Item = CommunicationInH, Error = CommandOrError>, >, impl Sink< - SinkItem = voter::CommunicationOut, AuthoritySignature, AuthorityId>, + SinkItem = CommunicationOutH, SinkError = CommandOrError>, >, ) where @@ -378,37 +423,21 @@ fn global_communication, B, E, N, RA>( .unwrap_or(false); // verification stream - let (commit_in, commit_out) = network.global_communication( + let (global_in, global_out) = network.global_communication( communication::SetId(set_id), voters.clone(), is_voter, ); - // block commit messages until relevant blocks are imported. - let commit_in = UntilCommitBlocksImported::new( + // block commit and catch up messages until relevant blocks are imported. + let global_in = UntilGlobalMessageBlocksImported::new( client.import_notification_stream(), client.clone(), - commit_in, + global_in, ); - let commits_in = commit_in.map_err(CommandOrError::from); - let commits_out = commit_out.sink_map_err(CommandOrError::from); - - let global_in = commits_in.map(|(round, commit, mut callback)| { - let callback = voter::Callback::Work(Box::new(move |outcome| match outcome { - voter::CommitProcessingOutcome::Good(_) => - callback(communication::CommitProcessingOutcome::Good), - voter::CommitProcessingOutcome::Bad(_) => - callback(communication::CommitProcessingOutcome::Bad), - })); - voter::CommunicationIn::Commit(round, commit, callback) - }); - - // NOTE: eventually this will also handle catch-up requests - let global_out = commits_out.with(|global| match global { - voter::CommunicationOut::Commit(round, commit) => Ok((round, commit)), - _ => unimplemented!(), - }); + let global_in = global_in.map_err(CommandOrError::from); + let global_out = global_out.sink_map_err(CommandOrError::from); (global_in, global_out) } @@ -443,7 +472,7 @@ fn register_finality_tracker_inherent_data_provider, N, RA, SC, X> { +pub struct GrandpaParams, N, RA, SC, X> { /// Configuration for the GRANDPA service. pub config: Config, /// A link to the block import worker. @@ -455,7 +484,7 @@ pub struct GrandpaParams<'a, B, E, Block: BlockT, N, RA, SC, X> { /// Handle to a future that will resolve on exit. pub on_exit: X, /// If supplied, can be used to hook on telemetry connection established events. - pub telemetry_on_connect: Option>, + pub telemetry_on_connect: Option, } /// Run a GRANDPA voter as a task. Provide configuration and a link to a @@ -497,13 +526,13 @@ pub fn run_grandpa_voter, N, RA, SC, X>( let (network, network_startup) = NetworkBridge::new( network, config.clone(), - Some(&set_state.read()), + set_state.clone(), on_exit.clone(), ); register_finality_tracker_inherent_data_provider(client.clone(), &inherent_data_providers)?; - if let Some(telemetry_on_connect) = telemetry_on_connect { + let telemetry_task = if let Some(telemetry_on_connect) = telemetry_on_connect { let authorities = authority_set.clone(); let events = telemetry_on_connect.telemetry_connection_sinks .for_each(move |_| { @@ -520,10 +549,11 @@ pub fn run_grandpa_voter, N, RA, SC, X>( ); Ok(()) }) - .then(|_| Ok(())); - let events = events.select(telemetry_on_connect.on_exit).then(|_| Ok(())); - telemetry_on_connect.executor.spawn(events); - } + .then(|_| -> Result<(), ()> { Ok(()) }); + futures::future::Either::A(events) + } else { + futures::future::Either::B(futures::future::empty()) + }; let voters = authority_set.current_authorities(); let initial_environment = Arc::new(Environment { @@ -723,7 +753,11 @@ pub fn run_grandpa_voter, N, RA, SC, X>( let voter_work = network_startup.and_then(move |()| voter_work); - Ok(voter_work.select(on_exit).then(|_| Ok(()))) + // Make sure that `telemetry_task` doesn't accidentally finish and kill grandpa. + let telemetry_task = telemetry_task + .then(|_| futures::future::empty::<(), ()>()); + + Ok(voter_work.select(on_exit).select2(telemetry_task).then(|_| Ok(()))) } #[deprecated(since = "1.1", note = "Please switch to run_grandpa_voter.")] diff --git a/core/finality-grandpa/src/light_import.rs b/core/finality-grandpa/src/light_import.rs index 25a3f84f6dc01c4bd5a88eda8a5013d6b528e3f9..717054e3087b162753533db98f2038675e8ab365 100644 --- a/core/finality-grandpa/src/light_import.rs +++ b/core/finality-grandpa/src/light_import.rs @@ -27,10 +27,11 @@ use client::{ }; use parity_codec::{Encode, Decode}; use consensus_common::{ - import_queue::{Verifier, SharedFinalityProofRequestBuilder}, well_known_cache_keys, + import_queue::Verifier, well_known_cache_keys, BlockOrigin, BlockImport, FinalityProofImport, ImportBlock, ImportResult, ImportedAux, - Error as ConsensusError, FinalityProofRequestBuilder, + Error as ConsensusError, }; +use network::config::{BoxFinalityProofRequestBuilder, FinalityProofRequestBuilder}; use runtime_primitives::Justification; use runtime_primitives::traits::{ NumberFor, Block as BlockT, Header as HeaderT, ProvideRuntimeApi, DigestFor, @@ -84,6 +85,16 @@ pub struct GrandpaLightBlockImport, RA> { data: Arc>>, } +impl, RA> Clone for GrandpaLightBlockImport { + fn clone(&self) -> Self { + GrandpaLightBlockImport { + client: self.client.clone(), + authority_set_provider: self.authority_set_provider.clone(), + data: self.data.clone(), + } + } +} + /// Mutable data of light block importer. struct LightImportData> { last_finalized: Block::Hash, @@ -100,8 +111,8 @@ struct LightAuthoritySet { impl, RA> GrandpaLightBlockImport { /// Create finality proof request builder. - pub fn create_finality_proof_request_builder(&self) -> SharedFinalityProofRequestBuilder { - Arc::new(GrandpaFinalityProofRequestBuilder(self.data.clone())) as _ + pub fn create_finality_proof_request_builder(&self) -> BoxFinalityProofRequestBuilder { + Box::new(GrandpaFinalityProofRequestBuilder(self.data.clone())) as _ } } @@ -116,7 +127,7 @@ impl, RA> BlockImport type Error = ConsensusError; fn import_block( - &self, + &mut self, block: ImportBlock, new_cache: HashMap>, ) -> Result { @@ -126,7 +137,7 @@ impl, RA> BlockImport } fn check_block( - &self, + &mut self, hash: Block::Hash, parent_hash: Block::Hash, ) -> Result { @@ -144,19 +155,22 @@ impl, RA> FinalityProofImport { type Error = ConsensusError; - fn on_start(&self, link: &mut dyn consensus_common::import_queue::Link) { + fn on_start(&mut self) -> Vec<(Block::Hash, NumberFor)> { + let mut out = Vec::new(); let chain_info = self.client.info().chain; let data = self.data.read(); for (pending_number, pending_hash) in data.consensus_changes.pending_changes() { if *pending_number > chain_info.finalized_number && *pending_number <= chain_info.best_number { - link.request_finality_proof(pending_hash, *pending_number); + out.push((pending_hash.clone(), *pending_number)); } } + + out } fn import_finality_proof( - &self, + &mut self, hash: Block::Hash, number: NumberFor, finality_proof: Vec, @@ -203,7 +217,7 @@ impl LightAuthoritySet { struct GrandpaFinalityProofRequestBuilder>(Arc>>); impl> FinalityProofRequestBuilder for GrandpaFinalityProofRequestBuilder { - fn build_request_data(&self, _hash: &B::Hash) -> Vec { + fn build_request_data(&mut self, _hash: &B::Hash) -> Vec { let data = self.0.read(); make_finality_proof_request( data.last_finalized, @@ -214,7 +228,7 @@ impl> FinalityProofRequestBuilder for GrandpaFinalityPro /// Try to import new block. fn do_import_block, RA, J>( - client: &Client, + mut client: &Client, data: &mut LightImportData, mut block: ImportBlock, new_cache: HashMap>, @@ -233,7 +247,7 @@ fn do_import_block, RA, J>( // we don't want to finalize on `inner.import_block` let justification = block.justification.take(); let enacts_consensus_change = !new_cache.is_empty(); - let import_result = client.import_block(block, new_cache); + let import_result = BlockImport::import_block(&mut client, block, new_cache); let mut imported_aux = match import_result { Ok(ImportResult::Imported(aux)) => aux, @@ -534,6 +548,19 @@ pub mod tests { pub GrandpaLightBlockImport ); + impl, RA> Clone + for NoJustificationsImport where + NumberFor: grandpa::BlockNumberOps, + B: Backend + 'static, + E: CallExecutor + 'static + Clone + Send + Sync, + DigestFor: Encode, + RA: Send + Sync, + { + fn clone(&self) -> Self { + NoJustificationsImport(self.0.clone()) + } + } + impl, RA> BlockImport for NoJustificationsImport where NumberFor: grandpa::BlockNumberOps, @@ -545,7 +572,7 @@ pub mod tests { type Error = ConsensusError; fn import_block( - &self, + &mut self, mut block: ImportBlock, new_cache: HashMap>, ) -> Result { @@ -554,7 +581,7 @@ pub mod tests { } fn check_block( - &self, + &mut self, hash: Block::Hash, parent_hash: Block::Hash, ) -> Result { @@ -572,12 +599,12 @@ pub mod tests { { type Error = ConsensusError; - fn on_start(&self, link: &mut dyn consensus_common::import_queue::Link) { - self.0.on_start(link) + fn on_start(&mut self) -> Vec<(Block::Hash, NumberFor)> { + self.0.on_start() } fn import_finality_proof( - &self, + &mut self, hash: Block::Hash, number: NumberFor, finality_proof: Vec, diff --git a/core/finality-grandpa/src/observer.rs b/core/finality-grandpa/src/observer.rs index 4738fd3ed6330729b73a1f5b55f0a7eeee923188..2c0818c2d70957def110832da26ee3020aeadf65 100644 --- a/core/finality-grandpa/src/observer.rs +++ b/core/finality-grandpa/src/observer.rs @@ -30,7 +30,7 @@ use runtime_primitives::traits::{NumberFor, Block as BlockT}; use substrate_primitives::{H256, Blake2Hasher}; use crate::{ - AuthoritySignature, global_communication, CommandOrError, Config, environment, + global_communication, CommandOrError, CommunicationIn, Config, environment, LinkHalf, Network, aux_schema::PersistentData, VoterCommand, VoterSetState, }; use crate::authorities::SharedAuthoritySet; @@ -57,22 +57,24 @@ impl<'a, Block: BlockT, B, E, RA> grandpa::Chain, RA, S>( +fn grandpa_observer, RA, S, F>( client: &Arc>, authority_set: &SharedAuthoritySet>, consensus_changes: &SharedConsensusChanges>, voters: &Arc>, last_finalized_number: NumberFor, commits: S, + note_round: F, ) -> impl Future>> where NumberFor: BlockNumberOps, B: Backend, E: CallExecutor + Send + Sync, RA: Send + Sync, S: Stream< - Item = voter::CommunicationIn, AuthoritySignature, AuthorityId>, + Item = CommunicationIn, Error = CommandOrError>, >, + F: Fn(u64), { let authority_set = authority_set.clone(); let consensus_changes = consensus_changes.clone(); @@ -85,8 +87,8 @@ fn grandpa_observer, RA, S>( let commit = grandpa::Commit::from(commit); (round, commit, callback) }, - voter::CommunicationIn::Auxiliary(_) => { - // ignore aux messages + voter::CommunicationIn::CatchUp(..) => { + // ignore catch up messages return future::ok(last_finalized_number); }, }; @@ -124,6 +126,10 @@ fn grandpa_observer, RA, S>( Err(e) => return future::err(e), }; + // note that we've observed completion of this round through the commit, + // and that implies that the next round has started. + note_round(round + 1); + grandpa::process_commit_validation_result(validation_result, callback); // proceed processing with new finalized block number @@ -167,15 +173,9 @@ pub fn run_grandpa_observer, N, RA, SC>( } = link; let PersistentData { authority_set, consensus_changes, set_state } = persistent_data; + let initial_state = (authority_set, consensus_changes, set_state.clone(), voter_commands_rx.into_future()); - let (network, network_startup) = NetworkBridge::new( - network, - config.clone(), - None, - on_exit.clone(), - ); - - let initial_state = (authority_set, consensus_changes, set_state, voter_commands_rx.into_future()); + let (network, network_startup) = NetworkBridge::new(network, config.clone(), set_state, on_exit.clone()); let observer_work = future::loop_fn(initial_state, move |state| { let (authority_set, consensus_changes, set_state, voter_commands_rx) = state; @@ -194,6 +194,21 @@ pub fn run_grandpa_observer, N, RA, SC>( let last_finalized_number = client.info().chain.finalized_number; + // NOTE: since we are not using `round_communication` we have to + // manually note the round with the gossip validator, otherwise we won't + // relay round messages. we want all full nodes to contribute to vote + // availability. + let note_round = { + let network = network.clone(); + let voters = voters.clone(); + + move |round| network.note_round( + crate::communication::Round(round), + crate::communication::SetId(set_id), + &*voters, + ) + }; + // create observer for the current set let observer = grandpa_observer( &client, @@ -202,6 +217,7 @@ pub fn run_grandpa_observer, N, RA, SC>( &voters, last_finalized_number, global_in, + note_round, ); let handle_voter_command = move |command, voter_commands_rx| { diff --git a/core/finality-grandpa/src/tests.rs b/core/finality-grandpa/src/tests.rs index 8afa495334397894492edaefd9688a5b67e8fb09..0a727df9a24adc2f3b4a5bd27921dbd3d9f89b39 100644 --- a/core/finality-grandpa/src/tests.rs +++ b/core/finality-grandpa/src/tests.rs @@ -19,9 +19,9 @@ use super::*; use network::test::{Block, DummySpecialization, Hash, TestNetFactory, Peer, PeersClient}; use network::test::{PassThroughVerifier}; -use network::config::{ProtocolConfig, Roles}; -use network::consensus_gossip as network_gossip; +use network::config::{ProtocolConfig, Roles, BoxFinalityProofRequestBuilder}; use parking_lot::Mutex; +use futures03::{StreamExt as _, TryStreamExt as _}; use tokio::runtime::current_thread; use keyring::ed25519::{Keyring as AuthorityKeyring}; use client::{ @@ -31,9 +31,7 @@ use client::{ }; use test_client::{self, runtime::BlockNumber}; use consensus_common::{BlockOrigin, ForkChoiceStrategy, ImportedAux, ImportBlock, ImportResult}; -use consensus_common::import_queue::{SharedBlockImport, SharedJustificationImport, SharedFinalityProofImport, - SharedFinalityProofRequestBuilder, -}; +use consensus_common::import_queue::{BoxBlockImport, BoxJustificationImport, BoxFinalityProofImport}; use std::collections::{HashMap, HashSet}; use std::result; use parity_codec::Decode; @@ -44,7 +42,6 @@ use fg_primitives::AuthorityId; use authorities::AuthoritySet; use finality_proof::{FinalityProofProvider, AuthoritySetForFinalityProver, AuthoritySetForFinalityChecker}; -use communication::GRANDPA_ENGINE_ID; use consensus_changes::ConsensusChanges; type PeerData = @@ -62,16 +59,14 @@ type PeerData = type GrandpaPeer = Peer; struct GrandpaTestNet { - peers: Vec>, + peers: Vec, test_config: TestApi, - started: bool, } impl GrandpaTestNet { fn new(test_config: TestApi, n_peers: usize) -> Self { let mut net = GrandpaTestNet { peers: Vec::with_capacity(n_peers), - started: false, test_config, }; let config = Self::default_config(); @@ -92,7 +87,6 @@ impl TestNetFactory for GrandpaTestNet { GrandpaTestNet { peers: Vec::new(), test_config: Default::default(), - started: false, } } @@ -111,10 +105,10 @@ impl TestNetFactory for GrandpaTestNet { fn make_block_import(&self, client: PeersClient) -> ( - SharedBlockImport, - Option>, - Option>, - Option>, + BoxBlockImport, + Option>, + Option>, + Option>, PeerData, ) { @@ -129,8 +123,9 @@ impl TestNetFactory for GrandpaTestNet { Arc::new(self.test_config.clone()), select_chain, ).expect("Could not create block import for fresh peer."); - let shared_import = Arc::new(import); - (shared_import.clone(), Some(shared_import), None, None, Mutex::new(Some(link))) + let justification_import = Box::new(import.clone()); + let block_import = Box::new(import); + (block_import, Some(justification_import), None, None, Mutex::new(Some(link))) }, PeersClient::Light(ref client) => { use crate::light_import::tests::light_block_import_without_justifications; @@ -144,8 +139,9 @@ impl TestNetFactory for GrandpaTestNet { Arc::new(self.test_config.clone()) ).expect("Could not create block import for fresh peer."); let finality_proof_req_builder = import.0.create_finality_proof_request_builder(); - let shared_import = Arc::new(import); - (shared_import.clone(), None, Some(shared_import), Some(finality_proof_req_builder), Mutex::new(None)) + let proof_import = Box::new(import.clone()); + let block_import = Box::new(import); + (block_import, None, Some(proof_import), Some(finality_proof_req_builder), Mutex::new(None)) }, } } @@ -163,112 +159,17 @@ impl TestNetFactory for GrandpaTestNet { } } - fn uses_tokio(&self) -> bool { - true - } - - fn peer(&self, i: usize) -> &GrandpaPeer { - &self.peers[i] + fn peer(&mut self, i: usize) -> &mut GrandpaPeer { + &mut self.peers[i] } - fn peers(&self) -> &Vec> { + fn peers(&self) -> &Vec { &self.peers } - fn mut_peers>)>(&mut self, closure: F) { + fn mut_peers)>(&mut self, closure: F) { closure(&mut self.peers); } - - fn started(&self) -> bool { - self.started - } - - fn set_started(&mut self, new: bool) { - self.started = new; - } -} - -#[derive(Clone)] -struct MessageRouting { - inner: Arc>, - peer_id: usize, -} - -impl MessageRouting { - fn new(inner: Arc>, peer_id: usize,) -> Self { - MessageRouting { - inner, - peer_id, - } - } -} - -impl Network for MessageRouting { - type In = Box + Send>; - - /// Get a stream of messages for a specific gossip topic. - fn messages_for(&self, topic: Hash) -> Self::In { - let inner = self.inner.lock(); - let peer = inner.peer(self.peer_id); - - let messages = peer.consensus_gossip_messages_for( - GRANDPA_ENGINE_ID, - topic, - ); - - let messages = messages.map_err( - move |_| panic!("Messages for topic {} dropped too early", topic) - ); - - Box::new(messages) - } - - fn register_validator(&self, v: Arc>) { - let inner = self.inner.lock(); - let peer = inner.peer(self.peer_id); - peer.with_gossip(move |gossip, context| { - gossip.register_validator(context, GRANDPA_ENGINE_ID, v); - }); - } - - fn gossip_message(&self, topic: Hash, data: Vec, force: bool) { - let inner = self.inner.lock(); - inner.peer(self.peer_id).gossip_message( - topic, - GRANDPA_ENGINE_ID, - data, - force, - ); - } - - fn send_message(&self, who: Vec, data: Vec) { - let inner = self.inner.lock(); - let peer = inner.peer(self.peer_id); - - peer.with_gossip(move |gossip, ctx| for who in &who { - gossip.send_message( - ctx, - who, - network_gossip::ConsensusMessage { - engine_id: GRANDPA_ENGINE_ID, - data: data.clone(), - } - ) - }) - } - - fn register_gossip_message(&self, _topic: Hash, _data: Vec) { - // NOTE: only required to restore previous state on startup - // not required for tests currently - } - - fn report(&self, _who: network::PeerId, _cost_benefit: i32) { - - } - - fn announce(&self, _block: Hash) { - - } } #[derive(Clone)] @@ -440,7 +341,6 @@ impl AuthoritySetForFinalityChecker for TestApi { } const TEST_GOSSIP_DURATION: Duration = Duration::from_millis(500); -const TEST_ROUTING_INTERVAL: Duration = Duration::from_millis(50); fn make_ids(keys: &[AuthorityKeyring]) -> Vec<(substrate_primitives::ed25519::Public, u64)> { keys.iter() @@ -452,6 +352,7 @@ fn make_ids(keys: &[AuthorityKeyring]) -> Vec<(substrate_primitives::ed25519::Pu // run the voters to completion. provide a closure to be invoked after // the voters are spawned but before blocking on them. fn run_to_completion_with( + runtime: &mut current_thread::Runtime, blocks: u64, net: Arc>, peers: &[AuthorityKeyring], @@ -462,7 +363,6 @@ fn run_to_completion_with( use parking_lot::RwLock; let mut wait_for = Vec::new(); - let mut runtime = current_thread::Runtime::new().unwrap(); let highest_finalized = Arc::new(RwLock::new(0)); @@ -472,12 +372,13 @@ fn run_to_completion_with( for (peer_id, key) in peers.iter().enumerate() { let highest_finalized = highest_finalized.clone(); - let (client, link) = { + let (client, net_service, link) = { let net = net.lock(); // temporary needed for some reason let link = net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed"); ( net.peers[peer_id].client().clone(), + net.peers[peer_id].network_service().clone(), link, ) }; @@ -485,6 +386,7 @@ fn run_to_completion_with( wait_for.push( Box::new( client.finality_notification_stream() + .map(|v| Ok::<_, ()>(v)).compat() .take_while(move |n| { let mut highest_finalized = highest_finalized.write(); if *n.header.number() > *highest_finalized { @@ -507,7 +409,7 @@ fn run_to_completion_with( name: Some(format!("peer#{}", peer_id)), }, link: link, - network: MessageRouting::new(net.clone(), peer_id), + network: net_service, inherent_data_providers: InherentDataProviders::new(), on_exit: Exit, telemetry_on_connect: None, @@ -524,35 +426,32 @@ fn run_to_completion_with( .map(|_| ()) .map_err(|_| ()); - let drive_to_completion = ::tokio::timer::Interval::new_interval(TEST_ROUTING_INTERVAL) - .for_each(move |_| { - net.lock().send_import_notifications(); - net.lock().send_finality_notifications(); - net.lock().sync_without_disconnects(); - Ok(()) - }) - .map(|_| ()) - .map_err(|_| ()); - + let drive_to_completion = futures::future::poll_fn(|| { net.lock().poll(); Ok(Async::NotReady) }); let _ = runtime.block_on(wait_for.select(drive_to_completion).map_err(|_| ())).unwrap(); let highest_finalized = *highest_finalized.read(); highest_finalized } -fn run_to_completion(blocks: u64, net: Arc>, peers: &[AuthorityKeyring]) -> u64 { - run_to_completion_with(blocks, net, peers, |_| None) +fn run_to_completion( + runtime: &mut current_thread::Runtime, + blocks: u64, + net: Arc>, + peers: &[AuthorityKeyring] +) -> u64 { + run_to_completion_with(runtime, blocks, net, peers, |_| None) } #[test] fn finalize_3_voters_no_observers() { let _ = env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let peers = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie]; let voters = make_ids(peers); let mut net = GrandpaTestNet::new(TestApi::new(voters), 3); net.peer(0).push_blocks(20, false); - net.sync(); + net.block_until_sync(&mut runtime); for i in 0..3 { assert_eq!(net.peer(i).client().info().chain.best_number, 20, @@ -560,7 +459,7 @@ fn finalize_3_voters_no_observers() { } let net = Arc::new(Mutex::new(net)); - run_to_completion(20, net.clone(), peers); + run_to_completion(&mut runtime, 20, net.clone(), peers); // normally there's no justification for finalized blocks assert!(net.lock().peer(0).client().justification(&BlockId::Number(20)).unwrap().is_none(), @@ -569,33 +468,36 @@ fn finalize_3_voters_no_observers() { #[test] fn finalize_3_voters_1_full_observer() { + let mut runtime = current_thread::Runtime::new().unwrap(); + let peers = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie]; let voters = make_ids(peers); let mut net = GrandpaTestNet::new(TestApi::new(voters), 4); net.peer(0).push_blocks(20, false); - net.sync(); + net.block_until_sync(&mut runtime); let net = Arc::new(Mutex::new(net)); let mut finality_notifications = Vec::new(); - let mut runtime = current_thread::Runtime::new().unwrap(); let all_peers = peers.iter() .cloned() .map(|key| Some(Arc::new(key.into()))) .chain(::std::iter::once(None)); for (peer_id, local_key) in all_peers.enumerate() { - let (client, link) = { + let (client, net_service, link) = { let net = net.lock(); let link = net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed"); ( net.peers[peer_id].client().clone(), + net.peers[peer_id].network_service().clone(), link, ) }; finality_notifications.push( client.finality_notification_stream() + .map(|v| Ok::<_, ()>(v)).compat() .take_while(|n| Ok(n.header.number() < &20)) .for_each(move |_| Ok(())) ); @@ -608,7 +510,7 @@ fn finalize_3_voters_1_full_observer() { name: Some(format!("peer#{}", peer_id)), }, link: link, - network: MessageRouting::new(net.clone(), peer_id), + network: net_service, inherent_data_providers: InherentDataProviders::new(), on_exit: Exit, telemetry_on_connect: None, @@ -623,11 +525,7 @@ fn finalize_3_voters_1_full_observer() { .map(|_| ()) .map_err(|_| ()); - let drive_to_completion = ::tokio::timer::Interval::new_interval(TEST_ROUTING_INTERVAL) - .for_each(move |_| { net.lock().sync_without_disconnects(); Ok(()) }) - .map(|_| ()) - .map_err(|_| ()); - + let drive_to_completion = futures::future::poll_fn(|| { net.lock().poll(); Ok(Async::NotReady) }); let _ = runtime.block_on(wait_for.select(drive_to_completion).map_err(|_| ())).unwrap(); } @@ -663,7 +561,7 @@ fn transition_3_voters_twice_1_full_observer() { let mut runtime = current_thread::Runtime::new().unwrap(); net.lock().peer(0).push_blocks(1, false); - net.lock().sync(); + net.lock().block_until_sync(&mut runtime); for (i, peer) in net.lock().peers().iter().enumerate() { let full_client = peer.client().as_full().expect("only full clients are used in test"); @@ -690,6 +588,7 @@ fn transition_3_voters_twice_1_full_observer() { // wait for blocks to be finalized before generating new ones let block_production = client.finality_notification_stream() + .map(|v| Ok::<_, ()>(v)).compat() .take_while(|n| Ok(n.header.number() < &30)) .for_each(move |n| { match n.header.number() { @@ -745,17 +644,19 @@ fn transition_3_voters_twice_1_full_observer() { .enumerate(); for (peer_id, local_key) in all_peers { - let (client, link) = { + let (client, net_service, link) = { let net = net.lock(); let link = net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed"); ( net.peers[peer_id].client().clone(), + net.peers[peer_id].network_service().clone(), link, ) }; finality_notifications.push( client.finality_notification_stream() + .map(|v| Ok::<_, ()>(v)).compat() .take_while(|n| Ok(n.header.number() < &30)) .for_each(move |_| Ok(())) .map(move |()| { @@ -777,7 +678,7 @@ fn transition_3_voters_twice_1_full_observer() { name: Some(format!("peer#{}", peer_id)), }, link: link, - network: MessageRouting::new(net.clone(), peer_id), + network: net_service, inherent_data_providers: InherentDataProviders::new(), on_exit: Exit, telemetry_on_connect: None, @@ -792,30 +693,22 @@ fn transition_3_voters_twice_1_full_observer() { .map(|_| ()) .map_err(|_| ()); - let drive_to_completion = ::tokio::timer::Interval::new_interval(TEST_ROUTING_INTERVAL) - .for_each(move |_| { - net.lock().send_import_notifications(); - net.lock().send_finality_notifications(); - net.lock().sync_without_disconnects(); - Ok(()) - }) - .map(|_| ()) - .map_err(|_| ()); - + let drive_to_completion = futures::future::poll_fn(|| { net.lock().poll(); Ok(Async::NotReady) }); let _ = runtime.block_on(wait_for.select(drive_to_completion).map_err(|_| ())).unwrap(); } #[test] fn justification_is_emitted_when_consensus_data_changes() { + let mut runtime = current_thread::Runtime::new().unwrap(); let peers = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie]; let mut net = GrandpaTestNet::new(TestApi::new(make_ids(peers)), 3); // import block#1 WITH consensus data change let new_authorities = vec![substrate_primitives::sr25519::Public::from_raw([42; 32])]; net.peer(0).push_authorities_change_block(new_authorities); - net.sync(); + net.block_until_sync(&mut runtime); let net = Arc::new(Mutex::new(net)); - run_to_completion(1, net.clone(), peers); + run_to_completion(&mut runtime, 1, net.clone(), peers); // ... and check that there's justification for block#1 assert!(net.lock().peer(0).client().justification(&BlockId::Number(1)).unwrap().is_some(), @@ -824,15 +717,16 @@ fn justification_is_emitted_when_consensus_data_changes() { #[test] fn justification_is_generated_periodically() { + let mut runtime = current_thread::Runtime::new().unwrap(); let peers = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie]; let voters = make_ids(peers); let mut net = GrandpaTestNet::new(TestApi::new(voters), 3); net.peer(0).push_blocks(32, false); - net.sync(); + net.block_until_sync(&mut runtime); let net = Arc::new(Mutex::new(net)); - run_to_completion(32, net.clone(), peers); + run_to_completion(&mut runtime, 32, net.clone(), peers); // when block#32 (justification_period) is finalized, justification // is required => generated @@ -862,6 +756,7 @@ fn consensus_changes_works() { #[test] fn sync_justifications_on_change_blocks() { + let mut runtime = current_thread::Runtime::new().unwrap(); let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie]; let peers_b = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob]; let voters = make_ids(peers_b); @@ -886,7 +781,7 @@ fn sync_justifications_on_change_blocks() { // add more blocks on top of it (until we have 25) net.peer(0).push_blocks(4, false); - net.sync(); + net.block_until_sync(&mut runtime); for i in 0..4 { assert_eq!(net.peer(i).client().info().chain.best_number, 25, @@ -894,7 +789,7 @@ fn sync_justifications_on_change_blocks() { } let net = Arc::new(Mutex::new(net)); - run_to_completion(25, net.clone(), peers_a); + run_to_completion(&mut runtime, 25, net.clone(), peers_a); // the first 3 peers are grandpa voters and therefore have already finalized // block 21 and stored a justification @@ -903,14 +798,20 @@ fn sync_justifications_on_change_blocks() { } // the last peer should get the justification by syncing from other peers - while net.lock().peer(3).client().justification(&BlockId::Number(21)).unwrap().is_none() { - net.lock().sync_without_disconnects(); - } + runtime.block_on(futures::future::poll_fn(move || -> std::result::Result<_, ()> { + if net.lock().peer(3).client().justification(&BlockId::Number(21)).unwrap().is_none() { + net.lock().poll(); + Ok(Async::NotReady) + } else { + Ok(Async::Ready(())) + } + })).unwrap() } #[test] fn finalizes_multiple_pending_changes_in_order() { let _ = env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie]; let peers_b = &[AuthorityKeyring::Dave, AuthorityKeyring::Eve, AuthorityKeyring::Ferdie]; @@ -956,7 +857,7 @@ fn finalizes_multiple_pending_changes_in_order() { // add more blocks on top of it (until we have 30) net.peer(0).push_blocks(4, false); - net.sync(); + net.block_until_sync(&mut runtime); // all peers imported both change blocks for i in 0..6 { @@ -965,11 +866,12 @@ fn finalizes_multiple_pending_changes_in_order() { } let net = Arc::new(Mutex::new(net)); - run_to_completion(30, net.clone(), all_peers); + run_to_completion(&mut runtime, 30, net.clone(), all_peers); } #[test] fn doesnt_vote_on_the_tip_of_the_chain() { + let mut runtime = current_thread::Runtime::new().unwrap(); let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie]; let voters = make_ids(peers_a); let api = TestApi::new(voters); @@ -977,7 +879,7 @@ fn doesnt_vote_on_the_tip_of_the_chain() { // add 100 blocks net.peer(0).push_blocks(100, false); - net.sync(); + net.block_until_sync(&mut runtime); for i in 0..3 { assert_eq!(net.peer(i).client().info().chain.best_number, 100, @@ -985,7 +887,7 @@ fn doesnt_vote_on_the_tip_of_the_chain() { } let net = Arc::new(Mutex::new(net)); - let highest = run_to_completion(75, net.clone(), peers_a); + let highest = run_to_completion(&mut runtime, 75, net.clone(), peers_a); // the highest block to be finalized will be 3/4 deep in the unfinalized chain assert_eq!(highest, 75); @@ -993,6 +895,8 @@ fn doesnt_vote_on_the_tip_of_the_chain() { #[test] fn force_change_to_new_set() { + let _ = env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); // two of these guys are offline. let genesis_authorities = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie, AuthorityKeyring::One, AuthorityKeyring::Two]; let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie]; @@ -1004,49 +908,44 @@ fn force_change_to_new_set() { let net = GrandpaTestNet::new(api, 3); let net = Arc::new(Mutex::new(net)); - let runner_net = net.clone(); - let add_blocks = move |_| { - net.lock().peer(0).push_blocks(1, false); - - { - // add a forced transition at block 12. - let parent_hash = net.lock().peer(0).client().info().chain.best_hash; - forced_transitions.lock().insert(parent_hash, (0, ScheduledChange { - next_authorities: voters.clone(), - delay: 10, - })); - - // add a normal transition too to ensure that forced changes take priority. - normal_transitions.lock().insert(parent_hash, ScheduledChange { - next_authorities: make_ids(genesis_authorities), - delay: 5, - }); - } + net.lock().peer(0).push_blocks(1, false); - net.lock().peer(0).push_blocks(25, false); - net.lock().sync(); + { + // add a forced transition at block 12. + let parent_hash = net.lock().peer(0).client().info().chain.best_hash; + forced_transitions.lock().insert(parent_hash, (0, ScheduledChange { + next_authorities: voters.clone(), + delay: 10, + })); + + // add a normal transition too to ensure that forced changes take priority. + normal_transitions.lock().insert(parent_hash, ScheduledChange { + next_authorities: make_ids(genesis_authorities), + delay: 5, + }); + } - for (i, peer) in net.lock().peers().iter().enumerate() { - assert_eq!(peer.client().info().chain.best_number, 26, - "Peer #{} failed to sync", i); + net.lock().peer(0).push_blocks(25, false); + net.lock().block_until_sync(&mut runtime); - let full_client = peer.client().as_full().expect("only full clients are used in test"); - let set: AuthoritySet = crate::aux_schema::load_authorities( - #[allow(deprecated)] - &**full_client.backend() - ).unwrap(); + for (i, peer) in net.lock().peers().iter().enumerate() { + assert_eq!(peer.client().info().chain.best_number, 26, + "Peer #{} failed to sync", i); - assert_eq!(set.current(), (1, voters.as_slice())); - assert_eq!(set.pending_changes().count(), 0); - } + let full_client = peer.client().as_full().expect("only full clients are used in test"); + let set: AuthoritySet = crate::aux_schema::load_authorities( + #[allow(deprecated)] + &**full_client.backend() + ).unwrap(); - None - }; + assert_eq!(set.current(), (1, voters.as_slice())); + assert_eq!(set.pending_changes().count(), 0); + } // it will only finalize if the forced transition happens. // we add_blocks after the voters are spawned because otherwise // the link-halfs have the wrong AuthoritySet - run_to_completion_with(25, runner_net, peers_a, add_blocks); + run_to_completion(&mut runtime, 25, net, peers_a); } #[test] @@ -1055,10 +954,10 @@ fn allows_reimporting_change_blocks() { let peers_b = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob]; let voters = make_ids(peers_a); let api = TestApi::new(voters); - let net = GrandpaTestNet::new(api.clone(), 3); + let mut net = GrandpaTestNet::new(api.clone(), 3); let client = net.peer(0).client().clone(); - let (block_import, ..) = net.make_block_import(client.clone()); + let (mut block_import, ..) = net.make_block_import(client.clone()); let full_client = client.as_full().unwrap(); let builder = full_client.new_block_at(&BlockId::Number(0), Default::default()).unwrap(); @@ -1104,10 +1003,10 @@ fn test_bad_justification() { let peers_b = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob]; let voters = make_ids(peers_a); let api = TestApi::new(voters); - let net = GrandpaTestNet::new(api.clone(), 3); + let mut net = GrandpaTestNet::new(api.clone(), 3); let client = net.peer(0).client().clone(); - let (block_import, ..) = net.make_block_import(client.clone()); + let (mut block_import, ..) = net.make_block_import(client.clone()); let full_client = client.as_full().expect("only full clients are used in test"); let builder = full_client.new_block_at(&BlockId::Number(0), Default::default()).unwrap(); @@ -1155,6 +1054,7 @@ fn voter_persists_its_votes() { use futures::sync::mpsc; let _ = env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); // we have two authorities but we'll only be running the voter for alice // we are going to be listening for the prevotes it casts @@ -1164,13 +1064,11 @@ fn voter_persists_its_votes() { // alice has a chain with 20 blocks let mut net = GrandpaTestNet::new(TestApi::new(voters.clone()), 2); net.peer(0).push_blocks(20, false); - net.sync(); + net.block_until_sync(&mut runtime); assert_eq!(net.peer(0).client().info().chain.best_number, 20, "Peer #{} failed to sync", 0); - let mut runtime = current_thread::Runtime::new().unwrap(); - let client = net.peer(0).client().clone(); let net = Arc::new(Mutex::new(net)); @@ -1181,6 +1079,7 @@ fn voter_persists_its_votes() { // sender is dropped the voter is stopped. { let net = net.clone(); + let client = client.clone(); let voter = future::loop_fn(voter_rx, move |rx| { let (_block_import, _, _, _, link) = net.lock().make_block_import(client.clone()); @@ -1194,20 +1093,21 @@ fn voter_persists_its_votes() { name: Some(format!("peer#{}", 0)), }, link: link, - network: MessageRouting::new(net.clone(), 0), + network: net.lock().peers[0].network_service().clone(), inherent_data_providers: InherentDataProviders::new(), on_exit: Exit, telemetry_on_connect: None, }; - let mut voter = run_grandpa_voter(grandpa_params).expect("all in order with client and network"); - - let voter = future::poll_fn(move || { - // we need to keep the block_import alive since it owns the - // sender for the voter commands channel, if that gets dropped - // then the voter will stop - let _block_import = _block_import.clone(); - voter.poll() - }); + + let voter = run_grandpa_voter(grandpa_params) + .expect("all in order with client and network") + .then(move |r| { + // we need to keep the block_import alive since it owns the + // sender for the voter commands channel, if that gets dropped + // then the voter will stop + drop(_block_import); + r + }); voter.select2(rx.into_future()).then(|res| match res { Ok(future::Either::A(x)) => { @@ -1244,11 +1144,18 @@ fn voter_persists_its_votes() { local_key: Some(Arc::new(peers[1].clone().into())), name: Some(format!("peer#{}", 1)), }; - let routing = MessageRouting::new(net.clone(), 1); + + let set_state = { + let (_, _, _, _, link) = net.lock().make_block_import(client); + let LinkHalf { persistent_data, .. } = link.lock().take().unwrap(); + let PersistentData { set_state, .. } = persistent_data; + set_state + }; + let (network, routing_work) = communication::NetworkBridge::new( - routing, + net.lock().peers[1].network_service().clone(), config.clone(), - None, + set_state, Exit, ); runtime.block_on(routing_work).unwrap(); @@ -1281,25 +1188,33 @@ fn voter_persists_its_votes() { // we push 20 more blocks to alice's chain net.lock().peer(0).push_blocks(20, false); - net.lock().sync(); - - assert_eq!(net.lock().peer(0).client().info().chain.best_number, 40, - "Peer #{} failed to sync", 0); - #[allow(deprecated)] - let block_30_hash = - net.lock().peer(0).client().as_full().unwrap().backend().blockchain().hash(30).unwrap().unwrap(); + let net2 = net.clone(); + let net = net.clone(); + let voter_tx = voter_tx.clone(); + let round_tx = round_tx.clone(); + future::Either::A(tokio_timer::Interval::new_interval(Duration::from_millis(200)) + .take_while(move |_| { + Ok(net2.lock().peer(1).client().info().chain.best_number != 40) + }) + .for_each(|_| Ok(())) + .and_then(move |_| { + #[allow(deprecated)] + let block_30_hash = + net.lock().peer(0).client().as_full().unwrap().backend().blockchain().hash(30).unwrap().unwrap(); - // we restart alice's voter - voter_tx.unbounded_send(()).unwrap(); + // we restart alice's voter + voter_tx.unbounded_send(()).unwrap(); - // and we push our own prevote for block 30 - let prevote = grandpa::Prevote { - target_number: 30, - target_hash: block_30_hash, - }; + // and we push our own prevote for block 30 + let prevote = grandpa::Prevote { + target_number: 30, + target_hash: block_30_hash, + }; - round_tx.lock().start_send(grandpa::Message::Prevote(prevote)).unwrap(); + round_tx.lock().start_send(grandpa::Message::Prevote(prevote)).unwrap(); + Ok(()) + }).map_err(|_| panic!())) } else if state.compare_and_swap(1, 2, Ordering::SeqCst) == 1 { // the next message we receive should be our own prevote @@ -1315,6 +1230,8 @@ fn voter_persists_its_votes() { // therefore we won't ever receive it again since it will be a // known message on the gossip layer + future::Either::B(future::ok(())) + } else if state.compare_and_swap(2, 3, Ordering::SeqCst) == 2 { // we then receive a precommit from alice for block 15 // even though we casted a prevote for block 30 @@ -1327,23 +1244,17 @@ fn voter_persists_its_votes() { // signal exit exit_tx.clone().lock().take().unwrap().send(()).unwrap(); + + future::Either::B(future::ok(())) + + } else { + panic!() } - Ok(()) }).map_err(|_| ())); } - let net = net.clone(); - let drive_to_completion = ::tokio::timer::Interval::new_interval(TEST_ROUTING_INTERVAL) - .for_each(move |_| { - net.lock().send_import_notifications(); - net.lock().send_finality_notifications(); - net.lock().sync_without_disconnects(); - Ok(()) - }) - .map(|_| ()) - .map_err(|_| ()); - + let drive_to_completion = futures::future::poll_fn(|| { net.lock().poll(); Ok(Async::NotReady) }); let exit = exit_rx.into_future().map(|_| ()).map_err(|_| ()); runtime.block_on(drive_to_completion.select(exit).map(|_| ()).map_err(|_| ())).unwrap(); @@ -1352,12 +1263,13 @@ fn voter_persists_its_votes() { #[test] fn finalize_3_voters_1_light_observer() { let _ = env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let authorities = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie]; let voters = make_ids(authorities); let mut net = GrandpaTestNet::new(TestApi::new(voters), 4); net.peer(0).push_blocks(20, false); - net.sync(); + net.block_until_sync(&mut runtime); for i in 0..4 { assert_eq!(net.peer(i).client().info().chain.best_number, 20, @@ -1368,10 +1280,11 @@ fn finalize_3_voters_1_light_observer() { let link = net.lock().peer(3).data.lock().take().expect("link initialized on startup; qed"); let finality_notifications = net.lock().peer(3).client().finality_notification_stream() + .map(|v| Ok::<_, ()>(v)).compat() .take_while(|n| Ok(n.header.number() < &20)) .collect(); - run_to_completion_with(20, net.clone(), authorities, |executor| { + run_to_completion_with(&mut runtime, 20, net.clone(), authorities, |executor| { executor.spawn( run_grandpa_observer( Config { @@ -1381,7 +1294,7 @@ fn finalize_3_voters_1_light_observer() { name: Some("observer".to_string()), }, link, - MessageRouting::new(net.clone(), 3), + net.lock().peers[3].network_service().clone(), Exit, ).unwrap() ).unwrap(); @@ -1393,6 +1306,7 @@ fn finalize_3_voters_1_light_observer() { #[test] fn finality_proof_is_fetched_by_light_client_when_consensus_data_changes() { let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let peers = &[AuthorityKeyring::Alice]; let mut net = GrandpaTestNet::new(TestApi::new(make_ids(peers)), 1); @@ -1402,14 +1316,18 @@ fn finality_proof_is_fetched_by_light_client_when_consensus_data_changes() { // && instead fetches finality proof for block #1 net.peer(0).push_authorities_change_block(vec![substrate_primitives::sr25519::Public::from_raw([42; 32])]); let net = Arc::new(Mutex::new(net)); - run_to_completion(1, net.clone(), peers); - net.lock().sync_without_disconnects(); + run_to_completion(&mut runtime, 1, net.clone(), peers); + net.lock().block_until_sync(&mut runtime); // check that the block#1 is finalized on light client - while net.lock().peer(1).client().info().chain.finalized_number != 1 { - net.lock().tick_peer(1); - net.lock().sync_without_disconnects(); - } + runtime.block_on(futures::future::poll_fn(move || -> std::result::Result<_, ()> { + if net.lock().peer(1).client().info().chain.finalized_number == 1 { + Ok(Async::Ready(())) + } else { + net.lock().poll(); + Ok(Async::NotReady) + } + })).unwrap() } #[test] @@ -1418,6 +1336,7 @@ fn empty_finality_proof_is_returned_to_light_client_when_authority_set_is_differ const FORCE_CHANGE: bool = true; let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); // two of these guys are offline. let genesis_authorities = if FORCE_CHANGE { @@ -1443,40 +1362,141 @@ fn empty_finality_proof_is_returned_to_light_client_when_authority_set_is_differ let net = GrandpaTestNet::new(api, 3); let net = Arc::new(Mutex::new(net)); - let runner_net = net.clone(); - let add_blocks = move |_| { - net.lock().peer(0).push_blocks(1, false); // best is #1 - - // add a forced transition at block 5. - if FORCE_CHANGE { - let parent_hash = net.lock().peer(0).client().info().chain.best_hash; - forced_transitions.lock().insert(parent_hash, (0, ScheduledChange { - next_authorities: voters.clone(), - delay: 3, - })); - } + net.lock().peer(0).push_blocks(1, false); // best is #1 - // ensure block#10 enacts authorities set change => justification is generated - // normally it will reach light client, but because of the forced change, it will not - net.lock().peer(0).push_blocks(8, false); // best is #9 - net.lock().peer(0).push_authorities_change_block( - vec![substrate_primitives::sr25519::Public::from_raw([42; 32])] - ); // #10 - net.lock().peer(0).push_blocks(1, false); // best is #11 - net.lock().sync_without_disconnects(); + // add a forced transition at block 5. + if FORCE_CHANGE { + let parent_hash = net.lock().peer(0).client().info().chain.best_hash; + forced_transitions.lock().insert(parent_hash, (0, ScheduledChange { + next_authorities: voters.clone(), + delay: 3, + })); + } - None - }; + // ensure block#10 enacts authorities set change => justification is generated + // normally it will reach light client, but because of the forced change, it will not + net.lock().peer(0).push_blocks(8, false); // best is #9 + net.lock().peer(0).push_authorities_change_block( + vec![substrate_primitives::sr25519::Public::from_raw([42; 32])] + ); // #10 + net.lock().peer(0).push_blocks(1, false); // best is #11 + net.lock().block_until_sync(&mut runtime); // finalize block #11 on full clients - run_to_completion_with(11, runner_net.clone(), peers_a, add_blocks); + run_to_completion(&mut runtime, 11, net.clone(), peers_a); + // request finalization by light client - runner_net.lock().add_light_peer(&GrandpaTestNet::default_config()); - runner_net.lock().sync_without_disconnects(); + net.lock().add_light_peer(&GrandpaTestNet::default_config()); + net.lock().block_until_sync(&mut runtime); // check block, finalized on light client assert_eq!( - runner_net.lock().peer(3).client().info().chain.finalized_number, + net.lock().peer(3).client().info().chain.finalized_number, if FORCE_CHANGE { 0 } else { 10 }, ); } + +#[test] +fn voter_catches_up_to_latest_round_when_behind() { + let _ = env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); + + let peers = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob]; + let voters = make_ids(peers); + + let mut net = GrandpaTestNet::new(TestApi::new(voters), 3); + net.peer(0).push_blocks(50, false); + net.block_until_sync(&mut runtime); + + let net = Arc::new(Mutex::new(net)); + let mut finality_notifications = Vec::new(); + + let voter = |local_key, peer_id, link, net: Arc>| -> Box + Send> { + let grandpa_params = GrandpaParams { + config: Config { + gossip_duration: TEST_GOSSIP_DURATION, + justification_period: 32, + local_key, + name: Some(format!("peer#{}", peer_id)), + }, + link: link, + network: net.lock().peer(peer_id).network_service().clone(), + inherent_data_providers: InherentDataProviders::new(), + on_exit: Exit, + telemetry_on_connect: None, + }; + + Box::new(run_grandpa_voter(grandpa_params).expect("all in order with client and network")) + }; + + // spawn authorities + for (peer_id, key) in peers.iter().enumerate() { + let (client, link) = { + let net = net.lock(); + let link = net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed"); + ( + net.peers[peer_id].client().clone(), + link, + ) + }; + + finality_notifications.push( + client.finality_notification_stream() + .map(|v| Ok::<_, ()>(v)).compat() + .take_while(|n| Ok(n.header.number() < &50)) + .for_each(move |_| Ok(())) + ); + + let voter = voter(Some(Arc::new((*key).into())), peer_id, link, net.clone()); + + runtime.spawn(voter); + } + + // wait for them to finalize block 50. since they'll vote on 3/4 of the + // unfinalized chain it will take at least 4 rounds to do it. + let wait_for_finality = ::futures::future::join_all(finality_notifications) + .map(|_| ()) + .map_err(|_| ()); + + // spawn a new voter, it should be behind by at least 4 rounds and should be + // able to catch up to the latest round + let test = { + let net = net.clone(); + let runtime = runtime.handle(); + + wait_for_finality.and_then(move |_| { + let peer_id = 2; + let (client, link) = { + let net = net.lock(); + let link = net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed"); + ( + net.peers[peer_id].client().clone(), + link, + ) + }; + + let set_state = link.persistent_data.set_state.clone(); + + let wait = client.finality_notification_stream() + .map(|v| Ok::<_, ()>(v)).compat() + .take_while(|n| Ok(n.header.number() < &50)) + .collect() + .map(|_| set_state); + + let voter = voter(None, peer_id, link, net); + + runtime.spawn(voter).unwrap(); + + wait + }) + .and_then(|set_state| { + // the last completed round in the new voter is higher than 4 + // which means it caught up to the voters + assert!(set_state.read().last_completed_round().number >= 4); + Ok(()) + }) + }; + + let drive_to_completion = futures::future::poll_fn(|| { net.lock().poll(); Ok(Async::NotReady) }); + let _ = runtime.block_on(test.select(drive_to_completion).map_err(|_| ())).unwrap(); +} diff --git a/core/finality-grandpa/src/until_imported.rs b/core/finality-grandpa/src/until_imported.rs index 7c981050dd4aea6a850f05636077fad2bd3c5361..5575a0d2c6009ecdeb8478f7fa3128e7eb2fda7c 100644 --- a/core/finality-grandpa/src/until_imported.rs +++ b/core/finality-grandpa/src/until_imported.rs @@ -20,15 +20,17 @@ //! //! This is used for votes and commit messages currently. -use super::{BlockStatus, Error, SignedMessage, CompactCommit}; +use super::{BlockStatus, CommunicationIn, Error, SignedMessage}; use log::{debug, warn}; -use client::ImportNotifications; +use client::{BlockImportNotification, ImportNotifications}; use futures::prelude::*; use futures::stream::Fuse; +use futures03::{StreamExt as _, TryStreamExt as _}; +use grandpa::voter; use parking_lot::Mutex; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, NumberFor}; -use tokio::timer::Interval; +use tokio_timer::Interval; use std::collections::{HashMap, VecDeque}; use std::sync::{atomic::{AtomicUsize, Ordering}, Arc}; @@ -63,7 +65,7 @@ pub(crate) trait BlockUntilImported: Sized { /// Buffering imported messages until blocks with given hashes are imported. pub(crate) struct UntilImported> { - import_notifications: Fuse>, + import_notifications: Fuse, Error = ()> + Send>>, status_check: Status, inner: Fuse, ready: VecDeque, @@ -90,7 +92,10 @@ impl UntilImported let check_pending = Interval::new(now + CHECK_PENDING_INTERVAL, CHECK_PENDING_INTERVAL); UntilImported { - import_notifications: import_notifications.fuse(), + import_notifications: { + let stream = import_notifications.map::<_, fn(_) -> _>(|v| Ok::<_, ()>(v)).compat(); + Box::new(stream) as Box + Send> + }.fuse(), status_check, inner: stream.fuse(), ready: VecDeque::new(), @@ -193,7 +198,6 @@ impl Stream for UntilImported if self.import_notifications.is_done() && self.inner.is_done() { Ok(Async::Ready(None)) } else { - Ok(Async::NotReady) } } @@ -253,18 +257,18 @@ impl BlockUntilImported for SignedMessage { /// signed messages are imported. pub(crate) type UntilVoteTargetImported = UntilImported>; -/// This blocks a commit message's import until all blocks -/// referenced in its votes are known. +/// This blocks a global message import, i.e. a commit or catch up messages, +/// until all blocks referenced in its votes are known. /// -/// This is used for compact commits which have already been checked for -/// structural soundness. -pub(crate) struct BlockCommitMessage { - inner: Arc<(AtomicUsize, Mutex, U)>>)>, +/// This is used for compact commits and catch up messages which have already +/// been checked for structural soundness (e.g. valid signatures). +pub(crate) struct BlockGlobalMessage { + inner: Arc<(AtomicUsize, Mutex>>)>, target_number: NumberFor, } -impl BlockUntilImported for BlockCommitMessage { - type Blocked = (u64, CompactCommit, U); +impl BlockUntilImported for BlockGlobalMessage { + type Blocked = CommunicationIn; fn schedule_wait( input: Self::Blocked, @@ -298,7 +302,7 @@ impl BlockUntilImported for BlockCommitMessage Result { - // check integrity: all precommits for same hash have same number. + // check integrity: all votes for same hash have same number. let canon_number = match checked_hashes.entry(target_hash) { Entry::Occupied(entry) => entry.get().number().clone(), Entry::Vacant(entry) => { @@ -315,51 +319,68 @@ impl BlockUntilImported for BlockCommitMessage { + // add known hashes from all precommits. + let precommit_targets = commit.precommits + .iter() + .map(|c| (c.target_number, c.target_hash)); - // add known hashes from the precommits. - for precommit in &commit.precommits { - let target_number = precommit.target_number; - let target_hash = precommit.target_hash; + for (target_number, target_hash) in precommit_targets { + if !query_known(target_hash, target_number)? { + return Ok(()) + } + } + }, + voter::CommunicationIn::CatchUp(ref catch_up, ..) => { + // add known hashes from all prevotes and precommits. + let prevote_targets = catch_up.prevotes + .iter() + .map(|s| (s.prevote.target_number, s.prevote.target_hash)); - if !query_known(target_hash, target_number)? { - return Ok(()) - } - } + let precommit_targets = catch_up.precommits + .iter() + .map(|s| (s.precommit.target_number, s.precommit.target_hash)); - // see if commit target hash is known. - if !query_known(commit.target_hash, commit.target_number)? { - return Ok(()) - } + let targets = prevote_targets.chain(precommit_targets); + + for (target_number, target_hash) in targets { + if !query_known(target_hash, target_number)? { + return Ok(()) + } + } + }, + }; } - // none of the hashes in the commit message were unknown. - // we can just return the commit directly. + // none of the hashes in the global message were unknown. + // we can just return the message directly. if unknown_count == 0 { ready(input); return Ok(()) } - let locked_commit = Arc::new((AtomicUsize::new(unknown_count), Mutex::new(Some(input)))); + let locked_global = Arc::new((AtomicUsize::new(unknown_count), Mutex::new(Some(input)))); // schedule waits for all unknown messages. // when the last one of these has `wait_completed` called on it, - // the commit will be returned. + // the global message will be returned. // // in the future, we may want to issue sync requests to the network // if this is taking a long time. for (hash, is_known) in checked_hashes { if let KnownOrUnknown::Unknown(target_number) = is_known { - wait(hash, BlockCommitMessage { - inner: locked_commit.clone(), + wait(hash, BlockGlobalMessage { + inner: locked_global.clone(), target_number, }) } @@ -398,25 +419,26 @@ impl BlockUntilImported for BlockCommitMessage = UntilImported< +/// A stream which gates off incoming global messages, i.e. commit and catch up +/// messages, until all referenced block hashes have been imported. +pub(crate) type UntilGlobalMessageBlocksImported = UntilImported< Block, Status, I, - BlockCommitMessage, + BlockGlobalMessage, >; #[cfg(test)] mod tests { use super::*; + use crate::{CatchUp, CompactCommit}; use tokio::runtime::current_thread::Runtime; - use tokio::timer::Delay; + use tokio_timer::Delay; use test_client::runtime::{Block, Hash, Header}; use consensus_common::BlockOrigin; use client::BlockImportNotification; use futures::future::Either; - use futures::sync::mpsc; + use futures03::channel::mpsc; use grandpa::Precommit; #[derive(Clone)] @@ -474,41 +496,73 @@ mod tests { ) } - #[test] - fn blocking_commit_message() { - let h1 = make_header(5); - let h2 = make_header(6); - let h3 = make_header(7); + // unwrap the commit from `CommunicationIn` returning its fields in a tuple, + // panics if the given message isn't a commit + fn unapply_commit(msg: CommunicationIn) -> (u64, CompactCommit::) { + match msg { + voter::CommunicationIn::Commit(round, commit, ..) => (round, commit), + _ => panic!("expected commit"), + } + } + + // unwrap the catch up from `CommunicationIn` returning its inner representation, + // panics if the given message isn't a catch up + fn unapply_catch_up(msg: CommunicationIn) -> CatchUp { + match msg { + voter::CommunicationIn::CatchUp(catch_up, ..) => catch_up, + _ => panic!("expected catch up"), + } + } + fn message_all_dependencies_satisfied( + msg: CommunicationIn, + enact_dependencies: F, + ) -> CommunicationIn where + F: FnOnce(&TestChainState), + { let (chain_state, import_notifications) = TestChainState::new(); let block_status = chain_state.block_status(); - let unknown_commit = CompactCommit:: { - target_hash: h1.hash(), - target_number: 5, - precommits: vec![ - Precommit { - target_hash: h2.hash(), - target_number: 6, - }, - Precommit { - target_hash: h3.hash(), - target_number: 7, - }, - ], - auth_data: Vec::new(), // not used - }; + // enact all dependencies before importing the message + enact_dependencies(&chain_state); - let (commit_tx, commit_rx) = mpsc::unbounded(); + let (global_tx, global_rx) = futures::sync::mpsc::unbounded(); - let until_imported = UntilCommitBlocksImported::new( + let until_imported = UntilGlobalMessageBlocksImported::new( import_notifications, block_status, - commit_rx.map_err(|_| panic!("should never error")), + global_rx.map_err(|_| panic!("should never error")), ); - commit_tx.unbounded_send((0, unknown_commit.clone(), ())).unwrap(); + global_tx.unbounded_send(msg).unwrap(); + let work = until_imported.into_future(); + + let mut runtime = Runtime::new().unwrap(); + runtime.block_on(work).map_err(|(e, _)| e).unwrap().0.unwrap() + } + + fn blocking_message_on_dependencies( + msg: CommunicationIn, + enact_dependencies: F, + ) -> CommunicationIn where + F: FnOnce(&TestChainState), + { + let (chain_state, import_notifications) = TestChainState::new(); + let block_status = chain_state.block_status(); + + let (global_tx, global_rx) = futures::sync::mpsc::unbounded(); + + let until_imported = UntilGlobalMessageBlocksImported::new( + import_notifications, + block_status, + global_rx.map_err(|_| panic!("should never error")), + ); + + global_tx.unbounded_send(msg).unwrap(); + + // NOTE: needs to be cloned otherwise it is moved to the stream and + // dropped too early. let inner_chain_state = chain_state.clone(); let work = until_imported .into_future() @@ -518,26 +572,64 @@ mod tests { Ok(Either::A(_)) => panic!("timeout should have fired first"), Ok(Either::B((_, until_imported))) => { // timeout fired. push in the headers. - inner_chain_state.import_header(h1); - inner_chain_state.import_header(h2); - inner_chain_state.import_header(h3); + enact_dependencies(&inner_chain_state); until_imported } }); let mut runtime = Runtime::new().unwrap(); - assert_eq!(runtime.block_on(work).map_err(|(e, _)| e).unwrap().0, Some((0, unknown_commit, ()))); + runtime.block_on(work).map_err(|(e, _)| e).unwrap().0.unwrap() } #[test] - fn commit_message_all_known() { + fn blocking_commit_message() { let h1 = make_header(5); let h2 = make_header(6); let h3 = make_header(7); - let (chain_state, import_notifications) = TestChainState::new(); - let block_status = chain_state.block_status(); + let unknown_commit = CompactCommit:: { + target_hash: h1.hash(), + target_number: 5, + precommits: vec![ + Precommit { + target_hash: h2.hash(), + target_number: 6, + }, + Precommit { + target_hash: h3.hash(), + target_number: 7, + }, + ], + auth_data: Vec::new(), // not used + }; + + let unknown_commit = || voter::CommunicationIn::Commit( + 0, + unknown_commit.clone(), + voter::Callback::Blank, + ); + + let res = blocking_message_on_dependencies( + unknown_commit(), + |chain_state| { + chain_state.import_header(h1); + chain_state.import_header(h2); + chain_state.import_header(h3); + }, + ); + + assert_eq!( + unapply_commit(res), + unapply_commit(unknown_commit()), + ); + } + + #[test] + fn commit_message_all_known() { + let h1 = make_header(5); + let h2 = make_header(6); + let h3 = make_header(7); let known_commit = CompactCommit:: { target_hash: h1.hash(), @@ -555,23 +647,156 @@ mod tests { auth_data: Vec::new(), // not used }; - chain_state.import_header(h1); - chain_state.import_header(h2); - chain_state.import_header(h3); + let known_commit = || voter::CommunicationIn::Commit( + 0, + known_commit.clone(), + voter::Callback::Blank, + ); - let (commit_tx, commit_rx) = mpsc::unbounded(); + let res = message_all_dependencies_satisfied( + known_commit(), + |chain_state| { + chain_state.import_header(h1); + chain_state.import_header(h2); + chain_state.import_header(h3); + }, + ); - let until_imported = UntilCommitBlocksImported::new( - import_notifications, - block_status, - commit_rx.map_err(|_| panic!("should never error")), + assert_eq!( + unapply_commit(res), + unapply_commit(known_commit()), ); + } - commit_tx.unbounded_send((0, known_commit.clone(), ())).unwrap(); + #[test] + fn blocking_catch_up_message() { + let h1 = make_header(5); + let h2 = make_header(6); + let h3 = make_header(7); - let work = until_imported.into_future(); + let signed_prevote = |header: &Header| { + grandpa::SignedPrevote { + id: Default::default(), + signature: Default::default(), + prevote: grandpa::Prevote { + target_hash: header.hash(), + target_number: *header.number(), + }, + } + }; - let mut runtime = Runtime::new().unwrap(); - assert_eq!(runtime.block_on(work).map_err(|(e, _)| e).unwrap().0, Some((0, known_commit, ()))); + let signed_precommit = |header: &Header| { + grandpa::SignedPrecommit { + id: Default::default(), + signature: Default::default(), + precommit: grandpa::Precommit { + target_hash: header.hash(), + target_number: *header.number(), + }, + } + }; + + let prevotes = vec![ + signed_prevote(&h1), + signed_prevote(&h3), + ]; + + let precommits = vec![ + signed_precommit(&h1), + signed_precommit(&h2), + ]; + + let unknown_catch_up = grandpa::CatchUp { + round_number: 1, + prevotes, + precommits, + base_hash: h1.hash(), + base_number: *h1.number(), + }; + + let unknown_catch_up = || voter::CommunicationIn::CatchUp( + unknown_catch_up.clone(), + voter::Callback::Blank, + ); + + let res = blocking_message_on_dependencies( + unknown_catch_up(), + |chain_state| { + chain_state.import_header(h1); + chain_state.import_header(h2); + chain_state.import_header(h3); + }, + ); + + assert_eq!( + unapply_catch_up(res), + unapply_catch_up(unknown_catch_up()), + ); + } + + #[test] + fn catch_up_message_all_known() { + let h1 = make_header(5); + let h2 = make_header(6); + let h3 = make_header(7); + + let signed_prevote = |header: &Header| { + grandpa::SignedPrevote { + id: Default::default(), + signature: Default::default(), + prevote: grandpa::Prevote { + target_hash: header.hash(), + target_number: *header.number(), + }, + } + }; + + let signed_precommit = |header: &Header| { + grandpa::SignedPrecommit { + id: Default::default(), + signature: Default::default(), + precommit: grandpa::Precommit { + target_hash: header.hash(), + target_number: *header.number(), + }, + } + }; + + let prevotes = vec![ + signed_prevote(&h1), + signed_prevote(&h3), + ]; + + let precommits = vec![ + signed_precommit(&h1), + signed_precommit(&h2), + ]; + + let unknown_catch_up = grandpa::CatchUp { + round_number: 1, + prevotes, + precommits, + base_hash: h1.hash(), + base_number: *h1.number(), + }; + + let unknown_catch_up = || voter::CommunicationIn::CatchUp( + unknown_catch_up.clone(), + voter::Callback::Blank, + ); + + let res = message_all_dependencies_satisfied( + unknown_catch_up(), + |chain_state| { + chain_state.import_header(h1); + chain_state.import_header(h2); + chain_state.import_header(h3); + }, + ); + + assert_eq!( + unapply_catch_up(res), + unapply_catch_up(unknown_catch_up()), + ); } } diff --git a/core/inherents/Cargo.toml b/core/inherents/Cargo.toml index 606d9c5ae97ba83ade7a633fd7a0f4bf1e3e08a7..1824eef80f06b7e953ec008e8a261375e56f917b 100644 --- a/core/inherents/Cargo.toml +++ b/core/inherents/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] parking_lot = { version = "0.8.0", optional = true } rstd = { package = "sr-std", path = "../sr-std", default-features = false } -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } runtime_primitives = { package = "sr-primitives", path = "../sr-primitives", default-features = false } [features] diff --git a/core/inherents/src/lib.rs b/core/inherents/src/lib.rs index 7b99c7ba526b24d2ba292a64dec2cb37556ffe48..040f289957fc31e5cf98b6cd35cdf9a6e5963e67 100644 --- a/core/inherents/src/lib.rs +++ b/core/inherents/src/lib.rs @@ -16,8 +16,8 @@ //! Provides types and traits for creating and checking inherents. //! -//! Each inherent is added to a produced block. Each runtime decides on which inherents its -//! want to attach to its blocks. All data that is required for the runtime to create the inherents +//! Each inherent is added to a produced block. Each runtime decides on which inherents it +//! wants to attach to its blocks. All data that is required for the runtime to create the inherents //! is stored in the `InherentData`. This `InherentData` is constructed by the node and given to //! the runtime. //! @@ -124,8 +124,8 @@ impl InherentData { /// /// It either returns okay for all checks, stores all occurred errors or just one fatal error. /// -/// When a fatal error occurres, all other errors are removed and the implementation needs to -/// abbort checking inherents. +/// When a fatal error occurs, all other errors are removed and the implementation needs to +/// abort checking inherents. #[derive(Encode, Decode, Clone)] pub struct CheckInherentsResult { /// Did the check succeed? diff --git a/core/keyring/src/ed25519.rs b/core/keyring/src/ed25519.rs index 9c303b62bc58e6728603dcbe1b27be7c85f724d8..bec4c801561f7b35486aeb16e831801c88ded151 100644 --- a/core/keyring/src/ed25519.rs +++ b/core/keyring/src/ed25519.rs @@ -18,7 +18,7 @@ use std::{collections::HashMap, ops::Deref}; use lazy_static::lazy_static; -use substrate_primitives::{ed25519::{Pair, Public, Signature}, Pair as PairT, H256}; +use substrate_primitives::{ed25519::{Pair, Public, Signature}, Pair as PairT, Public as PublicT, H256}; pub use substrate_primitives::ed25519; /// Set of test accounts. diff --git a/core/keyring/src/sr25519.rs b/core/keyring/src/sr25519.rs index 24a83ab798d26442d788b9bc219b1a493bb59496..8db66ab5ddff7e54d3ac80ba229b763858bd7922 100644 --- a/core/keyring/src/sr25519.rs +++ b/core/keyring/src/sr25519.rs @@ -19,7 +19,7 @@ use std::collections::HashMap; use std::ops::Deref; use lazy_static::lazy_static; -use substrate_primitives::{sr25519::{Pair, Public, Signature}, Pair as PairT, H256}; +use substrate_primitives::{sr25519::{Pair, Public, Signature}, Pair as PairT, Public as PublicT, H256}; pub use substrate_primitives::sr25519; /// Set of test accounts. @@ -68,7 +68,7 @@ impl Keyring { } pub fn to_raw_public_vec(self) -> Vec { - Public::from(self).into_raw_vec() + Public::from(self).to_raw_vec() } pub fn sign(self, msg: &[u8]) -> Signature { diff --git a/core/keystore/src/lib.rs b/core/keystore/src/lib.rs index c36c6504c0110163fbf8000a337a368a0e575045..77106059f82bd3cad93d14f26c71c79112d72fa2 100644 --- a/core/keystore/src/lib.rs +++ b/core/keystore/src/lib.rs @@ -23,7 +23,7 @@ use std::path::PathBuf; use std::fs::{self, File}; use std::io::{self, Write}; -use substrate_primitives::{ed25519::{Pair, Public}, Pair as PairT}; +use substrate_primitives::crypto::{KeyTypeId, Pair, Public}; /// Keystore error. #[derive(Debug, derive_more::Display, derive_more::From)] @@ -59,7 +59,7 @@ impl std::error::Error for Error { /// Key store. pub struct Store { path: PathBuf, - additional: HashMap, + additional: HashMap<(KeyTypeId, Vec), Vec>, } impl Store { @@ -69,33 +69,49 @@ impl Store { Ok(Store { path, additional: HashMap::new() }) } + fn get_pair(&self, public: &TPair::Public) -> Result> { + let key = (TPair::KEY_TYPE, public.to_raw_vec()); + if let Some(bytes) = self.additional.get(&key) { + let pair = TPair::from_seed_slice(bytes) + .map_err(|_| Error::InvalidSeed)?; + return Ok(Some(pair)); + } + Ok(None) + } + + fn insert_pair(&mut self, pair: &TPair) { + let key = (TPair::KEY_TYPE, pair.public().to_raw_vec()); + self.additional.insert(key, pair.to_raw_vec()); + } + /// Generate a new key, placing it into the store. - pub fn generate(&self, password: &str) -> Result { - let (pair, phrase, _) = Pair::generate_with_phrase(Some(password)); - let mut file = File::create(self.key_file_path(&pair.public()))?; + pub fn generate(&self, password: &str) -> Result { + let (pair, phrase, _) = TPair::generate_with_phrase(Some(password)); + let mut file = File::create(self.key_file_path::(&pair.public()))?; ::serde_json::to_writer(&file, &phrase)?; file.flush()?; Ok(pair) } /// Create a new key from seed. Do not place it into the store. - pub fn generate_from_seed(&mut self, seed: &str) -> Result { - let pair = Pair::from_string(seed, None) + pub fn generate_from_seed(&mut self, seed: &str) -> Result { + let pair = TPair::from_string(seed, None) .ok().ok_or(Error::InvalidSeed)?; - self.additional.insert(pair.public(), pair.clone()); + self.insert_pair(&pair); Ok(pair) } /// Load a key file with given public key. - pub fn load(&self, public: &Public, password: &str) -> Result { - if let Some(pair) = self.additional.get(public) { - return Ok(pair.clone()); + pub fn load(&self, public: &TPair::Public, password: &str) -> Result { + if let Some(pair) = self.get_pair(public)? { + return Ok(pair) } - let path = self.key_file_path(public); + + let path = self.key_file_path::(public); let file = File::open(path)?; let phrase: String = ::serde_json::from_reader(&file)?; - let (pair, _) = Pair::from_phrase(&phrase, Some(password)) + let (pair, _) = TPair::from_phrase(&phrase, Some(password)) .ok().ok_or(Error::InvalidPhrase)?; if &pair.public() != public { return Err(Error::InvalidPassword); @@ -104,22 +120,28 @@ impl Store { } /// Get public keys of all stored keys. - pub fn contents(&self) -> Result> { - let mut public_keys: Vec = self.additional.keys().cloned().collect(); + pub fn contents(&self) -> Result> { + let mut public_keys: Vec = self.additional.keys() + .filter_map(|(ty, public)| { + if *ty != TPublic::KEY_TYPE { + return None + } + Some(TPublic::from_slice(public)) + }) + .collect(); + + let key_type: [u8; 4] = TPublic::KEY_TYPE.to_le_bytes(); for entry in fs::read_dir(&self.path)? { let entry = entry?; let path = entry.path(); // skip directories and non-unicode file names (hex is unicode) if let Some(name) = path.file_name().and_then(|n| n.to_str()) { - if name.len() != 64 { continue } - match hex::decode(name) { - Ok(ref hex) if hex.len() == 32 => { - let mut buf = [0; 32]; - buf.copy_from_slice(&hex[..]); - - public_keys.push(Public(buf)); + Ok(ref hex) => { + if hex[0..4] != key_type { continue } + let public = TPublic::from_slice(&hex[4..]); + public_keys.push(public); } _ => continue, } @@ -129,9 +151,12 @@ impl Store { Ok(public_keys) } - fn key_file_path(&self, public: &Public) -> PathBuf { + fn key_file_path(&self, public: &TPair::Public) -> PathBuf { let mut buf = self.path.clone(); - buf.push(hex::encode(public.as_slice())); + let bytes: [u8; 4] = TPair::KEY_TYPE.to_le_bytes(); + let key_type = hex::encode(bytes); + let key = hex::encode(public.as_slice()); + buf.push(key_type + key.as_str()); buf } } @@ -140,6 +165,7 @@ impl Store { mod tests { use super::*; use tempdir::TempDir; + use substrate_primitives::ed25519; use substrate_primitives::crypto::Ss58Codec; #[test] @@ -147,16 +173,16 @@ mod tests { let temp_dir = TempDir::new("keystore").unwrap(); let store = Store::open(temp_dir.path().to_owned()).unwrap(); - assert!(store.contents().unwrap().is_empty()); + assert!(store.contents::().unwrap().is_empty()); - let key = store.generate("thepassword").unwrap(); - let key2 = store.load(&key.public(), "thepassword").unwrap(); + let key: ed25519::Pair = store.generate("thepassword").unwrap(); + let key2: ed25519::Pair = store.load(&key.public(), "thepassword").unwrap(); - assert!(store.load(&key.public(), "notthepassword").is_err()); + assert!(store.load::(&key.public(), "notthepassword").is_err()); assert_eq!(key.public(), key2.public()); - assert_eq!(store.contents().unwrap()[0], key.public()); + assert_eq!(store.contents::().unwrap()[0], key.public()); } #[test] @@ -164,7 +190,9 @@ mod tests { let temp_dir = TempDir::new("keystore").unwrap(); let mut store = Store::open(temp_dir.path().to_owned()).unwrap(); - let pair = store.generate_from_seed("0x3d97c819d68f9bafa7d6e79cb991eebcd77d966c5334c0b94d9e1fa7ad0869dc").unwrap(); + let pair: ed25519::Pair = store + .generate_from_seed("0x3d97c819d68f9bafa7d6e79cb991eebcd77d966c5334c0b94d9e1fa7ad0869dc") + .unwrap(); assert_eq!("5DKUrgFqCPV8iAXx9sjy1nyBygQCeiUYRFWurZGhnrn3HJCA", pair.public().to_ss58check()); } } diff --git a/core/network/Cargo.toml b/core/network/Cargo.toml index 56a69039c380898eca6f818ff8728f0c5e0b6161..8b343174706d24a0445e4d8ef1850e684daa66a1 100644 --- a/core/network/Cargo.toml +++ b/core/network/Cargo.toml @@ -9,23 +9,25 @@ edition = "2018" [dependencies] bytes = "0.4" derive_more = "0.14.0" +either = "1.5.2" log = "0.4" parking_lot = "0.8.0" bitflags = "1.0" fnv = "1.0" futures = "0.1.17" +futures03 = { package = "futures-preview", version = "0.3.0-alpha.17", features = ["compat"] } linked-hash-map = "0.5" linked_hash_set = "0.1.3" lru-cache = "0.1.1" rustc-hex = "2.0" rand = "0.6" -libp2p = { version = "0.9.1", default-features = false, features = ["secp256k1", "libp2p-websocket"] } -fork-tree = { path = "../../core/util/fork-tree" } +libp2p = { version = "0.10.0", default-features = false, features = ["secp256k1", "libp2p-websocket"] } +fork-tree = { path = "../../core/utils/fork-tree" } primitives = { package = "substrate-primitives", path = "../../core/primitives" } consensus = { package = "substrate-consensus-common", path = "../../core/consensus/common" } client = { package = "substrate-client", path = "../../core/client" } runtime_primitives = { package = "sr-primitives", path = "../../core/sr-primitives" } -parity-codec = { version = "3.3", features = ["derive"] } +parity-codec = { version = "4.1.1", features = ["derive"] } peerset = { package = "substrate-peerset", path = "../../core/peerset" } serde = { version = "1.0.70", features = ["derive"] } serde_json = "1.0.24" @@ -41,7 +43,7 @@ test_client = { package = "substrate-test-client", path = "../../core/test-clien test-client = { package = "substrate-test-runtime-client", path = "../../core/test-runtime/client", optional = true } erased-serde = "0.3.9" void = "1.0" -zeroize = "0.6.0" +zeroize = "0.9.0" [dev-dependencies] env_logger = { version = "0.6" } @@ -50,10 +52,9 @@ quickcheck = "0.8.5" rand = "0.6.5" test-client = { package = "substrate-test-runtime-client", path = "../../core/test-runtime/client" } test_runtime = { package = "substrate-test-runtime", path = "../../core/test-runtime" } -consensus = { package = "substrate-consensus-common", path = "../../core/consensus/common", features = ["test-helpers"] } tempdir = "0.3" tokio = "0.1.11" [features] default = [] -test-helpers = ["keyring", "test-client", "consensus/test-helpers", "tokio"] +test-helpers = ["keyring", "test-client", "tokio"] diff --git a/core/network/src/behaviour.rs b/core/network/src/behaviour.rs index 35684bc2571edbd22200781835a7536b78c9d07b..2550e906600cb35a3e3dfa837648f01fea87db4e 100644 --- a/core/network/src/behaviour.rs +++ b/core/network/src/behaviour.rs @@ -14,72 +14,59 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use crate::{debug_info, discovery::DiscoveryBehaviour, discovery::DiscoveryOut, DiscoveryNetBehaviour}; +use crate::{ + debug_info, discovery::DiscoveryBehaviour, discovery::DiscoveryOut, DiscoveryNetBehaviour, + protocol::event::DhtEvent +}; +use crate::{ExHashT, specialization::NetworkSpecialization}; +use crate::protocol::{CustomMessageOutcome, Protocol}; use futures::prelude::*; use libp2p::NetworkBehaviour; -use libp2p::core::{Multiaddr, PeerId, ProtocolsHandler, protocols_handler::IntoProtocolsHandler, PublicKey}; -use libp2p::core::swarm::{ConnectedPoint, NetworkBehaviour, NetworkBehaviourAction}; -use libp2p::core::swarm::{NetworkBehaviourEventProcess, PollParameters}; -#[cfg(not(target_os = "unknown"))] -use libp2p::core::swarm::toggle::Toggle; -#[cfg(not(target_os = "unknown"))] -use libp2p::mdns::{Mdns, MdnsEvent}; +use libp2p::core::{Multiaddr, PeerId, PublicKey}; +use libp2p::core::swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess}; +use libp2p::core::{nodes::Substream, muxing::StreamMuxerBox}; +use libp2p::multihash::Multihash; use log::warn; +use runtime_primitives::traits::Block as BlockT; use std::iter; use void; -/// General behaviour of the network. +/// General behaviour of the network. Combines all protocols together. #[derive(NetworkBehaviour)] -#[behaviour(out_event = "TBehaviourEv", poll_method = "poll")] -pub struct Behaviour { - /// Main protocol that handles everything except the discovery and the technicalities. - user_protocol: UserBehaviourWrap, +#[behaviour(out_event = "BehaviourOut", poll_method = "poll")] +pub struct Behaviour, H: ExHashT> { + /// All the substrate-specific protocols. + substrate: Protocol, /// Periodically pings and identifies the nodes we are connected to, and store information in a /// cache. - debug_info: debug_info::DebugInfoBehaviour, - /// Discovers nodes of the network. Defined below. - discovery: DiscoveryBehaviour, - /// Discovers nodes on the local network. - #[cfg(not(target_os = "unknown"))] - mdns: Toggle>, + debug_info: debug_info::DebugInfoBehaviour>, + /// Discovers nodes of the network. + discovery: DiscoveryBehaviour>, /// Queue of events to produce for the outside. #[behaviour(ignore)] - events: Vec, + events: Vec>, } -impl Behaviour { +/// Event generated by `Behaviour`. +pub enum BehaviourOut { + SubstrateAction(CustomMessageOutcome), + Dht(DhtEvent), +} + +impl, H: ExHashT> Behaviour { /// Builds a new `Behaviour`. pub fn new( - user_protocol: TBehaviour, + substrate: Protocol, user_agent: String, local_public_key: PublicKey, known_addresses: Vec<(PeerId, Multiaddr)>, enable_mdns: bool, ) -> Self { - let debug_info = debug_info::DebugInfoBehaviour::new(user_agent, local_public_key.clone()); - - if enable_mdns { - #[cfg(target_os = "unknown")] - warn!(target: "sub-libp2p", "mDNS is not available on this platform"); - } - Behaviour { - user_protocol: UserBehaviourWrap(user_protocol), - debug_info, - discovery: DiscoveryBehaviour::new(local_public_key, known_addresses), - #[cfg(not(target_os = "unknown"))] - mdns: if enable_mdns { - match Mdns::new() { - Ok(mdns) => Some(mdns).into(), - Err(err) => { - warn!(target: "sub-libp2p", "Failed to initialize mDNS: {:?}", err); - None.into() - } - } - } else { - None.into() - }, + substrate, + debug_info: debug_info::DebugInfoBehaviour::new(user_agent, local_public_key.clone()), + discovery: DiscoveryBehaviour::new(local_public_key, known_addresses, enable_mdns), events: Vec::new(), } } @@ -104,33 +91,42 @@ impl Behaviour &TBehaviour { - &self.user_protocol.0 + pub fn user_protocol(&self) -> &Protocol { + &self.substrate } /// Returns a mutable reference to the user protocol. - pub fn user_protocol_mut(&mut self) -> &mut TBehaviour { - &mut self.user_protocol.0 + pub fn user_protocol_mut(&mut self) -> &mut Protocol { + &mut self.substrate + } + + /// Start querying a record from the DHT. Will later produce either a `ValueFound` or a `ValueNotFound` event. + pub fn get_value(&mut self, key: &Multihash) { + self.discovery.get_value(key); + } + + /// Starts putting a record into DHT. Will later produce either a `ValuePut` or a `ValuePutFailed` event. + pub fn put_value(&mut self, key: Multihash, value: Vec) { + self.discovery.put_value(key, value); } } -impl NetworkBehaviourEventProcess for -Behaviour { +impl, H: ExHashT> NetworkBehaviourEventProcess for +Behaviour { fn inject_event(&mut self, event: void::Void) { void::unreachable(event) } } -impl NetworkBehaviourEventProcess> for -Behaviour { - fn inject_event(&mut self, event: UserEventWrap) { - self.events.push(event.0); +impl, H: ExHashT> NetworkBehaviourEventProcess> for +Behaviour { + fn inject_event(&mut self, event: CustomMessageOutcome) { + self.events.push(BehaviourOut::SubstrateAction(event)); } } -impl NetworkBehaviourEventProcess - for Behaviour - where TBehaviour: DiscoveryNetBehaviour { +impl, H: ExHashT> NetworkBehaviourEventProcess + for Behaviour { fn inject_event(&mut self, event: debug_info::DebugInfoEvent) { let debug_info::DebugInfoEvent::Identified { peer_id, mut info } = event; if !info.protocol_version.contains("substrate") { @@ -146,38 +142,35 @@ impl NetworkBehaviourEventProcess NetworkBehaviourEventProcess - for Behaviour - where TBehaviour: DiscoveryNetBehaviour { +impl, H: ExHashT> NetworkBehaviourEventProcess + for Behaviour { fn inject_event(&mut self, out: DiscoveryOut) { match out { DiscoveryOut::Discovered(peer_id) => { - self.user_protocol.0.add_discovered_nodes(iter::once(peer_id)); + self.substrate.add_discovered_nodes(iter::once(peer_id)); + } + DiscoveryOut::ValueFound(results) => { + self.events.push(BehaviourOut::Dht(DhtEvent::ValueFound(results))); + } + DiscoveryOut::ValueNotFound(key) => { + self.events.push(BehaviourOut::Dht(DhtEvent::ValueNotFound(key))); + } + DiscoveryOut::ValuePut(key) => { + self.events.push(BehaviourOut::Dht(DhtEvent::ValuePut(key))); + } + DiscoveryOut::ValuePutFailed(key) => { + self.events.push(BehaviourOut::Dht(DhtEvent::ValuePutFailed(key))); } } } } -#[cfg(not(target_os = "unknown"))] -impl NetworkBehaviourEventProcess for - Behaviour - where TBehaviour: DiscoveryNetBehaviour { - fn inject_event(&mut self, event: MdnsEvent) { - match event { - MdnsEvent::Discovered(list) => { - self.user_protocol.0.add_discovered_nodes(list.into_iter().map(|(peer_id, _)| peer_id)); - }, - MdnsEvent::Expired(_) => {} - } - } -} - -impl Behaviour { - fn poll(&mut self) -> Async> { +impl, H: ExHashT> Behaviour { + fn poll(&mut self) -> Async>> { if !self.events.is_empty() { return Async::Ready(NetworkBehaviourAction::GenerateEvent(self.events.remove(0))) } @@ -185,71 +178,3 @@ impl Behaviour(TInner); -/// Event produced by `UserBehaviourWrap`. -pub struct UserEventWrap(TInner); -impl NetworkBehaviour for UserBehaviourWrap { - type ProtocolsHandler = TInner::ProtocolsHandler; - type OutEvent = UserEventWrap; - fn new_handler(&mut self) -> Self::ProtocolsHandler { self.0.new_handler() } - fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec { - self.0.addresses_of_peer(peer_id) - } - fn inject_connected(&mut self, peer_id: PeerId, endpoint: ConnectedPoint) { - self.0.inject_connected(peer_id, endpoint) - } - fn inject_disconnected(&mut self, peer_id: &PeerId, endpoint: ConnectedPoint) { - self.0.inject_disconnected(peer_id, endpoint) - } - fn inject_node_event( - &mut self, - peer_id: PeerId, - event: <::Handler as ProtocolsHandler>::OutEvent - ) { - self.0.inject_node_event(peer_id, event) - } - fn poll( - &mut self, - params: &mut PollParameters - ) -> Async< - NetworkBehaviourAction< - <::Handler as ProtocolsHandler>::InEvent, - Self::OutEvent - > - > { - match self.0.poll(params) { - Async::NotReady => Async::NotReady, - Async::Ready(NetworkBehaviourAction::GenerateEvent(ev)) => - Async::Ready(NetworkBehaviourAction::GenerateEvent(UserEventWrap(ev))), - Async::Ready(NetworkBehaviourAction::DialAddress { address }) => - Async::Ready(NetworkBehaviourAction::DialAddress { address }), - Async::Ready(NetworkBehaviourAction::DialPeer { peer_id }) => - Async::Ready(NetworkBehaviourAction::DialPeer { peer_id }), - Async::Ready(NetworkBehaviourAction::SendEvent { peer_id, event }) => - Async::Ready(NetworkBehaviourAction::SendEvent { peer_id, event }), - Async::Ready(NetworkBehaviourAction::ReportObservedAddr { address }) => - Async::Ready(NetworkBehaviourAction::ReportObservedAddr { address }), - } - } - fn inject_replaced(&mut self, peer_id: PeerId, closed_endpoint: ConnectedPoint, new_endpoint: ConnectedPoint) { - self.0.inject_replaced(peer_id, closed_endpoint, new_endpoint) - } - fn inject_addr_reach_failure(&mut self, peer_id: Option<&PeerId>, addr: &Multiaddr, error: &dyn std::error::Error) { - self.0.inject_addr_reach_failure(peer_id, addr, error) - } - fn inject_dial_failure(&mut self, peer_id: &PeerId) { - self.0.inject_dial_failure(peer_id) - } - fn inject_new_listen_addr(&mut self, addr: &Multiaddr) { - self.0.inject_new_listen_addr(addr) - } - fn inject_expired_listen_addr(&mut self, addr: &Multiaddr) { - self.0.inject_expired_listen_addr(addr) - } - fn inject_new_external_addr(&mut self, addr: &Multiaddr) { - self.0.inject_new_external_addr(addr) - } -} diff --git a/core/network/src/config.rs b/core/network/src/config.rs index fd0a3a924eef1c6e6af423db14f11b9b974aa0a4..7c7c540d1175c23f783d120f72e239a538dbadf2 100644 --- a/core/network/src/config.rs +++ b/core/network/src/config.rs @@ -14,11 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! Configuration for the networking layer of Substrate. +//! Configuration of the networking layer. +//! +//! The [`Params`] struct is the struct that must be passed in order to initialize the networking. +//! See the documentation of [`Params`]. pub use crate::protocol::ProtocolConfig; +pub use libp2p::{identity, core::PublicKey, wasm_ext::ExtTransport, build_multiaddr}; -use crate::ProtocolId; use crate::chain::{Client, FinalityProofProvider}; use crate::on_demand_layer::OnDemand; use crate::service::{ExHashT, TransactionPool}; @@ -29,30 +32,54 @@ use runtime_primitives::traits::{Block as BlockT}; use std::sync::Arc; use libp2p::identity::{Keypair, secp256k1, ed25519}; use libp2p::wasm_ext; -use libp2p::{Multiaddr, multiaddr::Protocol}; +use libp2p::{PeerId, Multiaddr, multiaddr}; use std::error::Error; -use std::{io::{self, Write}, iter, fs, net::Ipv4Addr, path::{Path, PathBuf}}; +use std::{io::{self, Write}, iter, fmt, fs, net::Ipv4Addr, path::{Path, PathBuf}}; use zeroize::Zeroize; -/// Service initialization parameters. +/// Network initialization parameters. pub struct Params { - /// Assigned roles for our node. + /// Assigned roles for our node (full, light, ...). pub roles: Roles, + /// Network layer configuration. pub network_config: NetworkConfiguration, - /// Substrate relay chain access point. + + /// Client that contains the blockchain. pub chain: Arc>, + /// Finality proof provider. + /// + /// This object, if `Some`, is used when a node on the network requests a proof of finality + /// from us. pub finality_proof_provider: Option>>, - /// On-demand service reference. + + /// How to build requests for proofs of finality. + /// + /// This object, if `Some`, is used when we need a proof of finality from another node. + pub finality_proof_request_builder: Option>, + + /// The `OnDemand` object acts as a "receiver" for block data requests from the client. + /// If `Some`, the network worker will process these requests and answer them. + /// Normally used only for light clients. pub on_demand: Option>>, - /// Transaction pool. + + /// Pool of transactions. + /// + /// The network worker will fetch transactions from this object in order to propagate them on + /// the network. pub transaction_pool: Arc>, + /// Name of the protocol to use on the wire. Should be different for each chain. pub protocol_id: ProtocolId, + /// Import queue to use. + /// + /// The import queue is the component that verifies that blocks received from other nodes are + /// valid. pub import_queue: Box>, - /// Protocol specialization. + + /// Customization of the network. Use this to plug additional networking capabilities. pub specialization: S, } @@ -94,6 +121,104 @@ impl parity_codec::Decode for Roles { } } +/// Finality proof request builder. +pub trait FinalityProofRequestBuilder: Send { + /// Build data blob, associated with the request. + fn build_request_data(&mut self, hash: &B::Hash) -> Vec; +} + +/// Implementation of `FinalityProofRequestBuilder` that builds a dummy empty request. +#[derive(Debug, Default)] +pub struct DummyFinalityProofRequestBuilder; + +impl FinalityProofRequestBuilder for DummyFinalityProofRequestBuilder { + fn build_request_data(&mut self, _: &B::Hash) -> Vec { + Vec::new() + } +} + +/// Shared finality proof request builder struct used by the queue. +pub type BoxFinalityProofRequestBuilder = Box + Send + Sync>; + +/// Name of a protocol, transmitted on the wire. Should be unique for each chain. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ProtocolId(smallvec::SmallVec<[u8; 6]>); + +impl<'a> From<&'a [u8]> for ProtocolId { + fn from(bytes: &'a [u8]) -> ProtocolId { + ProtocolId(bytes.into()) + } +} + +impl ProtocolId { + /// Exposes the `ProtocolId` as bytes. + pub fn as_bytes(&self) -> &[u8] { + self.0.as_ref() + } +} + +/// Parses a string address and returns the component, if valid. +/// +/// # Example +/// +/// ``` +/// # use substrate_network::{Multiaddr, PeerId, config::parse_str_addr}; +/// let (peer_id, addr) = parse_str_addr( +/// "/ip4/198.51.100.19/tcp/30333/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV" +/// ).unwrap(); +/// assert_eq!(peer_id, "QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV".parse::().unwrap()); +/// assert_eq!(addr, "/ip4/198.51.100.19/tcp/30333".parse::().unwrap()); +/// ``` +/// +pub fn parse_str_addr(addr_str: &str) -> Result<(PeerId, Multiaddr), ParseErr> { + let mut addr: Multiaddr = addr_str.parse()?; + + let who = match addr.pop() { + Some(multiaddr::Protocol::P2p(key)) => PeerId::from_multihash(key) + .map_err(|_| ParseErr::InvalidPeerId)?, + _ => return Err(ParseErr::PeerIdMissing), + }; + + Ok((who, addr)) +} + +/// Error that can be generated by `parse_str_addr`. +#[derive(Debug)] +pub enum ParseErr { + /// Error while parsing the multiaddress. + MultiaddrParse(multiaddr::Error), + /// Multihash of the peer ID is invalid. + InvalidPeerId, + /// The peer ID is missing from the address. + PeerIdMissing, +} + +impl fmt::Display for ParseErr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ParseErr::MultiaddrParse(err) => write!(f, "{}", err), + ParseErr::InvalidPeerId => write!(f, "Peer id at the end of the address is invalid"), + ParseErr::PeerIdMissing => write!(f, "Peer id is missing from the address"), + } + } +} + +impl std::error::Error for ParseErr { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + ParseErr::MultiaddrParse(err) => Some(err), + ParseErr::InvalidPeerId => None, + ParseErr::PeerIdMissing => None, + } + } +} + +impl From for ParseErr { + fn from(err: multiaddr::Error) -> ParseErr { + ParseErr::MultiaddrParse(err) + } +} + /// Network service configuration. #[derive(Clone)] pub struct NetworkConfiguration { @@ -121,16 +246,8 @@ pub struct NetworkConfiguration { pub client_version: String, /// Name of the node. Sent over the wire for debugging purposes. pub node_name: String, - /// If true, the network will use mDNS to discover other libp2p nodes on the local network - /// and connect to them if they support the same chain. - pub enable_mdns: bool, - /// Optional external implementation of a libp2p transport. Used in WASM contexts where we need - /// some binding between the networking provided by the operating system or environment and - /// libp2p. - /// - /// This parameter exists whatever the target platform is, but it is expected to be set to - /// `Some` only when compiling for WASM. - pub wasm_external_transport: Option, + /// Configuration for the transport layer. + pub transport: TransportConfig, } impl Default for NetworkConfiguration { @@ -148,8 +265,10 @@ impl Default for NetworkConfiguration { non_reserved_mode: NonReservedPeerMode::Accept, client_version: "unknown".into(), node_name: "unknown".into(), - enable_mdns: false, - wasm_external_transport: None, + transport: TransportConfig::Normal { + enable_mdns: false, + wasm_external_transport: None, + }, } } } @@ -164,14 +283,48 @@ impl NetworkConfiguration { pub fn new_local() -> NetworkConfiguration { let mut config = NetworkConfiguration::new(); config.listen_addresses = vec![ - iter::once(Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1))) - .chain(iter::once(Protocol::Tcp(0))) + iter::once(multiaddr::Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1))) + .chain(iter::once(multiaddr::Protocol::Tcp(0))) + .collect() + ]; + config + } + + /// Create new default configuration for localhost-only connection with random port (useful for testing) + pub fn new_memory() -> NetworkConfiguration { + let mut config = NetworkConfiguration::new(); + config.listen_addresses = vec![ + iter::once(multiaddr::Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1))) + .chain(iter::once(multiaddr::Protocol::Tcp(0))) .collect() ]; config } } +/// Configuration for the transport layer. +#[derive(Clone)] +pub enum TransportConfig { + /// Normal transport mode. + Normal { + /// If true, the network will use mDNS to discover other libp2p nodes on the local network + /// and connect to them if they support the same chain. + enable_mdns: bool, + + /// Optional external implementation of a libp2p transport. Used in WASM contexts where we + /// need some binding between the networking provided by the operating system or environment + /// and libp2p. + /// + /// This parameter exists whatever the target platform is, but it is expected to be set to + /// `Some` only when compiling for WASM. + wasm_external_transport: Option, + }, + + /// Only allow connections within the same process. + /// Only addresses of the form `/memory/...` will be supported. + MemoryOnly, +} + /// The policy for connections to non-reserved peers. #[derive(Clone, Debug, PartialEq, Eq)] pub enum NonReservedPeerMode { diff --git a/core/network/src/custom_proto/behaviour.rs b/core/network/src/custom_proto/behaviour.rs index 975a1d2f3a030783afcfbaff2fef34ded42ae017..f6510c1a399c57a7a21860b96e9b6d3e6f033e30 100644 --- a/core/network/src/custom_proto/behaviour.rs +++ b/core/network/src/custom_proto/behaviour.rs @@ -14,16 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use crate::{DiscoveryNetBehaviour, ProtocolId}; +use crate::{DiscoveryNetBehaviour, config::ProtocolId}; use crate::custom_proto::handler::{CustomProtoHandlerProto, CustomProtoHandlerOut, CustomProtoHandlerIn}; use crate::custom_proto::upgrade::{CustomMessage, RegisteredProtocol}; use fnv::FnvHashMap; use futures::prelude::*; +use futures03::{StreamExt as _, TryStreamExt as _}; use libp2p::core::swarm::{ConnectedPoint, NetworkBehaviour, NetworkBehaviourAction, PollParameters}; use libp2p::core::{Multiaddr, PeerId}; use log::{debug, error, trace, warn}; use smallvec::SmallVec; -use std::{borrow::Cow, collections::hash_map::Entry, cmp, error, marker::PhantomData, mem}; +use std::{borrow::Cow, collections::hash_map::Entry, cmp, error, marker::PhantomData, mem, pin::Pin}; use std::time::{Duration, Instant}; use tokio_io::{AsyncRead, AsyncWrite}; use tokio_timer::clock::Clock; @@ -932,7 +933,7 @@ where fn poll( &mut self, - _params: &mut PollParameters, + _params: &mut impl PollParameters, ) -> Async< NetworkBehaviourAction< CustomProtoHandlerIn, @@ -942,7 +943,10 @@ where // Poll for instructions from the peerset. // Note that the peerset is a *best effort* crate, and we have to use defensive programming. loop { - match self.peerset.poll() { + let mut peerset01 = futures03::stream::poll_fn(|cx| + futures03::Stream::poll_next(Pin::new(&mut self.peerset), cx) + ).map(|v| Ok::<_, ()>(v)).compat(); + match peerset01.poll() { Ok(Async::Ready(Some(peerset::Message::Accept(index)))) => { self.peerset_report_accept(index); } diff --git a/core/network/src/custom_proto/tests.rs b/core/network/src/custom_proto/tests.rs index 37d4db29e6887d84a71983945e22845ca8d095d5..33ff81be4752e553172a07474a68156d00fc7850 100644 --- a/core/network/src/custom_proto/tests.rs +++ b/core/network/src/custom_proto/tests.rs @@ -26,7 +26,7 @@ use libp2p::{PeerId, Multiaddr, Transport}; use rand::seq::SliceRandom; use std::{io, time::Duration, time::Instant}; use test_client::runtime::Block; -use crate::protocol::message::{Message as MessageAlias, generic::Message}; +use crate::message::{Message as MessageAlias, generic::Message}; use crate::custom_proto::{CustomProto, CustomProtoOut, CustomMessage}; /// Builds two nodes that have each other as bootstrap nodes. @@ -157,7 +157,7 @@ impl NetworkBehaviour for CustomProtoWithAddr fn poll( &mut self, - params: &mut PollParameters + params: &mut impl PollParameters ) -> Async< NetworkBehaviourAction< <::Handler as ProtocolsHandler>::InEvent, diff --git a/core/network/src/custom_proto/upgrade.rs b/core/network/src/custom_proto/upgrade.rs index 9ede4753494c6f78312b1e6327ae17137c1bcc26..4cb6cb5dd9042e4333d6982eb31349565b3a5253 100644 --- a/core/network/src/custom_proto/upgrade.rs +++ b/core/network/src/custom_proto/upgrade.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use crate::ProtocolId; +use crate::config::ProtocolId; use bytes::Bytes; use libp2p::core::{Negotiated, Endpoint, UpgradeInfo, InboundUpgrade, OutboundUpgrade, upgrade::ProtocolName}; use libp2p::tokio_codec::Framed; diff --git a/core/network/src/debug_info.rs b/core/network/src/debug_info.rs index f482f13fc201ebef18ab27dda5fc952d97bf3a4b..f8e688acba500dc28a0d1f27802bbef4ec99f9e9 100644 --- a/core/network/src/debug_info.rs +++ b/core/network/src/debug_info.rs @@ -253,7 +253,7 @@ where TSubstream: AsyncRead + AsyncWrite { fn poll( &mut self, - params: &mut PollParameters + params: &mut impl PollParameters ) -> Async< NetworkBehaviourAction< <::Handler as ProtocolsHandler>::InEvent, diff --git a/core/network/src/discovery.rs b/core/network/src/discovery.rs index 4e44d9fa9ec732e08eeb4f8bace3515a70194c8f..1a377ba8721e1950716b3d17d1056bb9c7daa5e8 100644 --- a/core/network/src/discovery.rs +++ b/core/network/src/discovery.rs @@ -14,14 +14,50 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . +//! Discovery mechanisms of Substrate. +//! +//! The `DiscoveryBehaviour` struct implements the `NetworkBehaviour` trait of libp2p and is +//! responsible for discovering other nodes that are part of the network. +//! +//! Substrate uses the following mechanisms in order to discover nodes that are part of the network: +//! +//! - Bootstrap nodes. These are hard-coded node identities and addresses passed in the constructor +//! of the `DiscoveryBehaviour`. You can also call `add_known_address` later to add an entry. +//! +//! - mDNS. Discovers nodes on the local network by broadcasting UDP packets. +//! +//! - Kademlia random walk. Once connected, we perform random Kademlia `FIND_NODE` requests in +//! order for nodes to propagate to us their view of the network. This is performed automatically +//! by the `DiscoveryBehaviour`. +//! +//! Additionally, the `DiscoveryBehaviour` is also capable of storing and loading value in the +//! network-wide DHT. +//! +//! ## Usage +//! +//! The `DiscoveryBehaviour` generates events of type `DiscoveryOut`, most notably +//! `DiscoveryOut::Discovered` that is generated whenever we discover a node. +//! Only the identity of the node is returned. The node's addresses are stored within the +//! `DiscoveryBehaviour` and can be queried through the `NetworkBehaviour` trait. +//! +//! **Important**: In order for the discovery mechanism to work properly, there needs to be an +//! active mechanism that asks nodes for the addresses they are listening on. Whenever we learn +//! of a node's address, you must call `add_self_reported_address`. +//! + use futures::prelude::*; use libp2p::core::{Multiaddr, PeerId, ProtocolsHandler, PublicKey}; use libp2p::core::swarm::{ConnectedPoint, NetworkBehaviour, NetworkBehaviourAction}; use libp2p::core::swarm::PollParameters; -use libp2p::kad::{Kademlia, KademliaOut}; +#[cfg(not(target_os = "unknown"))] +use libp2p::core::{swarm::toggle::Toggle, nodes::Substream, muxing::StreamMuxerBox}; +use libp2p::kad::{GetValueResult, Kademlia, KademliaOut, PutValueResult}; +#[cfg(not(target_os = "unknown"))] +use libp2p::mdns::{Mdns, MdnsEvent}; +use libp2p::multihash::Multihash; use libp2p::multiaddr::Protocol; use log::{debug, info, trace, warn}; -use std::{cmp, time::Duration}; +use std::{cmp, collections::VecDeque, num::NonZeroU8, time::Duration}; use tokio_io::{AsyncRead, AsyncWrite}; use tokio_timer::{Delay, clock::Clock}; @@ -32,21 +68,37 @@ pub struct DiscoveryBehaviour { user_defined: Vec<(PeerId, Multiaddr)>, /// Kademlia requests and answers. kademlia: Kademlia, + /// Discovers nodes on the local network. + #[cfg(not(target_os = "unknown"))] + mdns: Toggle>>, /// Stream that fires when we need to perform the next random Kademlia query. next_kad_random_query: Delay, /// After `next_kad_random_query` triggers, the next one triggers after this duration. duration_to_next_kad: Duration, + /// Discovered nodes to return. + discoveries: VecDeque, /// `Clock` instance that uses the current execution context's source of time. clock: Clock, /// Identity of our local node. local_peer_id: PeerId, + /// Number of nodes we're currently connected to. + num_connections: u64, } impl DiscoveryBehaviour { /// Builds a new `DiscoveryBehaviour`. /// /// `user_defined` is a list of known address for nodes that never expire. - pub fn new(local_public_key: PublicKey, user_defined: Vec<(PeerId, Multiaddr)>) -> Self { + pub fn new( + local_public_key: PublicKey, + user_defined: Vec<(PeerId, Multiaddr)>, + enable_mdns: bool + ) -> Self { + if enable_mdns { + #[cfg(target_os = "unknown")] + warn!(target: "sub-libp2p", "mDNS is not available on this platform"); + } + let mut kademlia = Kademlia::new(local_public_key.clone().into_peer_id()); for (peer_id, addr) in &user_defined { kademlia.add_address(peer_id, addr.clone()); @@ -58,8 +110,22 @@ impl DiscoveryBehaviour { kademlia, next_kad_random_query: Delay::new(clock.now()), duration_to_next_kad: Duration::from_secs(1), + discoveries: VecDeque::new(), clock, local_peer_id: local_public_key.into_peer_id(), + num_connections: 0, + #[cfg(not(target_os = "unknown"))] + mdns: if enable_mdns { + match Mdns::new() { + Ok(mdns) => Some(mdns).into(), + Err(err) => { + warn!(target: "sub-libp2p", "Failed to initialize mDNS: {:?}", err); + None.into() + } + } + } else { + None.into() + }, } } @@ -71,22 +137,56 @@ impl DiscoveryBehaviour { /// Adds a hard-coded address for the given peer, that never expires. /// /// This adds an entry to the parameter that was passed to `new`. + /// + /// If we didn't know this address before, also generates a `Discovered` event. pub fn add_known_address(&mut self, peer_id: PeerId, addr: Multiaddr) { if self.user_defined.iter().all(|(p, a)| *p != peer_id && *a != addr) { + self.discoveries.push_back(peer_id.clone()); self.user_defined.push((peer_id, addr)); } } /// Call this method when a node reports an address for itself. + /// + /// **Note**: It is important that you call this method, otherwise the discovery mechanism will + /// not properly work. pub fn add_self_reported_address(&mut self, peer_id: &PeerId, addr: Multiaddr) { self.kademlia.add_address(peer_id, addr); } + + /// Start fetching a record from the DHT. + /// + /// A corresponding `ValueFound` or `ValueNotFound` event will later be generated. + pub fn get_value(&mut self, key: &Multihash) { + self.kademlia.get_value(key, NonZeroU8::new(10) + .expect("Casting 10 to NonZeroU8 should succeed; qed")); + } + + /// Start putting a record into the DHT. Other nodes can later fetch that value with + /// `get_value`. + /// + /// A corresponding `ValuePut` or `ValuePutFailed` event will later be generated. + pub fn put_value(&mut self, key: Multihash, value: Vec) { + self.kademlia.put_value(key, value); + } } /// Event generated by the `DiscoveryBehaviour`. pub enum DiscoveryOut { /// We have discovered a node. Can be called multiple times with the same identity. Discovered(PeerId), + + /// The DHT yeided results for the record request, grouped in (key, value) pairs. + ValueFound(Vec<(Multihash, Vec)>), + + /// The record requested was not found in the DHT. + ValueNotFound(Multihash), + + /// The record with a given key was successfully inserted into the DHT. + ValuePut(Multihash), + + /// Inserting a value into the DHT failed. + ValuePutFailed(Multihash), } impl NetworkBehaviour for DiscoveryBehaviour @@ -119,10 +219,12 @@ where } fn inject_connected(&mut self, peer_id: PeerId, endpoint: ConnectedPoint) { + self.num_connections += 1; NetworkBehaviour::inject_connected(&mut self.kademlia, peer_id, endpoint) } fn inject_disconnected(&mut self, peer_id: &PeerId, endpoint: ConnectedPoint) { + self.num_connections -= 1; NetworkBehaviour::inject_disconnected(&mut self.kademlia, peer_id, endpoint) } @@ -150,45 +252,17 @@ where fn poll( &mut self, - params: &mut PollParameters, + params: &mut impl PollParameters, ) -> Async< NetworkBehaviourAction< ::InEvent, Self::OutEvent, >, > { - // Poll Kademlia. - match self.kademlia.poll(params) { - Async::NotReady => (), - Async::Ready(NetworkBehaviourAction::GenerateEvent(ev)) => { - match ev { - KademliaOut::Discovered { .. } => {} - KademliaOut::KBucketAdded { peer_id, .. } => { - let ev = DiscoveryOut::Discovered(peer_id); - return Async::Ready(NetworkBehaviourAction::GenerateEvent(ev)); - } - KademliaOut::FindNodeResult { key, closer_peers } => { - trace!(target: "sub-libp2p", "Libp2p => Query for {:?} yielded {:?} results", - key, closer_peers.len()); - if closer_peers.is_empty() { - warn!(target: "sub-libp2p", "Libp2p => Random Kademlia query has yielded empty \ - results"); - } - } - // We never start any other type of query. - KademliaOut::GetProvidersResult { .. } => {} - KademliaOut::GetValueResult(_) => {} - KademliaOut::PutValueResult(_) => {} - } - }, - Async::Ready(NetworkBehaviourAction::DialAddress { address }) => - return Async::Ready(NetworkBehaviourAction::DialAddress { address }), - Async::Ready(NetworkBehaviourAction::DialPeer { peer_id }) => - return Async::Ready(NetworkBehaviourAction::DialPeer { peer_id }), - Async::Ready(NetworkBehaviourAction::SendEvent { peer_id, event }) => - return Async::Ready(NetworkBehaviourAction::SendEvent { peer_id, event }), - Async::Ready(NetworkBehaviourAction::ReportObservedAddr { address }) => - return Async::Ready(NetworkBehaviourAction::ReportObservedAddr { address }), + // Immediately process the content of `discovered`. + if let Some(peer_id) = self.discoveries.pop_front() { + let ev = DiscoveryOut::Discovered(peer_id); + return Async::Ready(NetworkBehaviourAction::GenerateEvent(ev)); } // Poll the stream that fires when we need to start a random Kademlia query. @@ -213,6 +287,95 @@ where } } + // Poll Kademlia. + loop { + match self.kademlia.poll(params) { + Async::NotReady => break, + Async::Ready(NetworkBehaviourAction::GenerateEvent(ev)) => { + match ev { + KademliaOut::Discovered { .. } => {} + KademliaOut::KBucketAdded { peer_id, .. } => { + let ev = DiscoveryOut::Discovered(peer_id); + return Async::Ready(NetworkBehaviourAction::GenerateEvent(ev)); + } + KademliaOut::FindNodeResult { key, closer_peers } => { + trace!(target: "sub-libp2p", "Libp2p => Query for {:?} yielded {:?} results", + key, closer_peers.len()); + if closer_peers.is_empty() && self.num_connections != 0 { + warn!(target: "sub-libp2p", "Libp2p => Random Kademlia query has yielded empty \ + results"); + } + } + KademliaOut::GetValueResult(res) => { + let ev = match res { + GetValueResult::Found { results } => { + let results = results + .into_iter() + .map(|r| (r.key, r.value)) + .collect(); + + DiscoveryOut::ValueFound(results) + } + GetValueResult::NotFound { key, .. } => { + DiscoveryOut::ValueNotFound(key) + } + }; + return Async::Ready(NetworkBehaviourAction::GenerateEvent(ev)); + } + KademliaOut::PutValueResult(res) => { + let ev = match res { + PutValueResult::Ok{ key, .. } => { + DiscoveryOut::ValuePut(key) + } + PutValueResult::Err { key, .. } => { + DiscoveryOut::ValuePutFailed(key) + } + }; + return Async::Ready(NetworkBehaviourAction::GenerateEvent(ev)); + } + // We never start any other type of query. + KademliaOut::GetProvidersResult { .. } => {} + } + }, + Async::Ready(NetworkBehaviourAction::DialAddress { address }) => + return Async::Ready(NetworkBehaviourAction::DialAddress { address }), + Async::Ready(NetworkBehaviourAction::DialPeer { peer_id }) => + return Async::Ready(NetworkBehaviourAction::DialPeer { peer_id }), + Async::Ready(NetworkBehaviourAction::SendEvent { peer_id, event }) => + return Async::Ready(NetworkBehaviourAction::SendEvent { peer_id, event }), + Async::Ready(NetworkBehaviourAction::ReportObservedAddr { address }) => + return Async::Ready(NetworkBehaviourAction::ReportObservedAddr { address }), + } + } + + // Poll mDNS. + #[cfg(not(target_os = "unknown"))] + loop { + match self.mdns.poll(params) { + Async::NotReady => break, + Async::Ready(NetworkBehaviourAction::GenerateEvent(event)) => { + match event { + MdnsEvent::Discovered(list) => { + self.discoveries.extend(list.into_iter().map(|(peer_id, _)| peer_id)); + if let Some(peer_id) = self.discoveries.pop_front() { + let ev = DiscoveryOut::Discovered(peer_id); + return Async::Ready(NetworkBehaviourAction::GenerateEvent(ev)); + } + }, + MdnsEvent::Expired(_) => {} + } + }, + Async::Ready(NetworkBehaviourAction::DialAddress { address }) => + return Async::Ready(NetworkBehaviourAction::DialAddress { address }), + Async::Ready(NetworkBehaviourAction::DialPeer { peer_id }) => + return Async::Ready(NetworkBehaviourAction::DialPeer { peer_id }), + Async::Ready(NetworkBehaviourAction::SendEvent { event, .. }) => + match event {}, // `event` is an enum with no variant + Async::Ready(NetworkBehaviourAction::ReportObservedAddr { address }) => + return Async::Ready(NetworkBehaviourAction::ReportObservedAddr { address }), + } + } + Async::NotReady } } @@ -247,7 +410,7 @@ mod tests { upgrade::apply(out.stream, upgrade, endpoint) }); - let behaviour = DiscoveryBehaviour::new(keypair.public(), user_defined.clone()); + let behaviour = DiscoveryBehaviour::new(keypair.public(), user_defined.clone(), false); let mut swarm = Swarm::new(transport, behaviour, keypair.public().into_peer_id()); let listen_addr: Multiaddr = format!("/memory/{}", rand::random::()).parse().unwrap(); diff --git a/core/network/src/lib.rs b/core/network/src/lib.rs index 105b02131592d416dcc6f928496301dc0ea0066c..98cbf75c63fcc1e813f3997e2ffa2dbb8f0803a1 100644 --- a/core/network/src/lib.rs +++ b/core/network/src/lib.rs @@ -17,11 +17,158 @@ #![warn(unused_extern_crates)] #![warn(missing_docs)] -//! Substrate-specific P2P networking: synchronizing blocks, propagating BFT messages. -//! Allows attachment of an optional subprotocol for chain-specific requests. +//! Substrate-specific P2P networking. //! //! **Important**: This crate is unstable and the API and usage may change. //! +//! # Node identities and addresses +//! +//! In a decentralized network, each node possesses a network private key and a network public key. +//! In Substrate, the keys are based on the ed25519 curve. As of the writing of this documentation, +//! the secp256k1 curve can also be used, but is deprecated. Our local node's keypair must be +//! passed as part of the network configuration. +//! +//! From a node's public key, we can derive its *identity*. In Substrate and libp2p, a node's +//! identity is represented with the [`PeerId`] struct. All network communications between nodes on +//! the network use encryption derived from both sides's keys, which means that **identities cannot +//! be faked**. +//! +//! A node's identity uniquely identifies a machine on the network. If you start two or more +//! clients using the same network key, large interferences will happen. +//! +//! # Substrate's network protocol +//! +//! Substrate's networking protocol is based upon libp2p. It is at the moment not possible and not +//! planned to permit using something else than the libp2p network stack and the rust-libp2p +//! library. However the libp2p framework is very flexible and the rust-libp2p library could be +//! extended to support a wider range of protocols than what is offered by libp2p. +//! +//! ## Discovery mechanisms +//! +//! In order for our node to join a peer-to-peer network, it has to know a list of nodes that are +//! part of said network. This includes nodes identities and their address (how to reach them). +//! Building such a list is called the **discovery** mechanism. There are three mechanisms that +//! Substrate uses: +//! +//! - Bootstrap nodes. These are hard-coded node identities and addresses passed alongside with +//! the network configuration. +//! - mDNS. We perform a UDP broadcast on the local network. Nodes that listen may respond with +//! their identity. More info [here](https://github.com/libp2p/specs/blob/master/discovery/mdns.md). +//! mDNS can be disabled in the network configuration. +//! - Kademlia random walk. Once connected, we perform random Kademlia `FIND_NODE` requests in +//! order for nodes to propagate to us their view of the network. More information about Kademlia +//! can be found [on Wikipedia](https://en.wikipedia.org/wiki/Kademlia). +//! +//! ## Connection establishment +//! +//! When node Alice knows node Bob's identity and address, it can establish a connection with Bob. +//! All connections must always use encryption and multiplexing. While some node addresses (eg. +//! addresses using `/quic`) already imply which encryption and/or multiplexing to use, for others +//! the **multistream-select** protocol is used in order to negotiate an encryption layer and/or a +//! multiplexing layer. +//! +//! The connection establishment mechanism is called the **transport**. +//! +//! As of the writing of this documentation, the following base-layer protocols are supported by +//! Substrate: +//! +//! - TCP/IP for addresses of the form `/ip4/1.2.3.4/tcp/5`. Once the TCP connection is open, an +//! encryption and a multiplexing layer are negotiated on top. +//! - WebSockets for addresses of the form `/ip4/1.2.3.4/tcp/5/ws`. A TCP/IP connection is open and +//! the WebSockets protocol is negotiated on top. Communications then happen inside WebSockets data +//! frames. Encryption and multiplexing are additionally negotiated again inside this channel. +//! - DNS for addresses of the form `/dns4/example.com/tcp/5` or `/dns4/example.com/tcp/5/ws`. A +//! node's address can contain a domain name. +//! +//! The following encryption protocols are supported: +//! +//! - [Secio](https://github.com/libp2p/specs/tree/master/secio). A TLS-1.2-like protocol but +//! without certificates. Support for secio will likely be deprecated in the far future. +//! - [Noise](https://noiseprotocol.org/). Support for noise is very experimental. The details are +//! very blurry and may change at any moment. +//! +//! The following multiplexing protocols are supported: +//! +//! - [Mplex](https://github.com/libp2p/specs/tree/master/mplex). Support for mplex will likely +//! be deprecated in the future. +//! - [Yamux](https://github.com/hashicorp/yamux/blob/master/spec.md). +//! +//! ## Substreams +//! +//! Once a connection has been established and uses multiplexing, substreams can be opened. When +//! a substream is open, the **multistream-select** protocol is used to negotiate which protocol to +//! use on that given substream. In practice, Substrate opens the following substreams: +//! +//! - We periodically open an ephemeral substream in order to ping the remote and check whether the +//! connection is still alive. Failure for the remote to reply leads to a disconnection. This uses +//! the libp2p ping protocol. +//! - We periodically open an ephemeral substream in order to ask information from the remote. This +//! is called [the `identify` protocol](https://github.com/libp2p/specs/tree/master/identify). +//! - We periodically open ephemeral substreams for Kademlia random walk queries. Each Kademlia +//! query is done in a new separate substream. This uses the +//! [standard libp2p Kademlia protocol](https://github.com/libp2p/specs/pull/108). +//! - We optionally keep a substream alive for all Substrate-based communications. The name of the +//! protocol negotiated is based on the *protocol ID* passed as part of the network configuration. +//! This protocol ID should be unique for each chain and prevents nodes from different chains from +//! connecting to each other. More information below. +//! +//! ## The Substrate substream +//! +//! Substrate uses a component named the **peerset manager (PSM)**. Through the discovery +//! mechanism, the PSM is aware of the nodes that are part of the network and decides which nodes +//! we should perform Substrate-based communications with. For these nodes, we open a connection +//! if necessary and open a unique substream for Substrate-based communications. If the PSM decides +//! that we should disconnect a node, then that substream is closed. +//! +//! For more information about the PSM, see the *substrate-peerset* crate. +//! +//! Note that at the moment there is no mechanism in place to solve the issues that arise where the +//! two sides of a connection open the unique substream simultaneously. In order to not run into +//! issues, only the dialer of a connection is allowed to open the unique substream. When the +//! substream is closed, the entire connection is closed as well. This is a bug, and should be +//! fixed by improving the protocol. +//! +//! Within the unique Substrate substream, messages encoded using +//! [*parity-scale-codec*](https://github.com/paritytech/parity-scale-codec) are exchanged. +//! The detail of theses messages is not totally in place, but they can be found in the +//! `message.rs` file. +//! +//! Once the substream is open, the first step is an exchange of a *status* message from both +//! sides, containing information such as the chain root hash, head of chain, and so on. +//! +//! Communications within this substream include: +//! +//! - Syncing. Blocks are announced and requested from other nodes. +//! - Light-client requests. When a light client requires information, a random node we have a +//! substream open with is chosen, and the information is requested from it. +//! - Gossiping. Used for example by grandpa. +//! - Network specialization. The network protocol can be specialized through a template parameter +//! of the network service. This specialization is free to send and receive messages with the +//! remote. This is meant to be used by the chain that is being built on top of Substrate +//! (eg. Polkadot). +//! +//! It is intended that in the future each of these components gets more isolated, so that they +//! are free to open and close their own substreams, and so that syncing and light client requests +//! are able to communicate with nodes outside of the range of the PSM. +//! +//! # Usage +//! +//! Using the `substrate-network` crate is done through the [`NetworkWorker`] struct. Create this +//! struct by passing a [`config::Params`], then poll it as if it was a `Future`. You can extract an +//! `Arc` from the `NetworkWorker`, which can be shared amongst multiple places +//! in order to give orders to the networking. +//! +//! See the [`config`] module for more information about how to configure the networking. +//! +//! After the `NetworkWorker` has been created, the important things to do are: +//! +//! - Calling `NetworkWorker::poll` in order to advance the network. +//! - Calling `on_block_import` whenever a block is added to the client. +//! - Calling `on_block_finalized` whenever a block is finalized. +//! - Calling `trigger_repropagate` when a transaction is added to the pool. +//! +//! More precise usage details are still being worked on and will likely change in the future. +//! mod behaviour; mod chain; @@ -29,7 +176,6 @@ mod custom_proto; mod debug_info; mod discovery; mod on_demand_layer; -#[macro_use] mod protocol; mod service; mod transport; @@ -42,26 +188,25 @@ pub mod test; pub use chain::{Client as ClientHandle, FinalityProofProvider}; pub use service::{ - NetworkService, NetworkWorker, FetchFuture, TransactionPool, ManageNetwork, - NetworkMsg, ExHashT, ReportHandle, + NetworkService, NetworkWorker, TransactionPool, ExHashT, ReportHandle, }; -pub use config::{NodeKeyConfig, Secret, Secp256k1Secret, Ed25519Secret}; -pub use protocol::{ProtocolStatus, PeerInfo, Context, consensus_gossip, message, specialization}; -pub use protocol::sync::{Status as SyncStatus, SyncState}; -pub use libp2p::{Multiaddr, multiaddr, build_multiaddr}; -pub use libp2p::{identity, PeerId, core::PublicKey}; +pub use protocol::{PeerInfo, Context, consensus_gossip, message, specialization}; +pub use protocol::sync::SyncState; +pub use libp2p::{Multiaddr, PeerId}; +#[doc(inline)] +pub use libp2p::multiaddr; pub use message::{generic as generic_message, RequestId, Status as StatusMessage}; -pub use error::Error; -pub use protocol::on_demand::AlwaysBadChecker; pub use on_demand_layer::{OnDemand, RemoteResponse}; + +// Used by the `construct_simple_protocol!` macro. #[doc(hidden)] pub use runtime_primitives::traits::Block as BlockT; use libp2p::core::nodes::ConnectedPoint; use serde::{Deserialize, Serialize}; use slog_derive::SerdeValue; -use std::{collections::{HashMap, HashSet}, fmt, time::Duration}; +use std::{collections::{HashMap, HashSet}, time::Duration}; /// Extension trait for `NetworkBehaviour` that also accepts discovering nodes. pub trait DiscoveryNetBehaviour { @@ -74,73 +219,6 @@ pub trait DiscoveryNetBehaviour { fn add_discovered_nodes(&mut self, nodes: impl Iterator); } -/// Name of a protocol, transmitted on the wire. Should be unique for each chain. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ProtocolId(smallvec::SmallVec<[u8; 6]>); - -impl<'a> From<&'a [u8]> for ProtocolId { - fn from(bytes: &'a [u8]) -> ProtocolId { - ProtocolId(bytes.into()) - } -} - -impl ProtocolId { - /// Exposes the `ProtocolId` as bytes. - pub fn as_bytes(&self) -> &[u8] { - self.0.as_ref() - } -} - -/// Parses a string address and returns the component, if valid. -pub fn parse_str_addr(addr_str: &str) -> Result<(PeerId, Multiaddr), ParseErr> { - let mut addr: Multiaddr = addr_str.parse()?; - - let who = match addr.pop() { - Some(multiaddr::Protocol::P2p(key)) => PeerId::from_multihash(key) - .map_err(|_| ParseErr::InvalidPeerId)?, - _ => return Err(ParseErr::PeerIdMissing), - }; - - Ok((who, addr)) -} - -/// Error that can be generated by `parse_str_addr`. -#[derive(Debug)] -pub enum ParseErr { - /// Error while parsing the multiaddress. - MultiaddrParse(multiaddr::Error), - /// Multihash of the peer ID is invalid. - InvalidPeerId, - /// The peer ID is missing from the address. - PeerIdMissing, -} - -impl fmt::Display for ParseErr { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ParseErr::MultiaddrParse(err) => write!(f, "{}", err), - ParseErr::InvalidPeerId => write!(f, "Peer id at the end of the address is invalid"), - ParseErr::PeerIdMissing => write!(f, "Peer id is missing from the address"), - } - } -} - -impl std::error::Error for ParseErr { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - ParseErr::MultiaddrParse(err) => Some(err), - ParseErr::InvalidPeerId => None, - ParseErr::PeerIdMissing => None, - } - } -} - -impl From for ParseErr { - fn from(err: multiaddr::Error) -> ParseErr { - ParseErr::MultiaddrParse(err) - } -} - /// Returns general information about the networking. /// /// Meant for general diagnostic purposes. diff --git a/core/network/src/on_demand_layer.rs b/core/network/src/on_demand_layer.rs index 86b3d6b7f4a12a304420db5f685539a3cb3b0ce4..17a70bbe0df57fe4de30b99996ece7dbc5a00e20 100644 --- a/core/network/src/on_demand_layer.rs +++ b/core/network/src/on_demand_layer.rs @@ -19,6 +19,7 @@ use crate::protocol::on_demand::RequestData; use std::sync::Arc; use futures::{prelude::*, sync::mpsc, sync::oneshot}; +use futures03::compat::{Compat01As03, Future01CompatExt as _}; use parking_lot::Mutex; use client::error::Error as ClientError; use client::light::fetcher::{Fetcher, FetchChecker, RemoteHeaderRequest, @@ -82,22 +83,22 @@ impl Fetcher for OnDemand where B: BlockT, B::Header: HeaderT, { - type RemoteHeaderResult = RemoteResponse; - type RemoteReadResult = RemoteResponse>>; - type RemoteCallResult = RemoteResponse>; - type RemoteChangesResult = RemoteResponse, u32)>>; - type RemoteBodyResult = RemoteResponse>; + type RemoteHeaderResult = Compat01As03>; + type RemoteReadResult = Compat01As03>>>; + type RemoteCallResult = Compat01As03>>; + type RemoteChangesResult = Compat01As03, u32)>>>; + type RemoteBodyResult = Compat01As03>>; fn remote_header(&self, request: RemoteHeaderRequest) -> Self::RemoteHeaderResult { let (sender, receiver) = oneshot::channel(); let _ = self.requests_send.unbounded_send(RequestData::RemoteHeader(request, sender)); - RemoteResponse { receiver } + RemoteResponse { receiver }.compat() } fn remote_read(&self, request: RemoteReadRequest) -> Self::RemoteReadResult { let (sender, receiver) = oneshot::channel(); let _ = self.requests_send.unbounded_send(RequestData::RemoteRead(request, sender)); - RemoteResponse { receiver } + RemoteResponse { receiver }.compat() } fn remote_read_child( @@ -106,25 +107,25 @@ impl Fetcher for OnDemand where ) -> Self::RemoteReadResult { let (sender, receiver) = oneshot::channel(); let _ = self.requests_send.unbounded_send(RequestData::RemoteReadChild(request, sender)); - RemoteResponse { receiver } + RemoteResponse { receiver }.compat() } fn remote_call(&self, request: RemoteCallRequest) -> Self::RemoteCallResult { let (sender, receiver) = oneshot::channel(); let _ = self.requests_send.unbounded_send(RequestData::RemoteCall(request, sender)); - RemoteResponse { receiver } + RemoteResponse { receiver }.compat() } fn remote_changes(&self, request: RemoteChangesRequest) -> Self::RemoteChangesResult { let (sender, receiver) = oneshot::channel(); let _ = self.requests_send.unbounded_send(RequestData::RemoteChanges(request, sender)); - RemoteResponse { receiver } + RemoteResponse { receiver }.compat() } fn remote_body(&self, request: RemoteBodyRequest) -> Self::RemoteBodyResult { let (sender, receiver) = oneshot::channel(); let _ = self.requests_send.unbounded_send(RequestData::RemoteBody(request, sender)); - RemoteResponse { receiver } + RemoteResponse { receiver }.compat() } } diff --git a/core/network/src/protocol.rs b/core/network/src/protocol.rs index 13be819faea7262f07d66d296ab6d7b0d19c4caa..50b6ad274166d55dce1ab137f5e734bddf65c539 100644 --- a/core/network/src/protocol.rs +++ b/core/network/src/protocol.rs @@ -14,8 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . +use crate::{DiscoveryNetBehaviour, config::ProtocolId}; +use crate::custom_proto::{CustomProto, CustomProtoOut}; use futures::prelude::*; -use libp2p::PeerId; +use libp2p::{Multiaddr, PeerId}; +use libp2p::core::swarm::{ConnectedPoint, NetworkBehaviour, NetworkBehaviourAction, PollParameters}; +use libp2p::core::{nodes::Substream, muxing::StreamMuxerBox}; +use libp2p::core::protocols_handler::{ProtocolsHandler, IntoProtocolsHandler}; use primitives::storage::StorageKey; use consensus::{import_queue::IncomingBlock, import_queue::Origin, BlockOrigin}; use runtime_primitives::{generic::BlockId, ConsensusEngineId, Justification}; @@ -23,19 +28,16 @@ use runtime_primitives::traits::{ Block as BlockT, Header as HeaderT, NumberFor, One, Zero, CheckedSub, SaturatedConversion }; -use consensus::import_queue::SharedFinalityProofRequestBuilder; -use message::{ - BlockRequest as BlockRequestMessage, - FinalityProofRequest as FinalityProofRequestMessage, Message, -}; -use message::{BlockAttributes, Direction, FromBlock, RequestId}; +use consensus::import_queue::{BlockImportResult, BlockImportError}; +use message::{BlockAttributes, Direction, FromBlock, Message, RequestId}; use message::generic::{Message as GenericMessage, ConsensusMessage}; +use event::Event; use consensus_gossip::{ConsensusGossip, MessageRecipient as GossipMessageRecipient}; use on_demand::{OnDemandCore, OnDemandNetwork, RequestData}; use specialization::NetworkSpecialization; -use sync::{ChainSync, Context as SyncContext, Status as SyncStatus, SyncState}; +use sync::{ChainSync, SyncState}; use crate::service::{TransactionPool, ExHashT}; -use crate::config::Roles; +use crate::config::{BoxFinalityProofRequestBuilder, Roles}; use rustc_hex::ToHex; use std::collections::{BTreeMap, HashMap}; use std::sync::Arc; @@ -49,6 +51,7 @@ use util::LruHashSet; mod util; pub mod consensus_gossip; pub mod message; +pub mod event; pub mod on_demand; pub mod specialization; pub mod sync; @@ -101,12 +104,13 @@ pub struct Protocol, H: ExHashT> { context_data: ContextData, // Connected peers pending Status message. handshaking_peers: HashMap, -} - -/// A peer from whom we have received a Status message. -#[derive(Clone)] -pub struct ConnectedPeer { - pub peer_info: PeerInfo + /// Used to report reputation changes. + peerset_handle: peerset::PeersetHandle, + transaction_pool: Arc>, + /// When asked for a proof of finality, we use this struct to build one. + finality_proof_provider: Option>>, + /// Handles opening the unique substream and sending and receiving raw messages. + behaviour: CustomProto, Substream>, } /// A peer that we are connected to @@ -115,17 +119,6 @@ struct HandshakingPeer { timestamp: time::Instant, } -/// Syncing status and statistics -#[derive(Clone)] -pub struct ProtocolStatus { - /// Sync status. - pub sync: SyncStatus, - /// Total number of connected peers - pub num_peers: usize, - /// Total number of active peers. - pub num_active_peers: usize, -} - /// Peer information #[derive(Debug, Clone)] struct Peer { @@ -155,27 +148,18 @@ pub struct PeerInfo { pub best_number: ::Number, } -/// Context passed as input to the methods of `protocol.rs` and that is used to communicate back -/// with the network. -pub trait NetworkOut { - /// Adjusts the reputation of the peer. Use this to point out that a peer has been malign or - /// irresponsible or appeared lazy. - fn report_peer(&mut self, who: PeerId, reputation: i32); - - /// Force disconnecting from a peer. - fn disconnect_peer(&mut self, who: PeerId); - - /// Send a message to a peer. - fn send_message(&mut self, who: PeerId, message: Message); +struct OnDemandIn<'a, B: BlockT> { + behaviour: &'a mut CustomProto, Substream>, + peerset: peerset::PeersetHandle, } -impl<'a, 'b, B: BlockT> OnDemandNetwork for &'a mut &'b mut dyn NetworkOut { +impl<'a, B: BlockT> OnDemandNetwork for OnDemandIn<'a, B> { fn report_peer(&mut self, who: &PeerId, reputation: i32) { - NetworkOut::report_peer(**self, who.clone(), reputation) + self.peerset.report_peer(who.clone(), reputation) } fn disconnect_peer(&mut self, who: &PeerId) { - NetworkOut::disconnect_peer(**self, who.clone()) + self.behaviour.disconnect_peer(who) } fn send_header_request(&mut self, who: &PeerId, id: RequestId, block: <::Header as HeaderT>::Number) { @@ -184,7 +168,7 @@ impl<'a, 'b, B: BlockT> OnDemandNetwork for &'a mut &'b mut dyn NetworkOut block, }); - NetworkOut::send_message(**self, who.clone(), message) + self.behaviour.send_packet(who, message) } fn send_read_request(&mut self, who: &PeerId, id: RequestId, block: ::Hash, key: Vec) { @@ -194,7 +178,7 @@ impl<'a, 'b, B: BlockT> OnDemandNetwork for &'a mut &'b mut dyn NetworkOut key, }); - NetworkOut::send_message(**self, who.clone(), message) + self.behaviour.send_packet(who, message) } fn send_read_child_request( @@ -212,7 +196,7 @@ impl<'a, 'b, B: BlockT> OnDemandNetwork for &'a mut &'b mut dyn NetworkOut key, }); - NetworkOut::send_message(**self, who.clone(), message) + self.behaviour.send_packet(who, message) } fn send_call_request( @@ -230,7 +214,7 @@ impl<'a, 'b, B: BlockT> OnDemandNetwork for &'a mut &'b mut dyn NetworkOut data, }); - NetworkOut::send_message(**self, who.clone(), message) + self.behaviour.send_packet(who, message) } fn send_changes_request( @@ -252,7 +236,7 @@ impl<'a, 'b, B: BlockT> OnDemandNetwork for &'a mut &'b mut dyn NetworkOut key, }); - NetworkOut::send_message(**self, who.clone(), message) + self.behaviour.send_packet(who, message) } fn send_body_request( @@ -274,7 +258,7 @@ impl<'a, 'b, B: BlockT> OnDemandNetwork for &'a mut &'b mut dyn NetworkOut max, }); - NetworkOut::send_message(**self, who.clone(), message) + self.behaviour.send_packet(who, message) } } @@ -296,29 +280,34 @@ pub trait Context { /// Protocol context. struct ProtocolContext<'a, B: 'a + BlockT, H: 'a + ExHashT> { - network_out: &'a mut dyn NetworkOut, + behaviour: &'a mut CustomProto, Substream>, context_data: &'a mut ContextData, + peerset_handle: &'a peerset::PeersetHandle, } impl<'a, B: BlockT + 'a, H: 'a + ExHashT> ProtocolContext<'a, B, H> { - fn new(context_data: &'a mut ContextData, network_out: &'a mut dyn NetworkOut) -> Self { - ProtocolContext { network_out, context_data } + fn new( + context_data: &'a mut ContextData, + behaviour: &'a mut CustomProto, Substream>, + peerset_handle: &'a peerset::PeersetHandle, + ) -> Self { + ProtocolContext { context_data, peerset_handle, behaviour } } } impl<'a, B: BlockT + 'a, H: ExHashT + 'a> Context for ProtocolContext<'a, B, H> { fn report_peer(&mut self, who: PeerId, reputation: i32) { - self.network_out.report_peer(who, reputation) + self.peerset_handle.report_peer(who, reputation) } fn disconnect_peer(&mut self, who: PeerId) { - self.network_out.disconnect_peer(who) + self.behaviour.disconnect_peer(&who) } fn send_consensus(&mut self, who: PeerId, consensus: ConsensusMessage) { send_message( + self.behaviour, &mut self.context_data.peers, - self.network_out, who, GenericMessage::Consensus(consensus) ) @@ -326,46 +315,14 @@ impl<'a, B: BlockT + 'a, H: ExHashT + 'a> Context for ProtocolContext<'a, B, fn send_chain_specific(&mut self, who: PeerId, message: Vec) { send_message( + self.behaviour, &mut self.context_data.peers, - self.network_out, who, GenericMessage::ChainSpecific(message) ) } } -impl<'a, B: BlockT + 'a, H: ExHashT + 'a> SyncContext for ProtocolContext<'a, B, H> { - fn report_peer(&mut self, who: PeerId, reputation: i32) { - self.network_out.report_peer(who, reputation) - } - - fn disconnect_peer(&mut self, who: PeerId) { - self.network_out.disconnect_peer(who) - } - - fn client(&self) -> &dyn Client { - &*self.context_data.chain - } - - fn send_finality_proof_request(&mut self, who: PeerId, request: FinalityProofRequestMessage) { - send_message( - &mut self.context_data.peers, - self.network_out, - who, - GenericMessage::FinalityProofRequest(request) - ) - } - - fn send_block_request(&mut self, who: PeerId, request: BlockRequestMessage) { - send_message( - &mut self.context_data.peers, - self.network_out, - who, - GenericMessage::BlockRequest(request) - ) - } -} - /// Data necessary to create a context. struct ContextData { // All connected peers @@ -395,10 +352,19 @@ impl, H: ExHashT> Protocol { chain: Arc>, checker: Arc>, specialization: S, - ) -> error::Result> { + transaction_pool: Arc>, + finality_proof_provider: Option>>, + finality_proof_request_builder: Option>, + protocol_id: ProtocolId, + peerset_config: peerset::PeersetConfig, + ) -> error::Result<(Protocol, peerset::PeersetHandle)> { let info = chain.info(); - let sync = ChainSync::new(config.roles, &info); - Ok(Protocol { + let sync = ChainSync::new(config.roles, chain.clone(), &info, finality_proof_request_builder); + let (peerset, peerset_handle) = peerset::Peerset::from_config(peerset_config); + let versions = &((MIN_VERSION as u8)..=(CURRENT_VERSION as u8)).collect::>(); + let behaviour = CustomProto::new(protocol_id, versions, peerset); + + let protocol = Protocol { tick_timeout: tokio_timer::Interval::new_interval(TICK_TIMEOUT), propagate_timeout: tokio_timer::Interval::new_interval(PROPAGATE_TIMEOUT), config: config, @@ -412,52 +378,77 @@ impl, H: ExHashT> Protocol { specialization: specialization, consensus_gossip: ConsensusGossip::new(), handshaking_peers: HashMap::new(), - }) - } - - /// Returns an object representing the status of the protocol. - pub fn status(&self) -> ProtocolStatus { - ProtocolStatus { - sync: self.sync.status(), - num_peers: self.context_data.peers.values().count(), - num_active_peers: self - .context_data - .peers - .values() - .filter(|p| p.block_request.is_some()) - .count(), - } + transaction_pool, + finality_proof_provider, + peerset_handle: peerset_handle.clone(), + behaviour, + }; + + Ok((protocol, peerset_handle)) } - pub fn is_major_syncing(&self) -> bool { - self.sync.status().is_major_syncing() + /// Returns the list of all the peers we have an open channel to. + pub fn open_peers(&self) -> impl Iterator { + self.behaviour.open_peers() } - pub fn is_offline(&self) -> bool { - self.sync.status().is_offline() + /// Returns true if we have a channel open with this node. + pub fn is_open(&self, peer_id: &PeerId) -> bool { + self.behaviour.is_open(peer_id) } - /// Starts a new data demand request. - /// - /// The parameter contains a `Sender` where the result, once received, must be sent. - pub(crate) fn add_on_demand_request(&mut self, mut network_out: &mut dyn NetworkOut, rq: RequestData) { - self.on_demand_core.add_request(&mut network_out, rq); + /// Disconnects the given peer if we are connected to it. + pub fn disconnect_peer(&mut self, peer_id: &PeerId) { + self.behaviour.disconnect_peer(peer_id) } - pub fn poll( - &mut self, - network_out: &mut dyn NetworkOut, - transaction_pool: &(impl TransactionPool + ?Sized) - ) -> Poll { - while let Ok(Async::Ready(_)) = self.tick_timeout.poll() { - self.tick(network_out); - } + /// Returns true if we try to open protocols with the given peer. + pub fn is_enabled(&self, peer_id: &PeerId) -> bool { + self.behaviour.is_enabled(peer_id) + } - while let Ok(Async::Ready(_)) = self.propagate_timeout.poll() { - self.propagate_extrinsics(network_out, transaction_pool); - } + /// Returns the state of the peerset manager, for debugging purposes. + pub fn peerset_debug_info(&mut self) -> serde_json::Value { + self.behaviour.peerset_debug_info() + } + + /// Returns the number of peers we're connected to. + pub fn num_connected_peers(&self) -> usize { + self.context_data.peers.values().count() + } + + /// Returns the number of peers we're connected to and that are being queried. + pub fn num_active_peers(&self) -> usize { + self.context_data + .peers + .values() + .filter(|p| p.block_request.is_some()) + .count() + } + + /// Current global sync state. + pub fn sync_state(&self) -> SyncState { + self.sync.status().state + } + + /// Target sync block number. + pub fn best_seen_block(&self) -> Option> { + self.sync.status().best_seen_block + } + + /// Number of peers participating in syncing. + pub fn num_sync_peers(&self) -> u32 { + self.sync.status().num_peers + } - Ok(Async::NotReady) + /// Starts a new data demand request. + /// + /// The parameter contains a `Sender` where the result, once received, must be sent. + pub(crate) fn add_on_demand_request(&mut self, rq: RequestData) { + self.on_demand_core.add_request(OnDemandIn { + behaviour: &mut self.behaviour, + peerset: self.peerset_handle.clone(), + }, rq); } fn is_on_demand_response(&self, who: &PeerId, response_id: message::RequestId) -> bool { @@ -466,7 +457,6 @@ impl, H: ExHashT> Protocol { fn handle_response( &mut self, - network_out: &mut dyn NetworkOut, who: PeerId, response: &message::BlockResponse ) -> Option> { @@ -481,8 +471,8 @@ impl, H: ExHashT> Protocol { return request.map(|(_, r)| r) } trace!(target: "sync", "Unexpected response packet from {} ({})", who, response.id); - network_out.report_peer(who.clone(), i32::min_value()); - network_out.disconnect_peer(who); + self.peerset_handle.report_peer(who.clone(), i32::min_value()); + self.behaviour.disconnect_peer(&who); } None } @@ -501,78 +491,80 @@ impl, H: ExHashT> Protocol { self.context_data.peers.iter().map(|(id, peer)| (id, &peer.info)) } + pub fn on_event(&mut self, event: Event) { + self.specialization.on_event(event); + } + pub fn on_custom_message( &mut self, - network_out: &mut dyn NetworkOut, - transaction_pool: &(impl TransactionPool + ?Sized), who: PeerId, message: Message, - finality_proof_provider: Option<&dyn FinalityProofProvider> ) -> CustomMessageOutcome { match message { - GenericMessage::Status(s) => self.on_status_message(network_out, who, s), - GenericMessage::BlockRequest(r) => self.on_block_request(network_out, who, r), + GenericMessage::Status(s) => self.on_status_message(who, s), + GenericMessage::BlockRequest(r) => self.on_block_request(who, r), GenericMessage::BlockResponse(r) => { // Note, this is safe because only `ordinary bodies` and `remote bodies` are received in this matter. if self.is_on_demand_response(&who, r.id) { - self.on_remote_body_response(network_out, who, r); + self.on_remote_body_response(who, r); } else { - if let Some(request) = self.handle_response(network_out, who.clone(), &r) { - let outcome = self.on_block_response(network_out, who.clone(), request, r); + if let Some(request) = self.handle_response(who.clone(), &r) { + let outcome = self.on_block_response(who.clone(), request, r); self.update_peer_info(&who); return outcome } } }, GenericMessage::BlockAnnounce(announce) => { - let outcome = self.on_block_announce(network_out, who.clone(), announce); + let outcome = self.on_block_announce(who.clone(), announce); self.update_peer_info(&who); return outcome; }, GenericMessage::Transactions(m) => - self.on_extrinsics(network_out, transaction_pool, who, m), - GenericMessage::RemoteCallRequest(request) => self.on_remote_call_request(network_out, who, request), + self.on_extrinsics(who, m), + GenericMessage::RemoteCallRequest(request) => self.on_remote_call_request(who, request), GenericMessage::RemoteCallResponse(response) => - self.on_remote_call_response(network_out, who, response), + self.on_remote_call_response(who, response), GenericMessage::RemoteReadRequest(request) => - self.on_remote_read_request(network_out, who, request), + self.on_remote_read_request(who, request), GenericMessage::RemoteReadResponse(response) => - self.on_remote_read_response(network_out, who, response), + self.on_remote_read_response(who, response), GenericMessage::RemoteHeaderRequest(request) => - self.on_remote_header_request(network_out, who, request), + self.on_remote_header_request(who, request), GenericMessage::RemoteHeaderResponse(response) => - self.on_remote_header_response(network_out, who, response), + self.on_remote_header_response(who, response), GenericMessage::RemoteChangesRequest(request) => - self.on_remote_changes_request(network_out, who, request), + self.on_remote_changes_request(who, request), GenericMessage::RemoteChangesResponse(response) => - self.on_remote_changes_response(network_out, who, response), + self.on_remote_changes_response(who, response), GenericMessage::FinalityProofRequest(request) => - self.on_finality_proof_request(network_out, who, request, finality_proof_provider), + self.on_finality_proof_request(who, request), GenericMessage::FinalityProofResponse(response) => - return self.on_finality_proof_response(network_out, who, response), + return self.on_finality_proof_response(who, response), + GenericMessage::RemoteReadChildRequest(_) => {} GenericMessage::Consensus(msg) => { if self.context_data.peers.get(&who).map_or(false, |peer| peer.info.protocol_version > 2) { self.consensus_gossip.on_incoming( - &mut ProtocolContext::new(&mut self.context_data, network_out), + &mut ProtocolContext::new(&mut self.context_data, &mut self.behaviour, &self.peerset_handle), who, msg, ); } } - other => self.specialization.on_message( - &mut ProtocolContext::new(&mut self.context_data, network_out), + GenericMessage::ChainSpecific(msg) => self.specialization.on_message( + &mut ProtocolContext::new(&mut self.context_data, &mut self.behaviour, &self.peerset_handle), who, - &mut Some(other), + msg, ), } CustomMessageOutcome::None } - fn send_message(&mut self, network_out: &mut dyn NetworkOut, who: PeerId, message: Message) { + fn send_message(&mut self, who: PeerId, message: Message) { send_message::( + &mut self.behaviour, &mut self.context_data.peers, - network_out, who, message, ); @@ -581,31 +573,28 @@ impl, H: ExHashT> Protocol { /// Locks `self` and returns a context plus the `ConsensusGossip` struct. pub fn consensus_gossip_lock<'a>( &'a mut self, - network_out: &'a mut dyn NetworkOut ) -> (impl Context + 'a, &'a mut ConsensusGossip) { - let context = ProtocolContext::new(&mut self.context_data, network_out); + let context = ProtocolContext::new(&mut self.context_data, &mut self.behaviour, &self.peerset_handle); (context, &mut self.consensus_gossip) } /// Locks `self` and returns a context plus the network specialization. pub fn specialization_lock<'a>( &'a mut self, - network_out: &'a mut dyn NetworkOut ) -> (impl Context + 'a, &'a mut S) { - let context = ProtocolContext::new(&mut self.context_data, network_out); + let context = ProtocolContext::new(&mut self.context_data, &mut self.behaviour, &self.peerset_handle); (context, &mut self.specialization) } /// Gossip a consensus message to the network. pub fn gossip_consensus_message( &mut self, - network_out: &mut dyn NetworkOut, topic: B::Hash, engine_id: ConsensusEngineId, message: Vec, recipient: GossipMessageRecipient, ) { - let mut context = ProtocolContext::new(&mut self.context_data, network_out); + let mut context = ProtocolContext::new(&mut self.context_data, &mut self.behaviour, &self.peerset_handle); let message = ConsensusMessage { data: message, engine_id }; match recipient { GossipMessageRecipient::BroadcastToAll => @@ -613,19 +602,19 @@ impl, H: ExHashT> Protocol { GossipMessageRecipient::BroadcastNew => self.consensus_gossip.multicast(&mut context, topic, message, false), GossipMessageRecipient::Peer(who) => - self.send_message(network_out, who, GenericMessage::Consensus(message)), + self.send_message(who, GenericMessage::Consensus(message)), } } /// Called when a new peer is connected - pub fn on_peer_connected(&mut self, network_out: &mut dyn NetworkOut, who: PeerId) { + pub fn on_peer_connected(&mut self, who: PeerId) { trace!(target: "sync", "Connecting {}", who); self.handshaking_peers.insert(who.clone(), HandshakingPeer { timestamp: time::Instant::now() }); - self.send_status(network_out, who); + self.send_status(who); } /// Called by peer when it is disconnecting - pub fn on_peer_disconnected(&mut self, mut network_out: &mut dyn NetworkOut, peer: PeerId) { + pub fn on_peer_disconnected(&mut self, peer: PeerId) { trace!(target: "sync", "Disconnecting {}", peer); // lock all the the peer lists so that add/remove peer events are in order let removed = { @@ -633,20 +622,23 @@ impl, H: ExHashT> Protocol { self.context_data.peers.remove(&peer) }; if let Some(peer_data) = removed { - let mut context = ProtocolContext::new(&mut self.context_data, network_out); + let mut context = ProtocolContext::new(&mut self.context_data, &mut self.behaviour, &self.peerset_handle); if peer_data.info.protocol_version > 2 { self.consensus_gossip.peer_disconnected(&mut context, peer.clone()); } - self.sync.peer_disconnected(&mut context, peer.clone()); + self.sync.peer_disconnected(peer.clone()); self.specialization.on_disconnect(&mut context, peer.clone()); - self.on_demand_core.on_disconnect(&mut network_out, peer); + self.on_demand_core.on_disconnect(OnDemandIn { + behaviour: &mut self.behaviour, + peerset: self.peerset_handle.clone(), + }, peer); } } /// Called as a back-pressure mechanism if the networking detects that the peer cannot process /// our messaging rate fast enough. - pub fn on_clogged_peer(&self, network_out: &mut dyn NetworkOut, who: PeerId, _msg: Option>) { - network_out.report_peer(who.clone(), CLOGGED_PEER_REPUTATION_CHANGE); + pub fn on_clogged_peer(&self, who: PeerId, _msg: Option>) { + self.peerset_handle.report_peer(who.clone(), CLOGGED_PEER_REPUTATION_CHANGE); // Print some diagnostics. if let Some(peer) = self.context_data.peers.get(&who) { @@ -661,7 +653,6 @@ impl, H: ExHashT> Protocol { fn on_block_request( &mut self, - network_out: &mut dyn NetworkOut, peer: PeerId, request: message::BlockRequest ) { @@ -675,8 +666,8 @@ impl, H: ExHashT> Protocol { // sending block requests to the node that is unable to serve it is considered a bad behavior if !self.config.roles.is_full() { trace!(target: "sync", "Peer {} is trying to sync from the light node", peer); - network_out.disconnect_peer(peer.clone()); - network_out.report_peer(peer, i32::min_value()); + self.behaviour.disconnect_peer(&peer); + self.peerset_handle.report_peer(peer, i32::min_value()); return; } @@ -734,12 +725,16 @@ impl, H: ExHashT> Protocol { blocks: blocks, }; trace!(target: "sync", "Sending BlockResponse with {} blocks", response.blocks.len()); - self.send_message(network_out, peer, GenericMessage::BlockResponse(response)) + self.send_message(peer, GenericMessage::BlockResponse(response)) + } + + /// Adjusts the reputation of a node. + pub fn report_peer(&self, who: PeerId, reputation: i32) { + self.peerset_handle.report_peer(who, reputation) } fn on_block_response( &mut self, - network_out: &mut dyn NetworkOut, peer: PeerId, request: message::BlockRequest, response: message::BlockResponse, @@ -762,29 +757,29 @@ impl, H: ExHashT> Protocol { // TODO [andre]: move this logic to the import queue so that // justifications are imported asynchronously (#1482) if request.fields == message::BlockAttributes::JUSTIFICATION { - let outcome = self.sync.on_block_justification_data( - &mut ProtocolContext::new(&mut self.context_data, network_out), - peer, - response - ); - - if let Some((origin, hash, nb, just)) = outcome { - CustomMessageOutcome::JustificationImport(origin, hash, nb, just) - } else { - CustomMessageOutcome::None + match self.sync.on_block_justification(peer, response) { + Ok(sync::OnBlockJustification::Nothing) => CustomMessageOutcome::None, + Ok(sync::OnBlockJustification::Import { peer, hash, number, justification }) => + CustomMessageOutcome::JustificationImport(peer, hash, number, justification), + Err(sync::BadPeer(id, repu)) => { + self.behaviour.disconnect_peer(&id); + self.peerset_handle.report_peer(id, repu); + CustomMessageOutcome::None + } } - } else { - let outcome = self.sync.on_block_data( - &mut ProtocolContext::new(&mut self.context_data, network_out), - peer, - request, - response - ); - if let Some((origin, blocks)) = outcome { - CustomMessageOutcome::BlockImport(origin, blocks) - } else { - CustomMessageOutcome::None + match self.sync.on_block_data(peer, request, response) { + Ok(sync::OnBlockData::Import(origin, blocks)) => + CustomMessageOutcome::BlockImport(origin, blocks), + Ok(sync::OnBlockData::Request(peer, req)) => { + self.send_message(peer, GenericMessage::BlockRequest(req)); + CustomMessageOutcome::None + } + Err(sync::BadPeer(id, repu)) => { + self.behaviour.disconnect_peer(&id); + self.peerset_handle.report_peer(id, repu); + CustomMessageOutcome::None + } } } } @@ -792,14 +787,18 @@ impl, H: ExHashT> Protocol { /// Perform time based maintenance. /// /// > **Note**: This method normally doesn't have to be called except for testing purposes. - pub fn tick(&mut self, mut network_out: &mut dyn NetworkOut) { - self.consensus_gossip.tick(&mut ProtocolContext::new(&mut self.context_data, network_out)); - self.maintain_peers(network_out); - self.sync.tick(&mut ProtocolContext::new(&mut self.context_data, network_out)); - self.on_demand_core.maintain_peers(&mut network_out); + pub fn tick(&mut self) { + self.consensus_gossip.tick( + &mut ProtocolContext::new(&mut self.context_data, &mut self.behaviour, &self.peerset_handle) + ); + self.maintain_peers(); + self.on_demand_core.maintain_peers(OnDemandIn { + behaviour: &mut self.behaviour, + peerset: self.peerset_handle.clone(), + }); } - fn maintain_peers(&mut self, network_out: &mut dyn NetworkOut) { + fn maintain_peers(&mut self) { let tick = time::Instant::now(); let mut aborting = Vec::new(); { @@ -820,20 +819,22 @@ impl, H: ExHashT> Protocol { } } - self.specialization.maintain_peers(&mut ProtocolContext::new(&mut self.context_data, network_out)); + self.specialization.maintain_peers( + &mut ProtocolContext::new(&mut self.context_data, &mut self.behaviour, &self.peerset_handle) + ); for p in aborting { - network_out.disconnect_peer(p.clone()); - network_out.report_peer(p, TIMEOUT_REPUTATION_CHANGE); + self.behaviour.disconnect_peer(&p); + self.peerset_handle.report_peer(p, TIMEOUT_REPUTATION_CHANGE); } } /// Called by peer to report status - fn on_status_message(&mut self, mut network_out: &mut dyn NetworkOut, who: PeerId, status: message::Status) { + fn on_status_message(&mut self, who: PeerId, status: message::Status) { trace!(target: "sync", "New peer {} {:?}", who, status); let protocol_version = { if self.context_data.peers.contains_key(&who) { debug!("Unexpected status packet from {}", who); - network_out.report_peer(who, UNEXPECTED_STATUS_REPUTATION_CHANGE); + self.peerset_handle.report_peer(who, UNEXPECTED_STATUS_REPUTATION_CHANGE); return; } if status.genesis_hash != self.genesis_hash { @@ -842,14 +843,14 @@ impl, H: ExHashT> Protocol { "Peer is on different chain (our genesis: {} theirs: {})", self.genesis_hash, status.genesis_hash ); - network_out.report_peer(who.clone(), i32::min_value()); - network_out.disconnect_peer(who); + self.peerset_handle.report_peer(who.clone(), i32::min_value()); + self.behaviour.disconnect_peer(&who); return; } if status.version < MIN_VERSION && CURRENT_VERSION < status.min_supported_version { trace!(target: "protocol", "Peer {:?} using unsupported protocol version {}", who, status.version); - network_out.report_peer(who.clone(), i32::min_value()); - network_out.disconnect_peer(who); + self.peerset_handle.report_peer(who.clone(), i32::min_value()); + self.behaviour.disconnect_peer(&who); return; } @@ -857,8 +858,8 @@ impl, H: ExHashT> Protocol { // we're not interested in light peers if status.roles.is_light() { debug!(target: "sync", "Peer {} is unable to serve light requests", who); - network_out.report_peer(who.clone(), i32::min_value()); - network_out.disconnect_peer(who); + self.peerset_handle.report_peer(who.clone(), i32::min_value()); + self.behaviour.disconnect_peer(&who); return; } @@ -874,8 +875,8 @@ impl, H: ExHashT> Protocol { .saturated_into::(); if blocks_difference > LIGHT_MAXIMAL_BLOCKS_DIFFERENCE { debug!(target: "sync", "Peer {} is far behind us and will unable to serve light requests", who); - network_out.report_peer(who.clone(), PEER_BEHIND_US_LIGHT_REPUTATION_CHANGE); - network_out.disconnect_peer(who); + self.peerset_handle.report_peer(who.clone(), PEER_BEHIND_US_LIGHT_REPUTATION_CHANGE); + self.behaviour.disconnect_peer(&who); return; } } @@ -912,9 +913,19 @@ impl, H: ExHashT> Protocol { }; let info = self.context_data.peers.get(&who).expect("We just inserted above; QED").info.clone(); - self.on_demand_core.on_connect(&mut network_out, who.clone(), status.roles, status.best_number); - let mut context = ProtocolContext::new(&mut self.context_data, network_out); - self.sync.new_peer(&mut context, who.clone(), info); + self.on_demand_core.on_connect(OnDemandIn { + behaviour: &mut self.behaviour, + peerset: self.peerset_handle.clone(), + }, who.clone(), status.roles, status.best_number); + match self.sync.new_peer(who.clone(), info) { + Ok(None) => (), + Ok(Some(req)) => self.send_message(who.clone(), GenericMessage::BlockRequest(req)), + Err(sync::BadPeer(id, repu)) => { + self.behaviour.disconnect_peer(&id); + self.peerset_handle.report_peer(id, repu) + } + } + let mut context = ProtocolContext::new(&mut self.context_data, &mut self.behaviour, &self.peerset_handle); if protocol_version > 2 { self.consensus_gossip.new_peer(&mut context, who.clone(), status.roles); } @@ -924,8 +935,6 @@ impl, H: ExHashT> Protocol { /// Called when peer sends us new extrinsics fn on_extrinsics( &mut self, - network_out: &mut dyn NetworkOut, - transaction_pool: &(impl TransactionPool + ?Sized), who: PeerId, extrinsics: message::Transactions ) { @@ -937,8 +946,8 @@ impl, H: ExHashT> Protocol { trace!(target: "sync", "Received {} extrinsics from {}", extrinsics.len(), who); if let Some(ref mut peer) = self.context_data.peers.get_mut(&who) { for t in extrinsics { - if let Some(hash) = transaction_pool.import(&t) { - network_out.report_peer(who.clone(), NEW_EXTRINSIC_REPUTATION_CHANGE); + if let Some(hash) = self.transaction_pool.import(&t) { + self.peerset_handle.report_peer(who.clone(), NEW_EXTRINSIC_REPUTATION_CHANGE); peer.known_extrinsics.insert(hash); } else { trace!(target: "sync", "Extrinsic rejected"); @@ -950,8 +959,6 @@ impl, H: ExHashT> Protocol { /// Call when we must propagate ready extrinsics to peers. pub fn propagate_extrinsics( &mut self, - network_out: &mut dyn NetworkOut, - transaction_pool: &(impl TransactionPool + ?Sized) ) { debug!(target: "sync", "Propagating extrinsics"); @@ -960,7 +967,7 @@ impl, H: ExHashT> Protocol { return; } - let extrinsics = transaction_pool.transactions(); + let extrinsics = self.transaction_pool.transactions(); let mut propagated_to = HashMap::new(); for (who, peer) in self.context_data.peers.iter_mut() { let (hashes, to_send): (Vec<_>, Vec<_>) = extrinsics @@ -977,18 +984,18 @@ impl, H: ExHashT> Protocol { .push(who.to_base58()); } trace!(target: "sync", "Sending {} transactions to {}", to_send.len(), who); - network_out.send_message(who.clone(), GenericMessage::Transactions(to_send)) + self.behaviour.send_packet(who, GenericMessage::Transactions(to_send)) } } - transaction_pool.on_broadcasted(propagated_to); + self.transaction_pool.on_broadcasted(propagated_to); } /// Make sure an important block is propagated to peers. /// /// In chain-based consensus, we often need to make sure non-best forks are /// at least temporarily synced. - pub fn announce_block(&mut self, network_out: &mut dyn NetworkOut, hash: B::Hash) { + pub fn announce_block(&mut self, hash: B::Hash) { let header = match self.context_data.chain.header(&BlockId::Hash(hash)) { Ok(Some(header)) => header, Ok(None) => { @@ -1000,6 +1007,12 @@ impl, H: ExHashT> Protocol { return; } }; + + // don't announce genesis block since it will be ignored + if header.number().is_zero() { + return; + } + let hash = header.hash(); let message = GenericMessage::BlockAnnounce(message::BlockAnnounce { header: header.clone() }); @@ -1007,12 +1020,12 @@ impl, H: ExHashT> Protocol { for (who, ref mut peer) in self.context_data.peers.iter_mut() { trace!(target: "sync", "Reannouncing block {:?} to {}", hash, who); peer.known_blocks.insert(hash); - network_out.send_message(who.clone(), message.clone()) + self.behaviour.send_packet(who, message.clone()) } } /// Send Status message - fn send_status(&mut self, network_out: &mut dyn NetworkOut, who: PeerId) { + fn send_status(&mut self, who: PeerId) { let info = self.context_data.chain.info(); let status = message::generic::Status { version: CURRENT_VERSION, @@ -1024,12 +1037,11 @@ impl, H: ExHashT> Protocol { chain_status: self.specialization.status(), }; - self.send_message(network_out, who, GenericMessage::Status(status)) + self.send_message(who, GenericMessage::Status(status)) } fn on_block_announce( &mut self, - mut network_out: &mut dyn NetworkOut, who: PeerId, announce: message::BlockAnnounce ) -> CustomMessageOutcome { @@ -1040,29 +1052,32 @@ impl, H: ExHashT> Protocol { peer.known_blocks.insert(hash.clone()); } } - self.on_demand_core.on_block_announce(&mut network_out, who.clone(), *header.number()); - let try_import = self.sync.on_block_announce( - &mut ProtocolContext::new(&mut self.context_data, network_out), - who.clone(), - hash, - &header, - ); - - // try_import is only true when we have all data required to import block - // in the BlockAnnounce message. This is only when: - // 1) we're on light client; - // AND - // - EITHER 2.1) announced block is stale; - // - OR 2.2) announced block is NEW and we normally only want to download this single block (i.e. - // there are no ascendants of this block scheduled for retrieval) - if !try_import { - return CustomMessageOutcome::None; + self.on_demand_core.on_block_announce(OnDemandIn { + behaviour: &mut self.behaviour, + peerset: self.peerset_handle.clone(), + }, who.clone(), *header.number()); + + match self.sync.on_block_announce(who.clone(), hash, &header) { + sync::OnBlockAnnounce::Request(peer, req) => { + self.send_message(peer, GenericMessage::BlockRequest(req)); + return CustomMessageOutcome::None + } + sync::OnBlockAnnounce::Nothing => { + // try_import is only true when we have all data required to import block + // in the BlockAnnounce message. This is only when: + // 1) we're on light client; + // AND + // - EITHER 2.1) announced block is stale; + // - OR 2.2) announced block is NEW and we normally only want to download this single block (i.e. + // there are no ascendants of this block scheduled for retrieval) + return CustomMessageOutcome::None + } + sync::OnBlockAnnounce::ImportHeader => () // We proceed with the import. } // to import header from announced block let's construct response to request that normally would have // been sent over network (but it is not in our case) let blocks_to_import = self.sync.on_block_data( - &mut ProtocolContext::new(&mut self.context_data, network_out), who.clone(), message::generic::BlockRequest { id: 0, @@ -1087,17 +1102,25 @@ impl, H: ExHashT> Protocol { }, ); match blocks_to_import { - Some((origin, blocks)) => CustomMessageOutcome::BlockImport(origin, blocks), - None => CustomMessageOutcome::None, + Ok(sync::OnBlockData::Import(origin, blocks)) => CustomMessageOutcome::BlockImport(origin, blocks), + Ok(sync::OnBlockData::Request(peer, req)) => { + self.send_message(peer, GenericMessage::BlockRequest(req)); + CustomMessageOutcome::None + } + Err(sync::BadPeer(id, repu)) => { + self.behaviour.disconnect_peer(&id); + self.peerset_handle.report_peer(id, repu); + CustomMessageOutcome::None + } } } /// Call this when a block has been imported in the import queue and we should announce it on /// the network. - pub fn on_block_imported(&mut self, network_out: &mut dyn NetworkOut, hash: B::Hash, header: &B::Header) { + pub fn on_block_imported(&mut self, hash: B::Hash, header: &B::Header) { self.sync.update_chain_info(header); self.specialization.on_block_imported( - &mut ProtocolContext::new(&mut self.context_data, network_out), + &mut ProtocolContext::new(&mut self.context_data, &mut self.behaviour, &self.peerset_handle), hash.clone(), header, ); @@ -1114,24 +1137,19 @@ impl, H: ExHashT> Protocol { for (who, ref mut peer) in self.context_data.peers.iter_mut() { if peer.known_blocks.insert(hash.clone()) { trace!(target: "sync", "Announcing block {:?} to {}", hash, who); - network_out.send_message(who.clone(), message.clone()) + self.behaviour.send_packet(who, message.clone()) } } } /// Call this when a block has been finalized. The sync layer may have some additional /// requesting to perform. - pub fn on_block_finalized(&mut self, network_out: &mut dyn NetworkOut, hash: B::Hash, header: &B::Header) { - self.sync.on_block_finalized( - &hash, - *header.number(), - &mut ProtocolContext::new(&mut self.context_data, network_out), - ); + pub fn on_block_finalized(&mut self, hash: B::Hash, header: &B::Header) { + self.sync.on_block_finalized(&hash, *header.number()) } fn on_remote_call_request( &mut self, - network_out: &mut dyn NetworkOut, who: PeerId, request: message::RemoteCallRequest, ) { @@ -1155,13 +1173,12 @@ impl, H: ExHashT> Protocol { request.block, error ); - network_out.report_peer(who.clone(), RPC_FAILED_REPUTATION_CHANGE); + self.peerset_handle.report_peer(who.clone(), RPC_FAILED_REPUTATION_CHANGE); Default::default() } }; self.send_message( - network_out, who, GenericMessage::RemoteCallResponse(message::RemoteCallResponse { id: request.id, @@ -1174,63 +1191,51 @@ impl, H: ExHashT> Protocol { /// /// Uses `protocol` to queue a new justification request and tries to dispatch all pending /// requests. - pub fn request_justification(&mut self, network_out: &mut dyn NetworkOut, hash: &B::Hash, number: NumberFor) { - let mut context = - ProtocolContext::new(&mut self.context_data, network_out); - self.sync.request_justification(&hash, number, &mut context); - } - - /// Clears all pending justification requests. - pub fn clear_justification_requests(&mut self) { - self.sync.clear_justification_requests() + pub fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { + self.sync.request_justification(&hash, number) } /// A batch of blocks have been processed, with or without errors. - /// Call this when a batch of blocks have been processed by the import queue, with or without + /// Call this when a batch of blocks have been processed by the importqueue, with or without /// errors. pub fn blocks_processed( &mut self, - network_out: &mut dyn NetworkOut, - processed_blocks: Vec, - has_error: bool + imported: usize, + count: usize, + results: Vec<(Result>, BlockImportError>, B::Hash)> ) { - let mut context = ProtocolContext::new(&mut self.context_data, network_out); - self.sync.blocks_processed(&mut context, processed_blocks, has_error); - } - - /// Restart the sync process. - pub fn restart(&mut self, network_out: &mut dyn NetworkOut) { let peers = self.context_data.peers.clone(); - let mut context = ProtocolContext::new(&mut self.context_data, network_out); - self.sync.restart(&mut context, |peer_id| peers.get(peer_id).map(|i| i.info.clone())); - } - - /// Notify about successful import of the given block. - pub fn block_imported(&mut self, hash: &B::Hash, number: NumberFor) { - self.sync.block_imported(hash, number) - } - - pub fn set_finality_proof_request_builder(&mut self, request_builder: SharedFinalityProofRequestBuilder) { - self.sync.set_finality_proof_request_builder(request_builder) + let results = self.sync.on_blocks_processed( + imported, + count, + results, + |peer_id| peers.get(peer_id).map(|i| i.info.clone()) + ); + for result in results { + match result { + Ok((id, req)) => { + let msg = GenericMessage::BlockRequest(req); + send_message(&mut self.behaviour, &mut self.context_data.peers, id, msg) + } + Err(sync::BadPeer(id, repu)) => { + self.behaviour.disconnect_peer(&id); + self.peerset_handle.report_peer(id, repu) + } + } + } } /// Call this when a justification has been processed by the import queue, with or without /// errors. pub fn justification_import_result(&mut self, hash: B::Hash, number: NumberFor, success: bool) { - self.sync.justification_import_result(hash, number, success) + self.sync.on_justification_import(hash, number, success) } /// Request a finality proof for the given block. /// /// Queues a new finality proof request and tries to dispatch all pending requests. - pub fn request_finality_proof( - &mut self, - network_out: &mut dyn NetworkOut, - hash: &B::Hash, - number: NumberFor - ) { - let mut context = ProtocolContext::new(&mut self.context_data, network_out); - self.sync.request_finality_proof(&hash, number, &mut context); + pub fn request_finality_proof(&mut self, hash: &B::Hash, number: NumberFor) { + self.sync.request_finality_proof(&hash, number) } pub fn finality_proof_import_result( @@ -1238,22 +1243,23 @@ impl, H: ExHashT> Protocol { request_block: (B::Hash, NumberFor), finalization_result: Result<(B::Hash, NumberFor), ()>, ) { - self.sync.finality_proof_import_result(request_block, finalization_result) + self.sync.on_finality_proof_import(request_block, finalization_result) } fn on_remote_call_response( &mut self, - mut network_out: &mut dyn NetworkOut, who: PeerId, response: message::RemoteCallResponse ) { trace!(target: "sync", "Remote call response {} from {}", response.id, who); - self.on_demand_core.on_remote_call_response(&mut network_out, who, response); + self.on_demand_core.on_remote_call_response(OnDemandIn { + behaviour: &mut self.behaviour, + peerset: self.peerset_handle.clone(), + }, who, response); } fn on_remote_read_request( &mut self, - network_out: &mut dyn NetworkOut, who: PeerId, request: message::RemoteReadRequest, ) { @@ -1273,7 +1279,6 @@ impl, H: ExHashT> Protocol { } }; self.send_message( - network_out, who, GenericMessage::RemoteReadResponse(message::RemoteReadResponse { id: request.id, @@ -1284,17 +1289,18 @@ impl, H: ExHashT> Protocol { fn on_remote_read_response( &mut self, - mut network_out: &mut dyn NetworkOut, who: PeerId, response: message::RemoteReadResponse ) { trace!(target: "sync", "Remote read response {} from {}", response.id, who); - self.on_demand_core.on_remote_read_response(&mut network_out, who, response); + self.on_demand_core.on_remote_read_response(OnDemandIn { + behaviour: &mut self.behaviour, + peerset: self.peerset_handle.clone(), + }, who, response); } fn on_remote_header_request( &mut self, - network_out: &mut dyn NetworkOut, who: PeerId, request: message::RemoteHeaderRequest>, ) { @@ -1313,7 +1319,6 @@ impl, H: ExHashT> Protocol { } }; self.send_message( - network_out, who, GenericMessage::RemoteHeaderResponse(message::RemoteHeaderResponse { id: request.id, @@ -1325,17 +1330,18 @@ impl, H: ExHashT> Protocol { fn on_remote_header_response( &mut self, - mut network_out: &mut dyn NetworkOut, who: PeerId, response: message::RemoteHeaderResponse, ) { trace!(target: "sync", "Remote header proof response {} from {}", response.id, who); - self.on_demand_core.on_remote_header_response(&mut network_out, who, response); + self.on_demand_core.on_remote_header_response(OnDemandIn { + behaviour: &mut self.behaviour, + peerset: self.peerset_handle.clone(), + }, who, response); } fn on_remote_changes_request( &mut self, - network_out: &mut dyn NetworkOut, who: PeerId, request: message::RemoteChangesRequest, ) { @@ -1373,7 +1379,6 @@ impl, H: ExHashT> Protocol { } }; self.send_message( - network_out, who, GenericMessage::RemoteChangesResponse(message::RemoteChangesResponse { id: request.id, @@ -1387,7 +1392,6 @@ impl, H: ExHashT> Protocol { fn on_remote_changes_response( &mut self, - mut network_out: &mut dyn NetworkOut, who: PeerId, response: message::RemoteChangesResponse, B::Hash>, ) { @@ -1396,18 +1400,19 @@ impl, H: ExHashT> Protocol { who, response.max ); - self.on_demand_core.on_remote_changes_response(&mut network_out, who, response); + self.on_demand_core.on_remote_changes_response(OnDemandIn { + behaviour: &mut self.behaviour, + peerset: self.peerset_handle.clone(), + }, who, response); } fn on_finality_proof_request( &mut self, - network_out: &mut dyn NetworkOut, who: PeerId, request: message::FinalityProofRequest, - finality_proof_provider: Option<&dyn FinalityProofProvider> ) { trace!(target: "sync", "Finality proof request from {} for {}", who, request.block); - let finality_proof = finality_proof_provider.as_ref() + let finality_proof = self.finality_proof_provider.as_ref() .ok_or_else(|| String::from("Finality provider is not configured")) .and_then(|provider| provider.prove_finality(request.block, &request.request).map_err(|e| e.to_string()) @@ -1424,7 +1429,6 @@ impl, H: ExHashT> Protocol { }, }; self.send_message( - network_out, who, GenericMessage::FinalityProofResponse(message::FinalityProofResponse { id: 0, @@ -1436,31 +1440,31 @@ impl, H: ExHashT> Protocol { fn on_finality_proof_response( &mut self, - network_out: &mut dyn NetworkOut, who: PeerId, response: message::FinalityProofResponse, ) -> CustomMessageOutcome { trace!(target: "sync", "Finality proof response from {} for {}", who, response.block); - let outcome = self.sync.on_block_finality_proof_data( - &mut ProtocolContext::new(&mut self.context_data, network_out), - who, - response, - ); - - if let Some((origin, hash, nb, proof)) = outcome { - CustomMessageOutcome::FinalityProofImport(origin, hash, nb, proof) - } else { - CustomMessageOutcome::None + match self.sync.on_block_finality_proof(who, response) { + Ok(sync::OnBlockFinalityProof::Nothing) => CustomMessageOutcome::None, + Ok(sync::OnBlockFinalityProof::Import { peer, hash, number, proof }) => + CustomMessageOutcome::FinalityProofImport(peer, hash, number, proof), + Err(sync::BadPeer(id, repu)) => { + self.behaviour.disconnect_peer(&id); + self.peerset_handle.report_peer(id, repu); + CustomMessageOutcome::None + } } } fn on_remote_body_response( &mut self, - mut network_out: &mut dyn NetworkOut, peer: PeerId, response: message::BlockResponse ) { - self.on_demand_core.on_remote_body_response(&mut network_out, peer, response); + self.on_demand_core.on_remote_body_response(OnDemandIn { + behaviour: &mut self.behaviour, + peerset: self.peerset_handle.clone(), + }, peer, response); } } @@ -1474,8 +1478,8 @@ pub enum CustomMessageOutcome { } fn send_message( + behaviour: &mut CustomProto, Substream>, peers: &mut HashMap>, - network_out: &mut dyn NetworkOut, who: PeerId, mut message: Message, ) { @@ -1490,5 +1494,142 @@ fn send_message( peer.block_request = Some((time::Instant::now(), r.clone())); } } - network_out.send_message(who, message); + behaviour.send_packet(&who, message); +} + +impl, H: ExHashT> NetworkBehaviour for +Protocol { + type ProtocolsHandler = , Substream> as NetworkBehaviour>::ProtocolsHandler; + type OutEvent = CustomMessageOutcome; + + fn new_handler(&mut self) -> Self::ProtocolsHandler { + self.behaviour.new_handler() + } + + fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec { + self.behaviour.addresses_of_peer(peer_id) + } + + fn inject_connected(&mut self, peer_id: PeerId, endpoint: ConnectedPoint) { + self.behaviour.inject_connected(peer_id, endpoint) + } + + fn inject_disconnected(&mut self, peer_id: &PeerId, endpoint: ConnectedPoint) { + self.behaviour.inject_disconnected(peer_id, endpoint) + } + + fn inject_node_event( + &mut self, + peer_id: PeerId, + event: <::Handler as ProtocolsHandler>::OutEvent, + ) { + self.behaviour.inject_node_event(peer_id, event) + } + + fn poll( + &mut self, + params: &mut impl PollParameters, + ) -> Async< + NetworkBehaviourAction< + <::Handler as ProtocolsHandler>::InEvent, + Self::OutEvent + > + > { + while let Ok(Async::Ready(_)) = self.tick_timeout.poll() { + self.tick(); + } + + while let Ok(Async::Ready(_)) = self.propagate_timeout.poll() { + self.propagate_extrinsics(); + } + + for (id, r) in self.sync.block_requests() { + send_message(&mut self.behaviour, &mut self.context_data.peers, id, GenericMessage::BlockRequest(r)) + } + for (id, r) in self.sync.justification_requests() { + send_message(&mut self.behaviour, &mut self.context_data.peers, id, GenericMessage::BlockRequest(r)) + } + for (id, r) in self.sync.finality_proof_requests() { + send_message(&mut self.behaviour, &mut self.context_data.peers, id, GenericMessage::FinalityProofRequest(r)) + } + + let event = match self.behaviour.poll(params) { + Async::NotReady => return Async::NotReady, + Async::Ready(NetworkBehaviourAction::GenerateEvent(ev)) => ev, + Async::Ready(NetworkBehaviourAction::DialAddress { address }) => + return Async::Ready(NetworkBehaviourAction::DialAddress { address }), + Async::Ready(NetworkBehaviourAction::DialPeer { peer_id }) => + return Async::Ready(NetworkBehaviourAction::DialPeer { peer_id }), + Async::Ready(NetworkBehaviourAction::SendEvent { peer_id, event }) => + return Async::Ready(NetworkBehaviourAction::SendEvent { peer_id, event }), + Async::Ready(NetworkBehaviourAction::ReportObservedAddr { address }) => + return Async::Ready(NetworkBehaviourAction::ReportObservedAddr { address }), + }; + + let outcome = match event { + CustomProtoOut::CustomProtocolOpen { peer_id, version, .. } => { + debug_assert!( + version <= CURRENT_VERSION as u8 + && version >= MIN_VERSION as u8 + ); + self.on_peer_connected(peer_id); + CustomMessageOutcome::None + } + CustomProtoOut::CustomProtocolClosed { peer_id, .. } => { + self.on_peer_disconnected(peer_id); + CustomMessageOutcome::None + }, + CustomProtoOut::CustomMessage { peer_id, message } => + self.on_custom_message(peer_id, message), + CustomProtoOut::Clogged { peer_id, messages } => { + debug!(target: "sync", "{} clogging messages:", messages.len()); + for msg in messages.into_iter().take(5) { + debug!(target: "sync", "{:?}", msg); + self.on_clogged_peer(peer_id.clone(), Some(msg)); + } + CustomMessageOutcome::None + } + }; + + if let CustomMessageOutcome::None = outcome { + Async::NotReady + } else { + Async::Ready(NetworkBehaviourAction::GenerateEvent(outcome)) + } + } + + fn inject_replaced(&mut self, peer_id: PeerId, closed_endpoint: ConnectedPoint, new_endpoint: ConnectedPoint) { + self.behaviour.inject_replaced(peer_id, closed_endpoint, new_endpoint) + } + + fn inject_addr_reach_failure( + &mut self, + peer_id: Option<&PeerId>, + addr: &Multiaddr, + error: &dyn std::error::Error + ) { + self.behaviour.inject_addr_reach_failure(peer_id, addr, error) + } + + fn inject_dial_failure(&mut self, peer_id: &PeerId) { + self.behaviour.inject_dial_failure(peer_id) + } + + fn inject_new_listen_addr(&mut self, addr: &Multiaddr) { + self.behaviour.inject_new_listen_addr(addr) + } + + fn inject_expired_listen_addr(&mut self, addr: &Multiaddr) { + self.behaviour.inject_expired_listen_addr(addr) + } + + fn inject_new_external_addr(&mut self, addr: &Multiaddr) { + self.behaviour.inject_new_external_addr(addr) + } +} + +impl, H: ExHashT> DiscoveryNetBehaviour for Protocol { + fn add_discovered_nodes(&mut self, peer_ids: impl Iterator) { + self.behaviour.add_discovered_nodes(peer_ids) + } } diff --git a/core/network/src/protocol/consensus_gossip.rs b/core/network/src/protocol/consensus_gossip.rs index a1c9783b91be5fd84d8086e07d837f367c54cd70..f1343269596aa1c5eb7784be54e4fe08ffc3c000 100644 --- a/core/network/src/protocol/consensus_gossip.rs +++ b/core/network/src/protocol/consensus_gossip.rs @@ -432,13 +432,14 @@ impl ConsensusGossip { } let engine_id = message.engine_id; - //validate the message + // validate the message let validation = self.validators.get(&engine_id) .cloned() .map(|v| { let mut context = NetworkContext { gossip: self, protocol, engine_id }; v.validate(&mut context, &who, &message.data) }); + let validation_result = match validation { Some(ValidationResult::ProcessAndKeep(topic)) => Some((topic, true)), Some(ValidationResult::ProcessAndDiscard(topic)) => Some((topic, false)), diff --git a/core/network/src/protocol/event.rs b/core/network/src/protocol/event.rs new file mode 100644 index 0000000000000000000000000000000000000000..2edbb0fbf7563120dd2378f2c4ccb5eab97c115a --- /dev/null +++ b/core/network/src/protocol/event.rs @@ -0,0 +1,41 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +//! Network event types. These are are not the part of the protocol, but rather +//! events that happen on the network like DHT get/put results received. + +use libp2p::multihash::Multihash; + +/// Events generated by DHT as a response to get_value and put_value requests. +pub enum DhtEvent { + /// The value was found. + ValueFound(Vec<(Multihash, Vec)>), + + /// The requested record has not been found in the DHT. + ValueNotFound(Multihash), + + /// The record has been successfully inserted into the DHT. + ValuePut(Multihash), + + /// An error has occured while putting a record into the DHT. + ValuePutFailed(Multihash), +} + +/// Type for events generated by networking layer. +pub enum Event { + /// Event generated by a DHT. + Dht(DhtEvent), +} diff --git a/core/network/src/protocol/specialization.rs b/core/network/src/protocol/specialization.rs index 41b10bf7079c79c018d918156894aa24f2b80f85..7f6b7dc44f716a2fecb18b84dbeacf6f1cd32093 100644 --- a/core/network/src/protocol/specialization.rs +++ b/core/network/src/protocol/specialization.rs @@ -16,6 +16,8 @@ //! Specializations of the substrate network protocol to allow more complex forms of communication. +pub use crate::protocol::event::{DhtEvent, Event}; + use crate::protocol::Context; use libp2p::PeerId; use runtime_primitives::traits::Block as BlockT; @@ -36,9 +38,12 @@ pub trait NetworkSpecialization: Send + Sync + 'static { &mut self, ctx: &mut dyn Context, who: PeerId, - message: &mut Option> + message: Vec ); + /// Called when a network-specific event arrives. + fn on_event(&mut self, event: Event); + /// Called on abort. #[deprecated(note = "This method is never called; aborting corresponds to dropping the object")] fn on_abort(&mut self) { } @@ -125,11 +130,18 @@ macro_rules! construct_simple_protocol { &mut self, _ctx: &mut $crate::Context<$block>, _who: $crate::PeerId, - _message: &mut Option<$crate::message::Message<$block>> + _message: Vec, ) { $( self.$sub_protocol_name.on_message(_ctx, _who, _message); )* } + fn on_event( + &mut self, + _event: $crate::specialization::Event + ) { + $( self.$sub_protocol_name.on_event(_event); )* + } + fn on_abort(&mut self) { $( self.$sub_protocol_name.on_abort(); )* } diff --git a/core/network/src/protocol/sync.rs b/core/network/src/protocol/sync.rs index 591d5e4669b5840c8d43ea1ecd70cafb66e91a23..5405073a0ea5013e46a0d58e015cc263763f2dc3 100644 --- a/core/network/src/protocol/sync.rs +++ b/core/network/src/protocol/sync.rs @@ -1,16 +1,16 @@ // Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. - +// // Substrate 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. - +// // Substrate 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 Substrate. If not, see . @@ -24,154 +24,161 @@ //! //! The `ChainSync` struct maintains the state of the block requests. Whenever something happens on //! the network, or whenever a block has been successfully verified, call the appropriate method in -//! order to update it. You must also regularly call `tick()`. -//! -//! To each of these methods, you must pass a `Context` object that the `ChainSync` will use to -//! send its new outgoing requests. +//! order to update it. //! -use std::cmp::max; -use std::ops::Range; -use std::collections::{HashMap, VecDeque}; -use log::{debug, trace, warn, info, error}; -use crate::protocol::PeerInfo as ProtocolPeerInfo; -use libp2p::PeerId; -use client::{BlockStatus, ClientInfo}; -use consensus::{BlockOrigin, import_queue::{IncomingBlock, SharedFinalityProofRequestBuilder}}; -use client::error::Error as ClientError; use blocks::BlockCollection; +use client::{BlockStatus, ClientInfo, error::Error as ClientError}; +use consensus::{BlockOrigin, import_queue::{IncomingBlock, BlockImportResult, BlockImportError}}; +use crate::{ + config::{Roles, BoxFinalityProofRequestBuilder}, + message::{self, generic::FinalityProofRequest, BlockAttributes, BlockRequest, BlockResponse, FinalityProofResponse}, + protocol +}; +use either::Either; use extra_requests::ExtraRequests; -use runtime_primitives::traits::{ - Block as BlockT, Header as HeaderT, NumberFor, Zero, One, - CheckedSub, SaturatedConversion +use libp2p::PeerId; +use log::{debug, trace, warn, info, error}; +use runtime_primitives::{ + Justification, + generic::BlockId, + traits::{Block, Header, NumberFor, Zero, One, CheckedSub, SaturatedConversion} }; -use runtime_primitives::{Justification, generic::BlockId}; -use crate::message; -use crate::config::Roles; -use std::collections::HashSet; +use std::{fmt, ops::Range, collections::{HashMap, HashSet, VecDeque}, sync::Arc}; mod blocks; mod extra_requests; /// Maximum blocks to request in a single packet. const MAX_BLOCKS_TO_REQUEST: usize = 128; + /// Maximum blocks to store in the import queue. const MAX_IMPORTING_BLOCKS: usize = 2048; -/// We use a heuristic that with a high likelihood, by the time `MAJOR_SYNC_BLOCKS` have been -/// imported we'll be on the same chain as (or at least closer to) the peer so we want to delay the -/// ancestor search to not waste time doing that when we're so far behind. -const MAJOR_SYNC_BLOCKS: usize = 5; + +/// We use a heuristic that with a high likelihood, by the time +/// `MAJOR_SYNC_BLOCKS` have been imported we'll be on the same +/// chain as (or at least closer to) the peer so we want to delay +/// the ancestor search to not waste time doing that when we are +/// so far behind. +const MAJOR_SYNC_BLOCKS: u8 = 5; + /// Number of recently announced blocks to track for each peer. const ANNOUNCE_HISTORY_SIZE: usize = 64; + /// Max number of blocks to download for unknown forks. const MAX_UNKNOWN_FORK_DOWNLOAD_LEN: u32 = 32; -/// Reputation change when a peer sent us a status message that led to a database read error. + +/// Reputation change when a peer sent us a status message that led to a +/// database read error. const BLOCKCHAIN_STATUS_READ_ERROR_REPUTATION_CHANGE: i32 = -(1 << 16); -/// Reputation change when a peer failed to answer our legitimate ancestry block search. + +/// Reputation change when a peer failed to answer our legitimate ancestry +/// block search. const ANCESTRY_BLOCK_ERROR_REPUTATION_CHANGE: i32 = -(1 << 9); -/// Reputation change when a peer sent us a status message with a different genesis than us. + +/// Reputation change when a peer sent us a status message with a different +/// genesis than us. const GENESIS_MISMATCH_REPUTATION_CHANGE: i32 = i32::min_value() + 1; -/// Context for a network-specific handler. -pub trait Context { - /// Get a reference to the client. - fn client(&self) -> &dyn crate::chain::Client; +/// Reputation change for peers which send us a block with an incomplete header. +const INCOMPLETE_HEADER_REPUTATION_CHANGE: i32 = -(1 << 20); - /// Adjusts the reputation of the peer. Use this to point out that a peer has been malign or - /// irresponsible or appeared lazy. - fn report_peer(&mut self, who: PeerId, reputation: i32); +/// Reputation change for peers which send us a block which we fail to verify. +const VERIFICATION_FAIL_REPUTATION_CHANGE: i32 = -(1 << 20); - /// Force disconnecting from a peer. Use this when a peer misbehaved. - fn disconnect_peer(&mut self, who: PeerId); +/// Reputation change for peers which send us a bad block. +const BAD_BLOCK_REPUTATION_CHANGE: i32 = -(1 << 29); - /// Request a finality proof from a peer. - fn send_finality_proof_request(&mut self, who: PeerId, request: message::FinalityProofRequest); +/// Reputation change for peers which send us a block with bad justifications. +const BAD_JUSTIFICATION_REPUTATION_CHANGE: i32 = -(1 << 16); - /// Request a block from a peer. - fn send_block_request(&mut self, who: PeerId, request: message::BlockRequest); +/// The main data structure which contains all the state for a chains +/// active syncing strategy. +pub struct ChainSync { + /// Chain client. + client: Arc>, + /// The active peers that we are using to sync and their PeerSync status + peers: HashMap>, + /// A `BlockCollection` of blocks that are being downloaded from peers + blocks: BlockCollection, + /// The best block number in our queue of blocks to import + best_queued_number: NumberFor, + /// The best block hash in our queue of blocks to import + best_queued_hash: B::Hash, + /// The role of this node, e.g. light or full + role: Roles, + /// What block attributes we require for this node, usually derived from + /// what role we are, but could be customized + required_block_attributes: message::BlockAttributes, + /// Any extra finality proof requests. + extra_finality_proofs: ExtraRequests, + /// Any extra justification requests. + extra_justifications: ExtraRequests, + /// A set of hashes of blocks that are being downloaded or have been + /// downloaded and are queued for import. + queue_blocks: HashSet, + /// The best block number that we are currently importing. + best_importing_number: NumberFor, + request_builder: Option> } -#[derive(Debug, Clone)] /// All the data we have about a Peer that we are trying to sync with -pub(crate) struct PeerSync { - /// The common number is the block number that is a common point of ancestry for both our chains - /// (as far as we know) +#[derive(Debug, Clone)] +pub struct PeerSync { + /// The common number is the block number that is a common point of + /// ancestry for both our chains (as far as we know). pub common_number: NumberFor, - /// The hash of the best block that we've seen for this peer + /// The hash of the best block that we've seen for this peer. pub best_hash: B::Hash, - /// The number of the best block that we've seen for this peer + /// The number of the best block that we've seen for this peer. pub best_number: NumberFor, - /// The state of syncing this peer is in for us, generally categories into `Available` or "busy" - /// with something as defined by `PeerSyncState`. + /// The state of syncing this peer is in for us, generally categories + /// into `Available` or "busy" with something as defined by `PeerSyncState`. pub state: PeerSyncState, - /// A queue of blocks that this peer has announced to us, should only contain - /// `ANNOUNCE_HISTORY_SIZE` entries. - pub recently_announced: VecDeque, + /// A queue of blocks that this peer has announced to us, should only + /// contain `ANNOUNCE_HISTORY_SIZE` entries. + pub recently_announced: VecDeque } /// The sync status of a peer we are trying to sync with #[derive(Debug)] -pub(crate) struct PeerInfo { +pub struct PeerInfo { /// Their best block hash. pub best_hash: B::Hash, /// Their best block number. - pub best_number: NumberFor, + pub best_number: NumberFor } +/// The state of syncing between a Peer and ourselves. +/// +/// Generally two categories, "busy" or `Available`. If busy, the enum +/// defines what we are busy with. #[derive(Copy, Clone, Eq, PartialEq, Debug)] -/// The ancestor search state expresses which algorithm, and its stateful parameters, we are using to -/// try to find an ancestor block -pub(crate) enum AncestorSearchState { - /// Use exponential backoff to find an ancestor, then switch to binary search. - /// We keep track of the exponent. - ExponentialBackoff(NumberFor), - /// Using binary search to find the best ancestor. - /// We keep track of left and right bounds. - BinarySearch(NumberFor, NumberFor), -} - -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -/// The state of syncing between a Peer and ourselves. Generally two categories, "busy" or -/// `Available`. If busy, the Enum defines what we are busy with. -pub(crate) enum PeerSyncState { - /// Searching for ancestors the Peer has in common with us. - AncestorSearch(NumberFor, AncestorSearchState), +pub enum PeerSyncState { /// Available for sync requests. Available, + /// Searching for ancestors the Peer has in common with us. + AncestorSearch(NumberFor, AncestorSearchState), /// Actively downloading new blocks, starting from the given Number. DownloadingNew(NumberFor), - /// Downloading a stale block with given Hash. Stale means that it's a block with a number that - /// is lower than our best number. It might be from a fork and not necessarily already imported. + /// Downloading a stale block with given Hash. Stale means that it is a + /// block with a number that is lower than our best number. It might be + /// from a fork and not necessarily already imported. DownloadingStale(B::Hash), /// Downloading justification for given block hash. DownloadingJustification(B::Hash), /// Downloading finality proof for given block hash. - DownloadingFinalityProof(B::Hash), + DownloadingFinalityProof(B::Hash) } -/// The main data structure to contain all the state for a chains active syncing strategy. -pub struct ChainSync { - /// The active peers that we are using to sync and their PeerSync status - peers: HashMap>, - /// A `BlockCollection` of blocks that are being downloaded from peers - blocks: BlockCollection, - /// The best block number in our queue of blocks to import - best_queued_number: NumberFor, - /// The best block hash in our queue of blocks to import - best_queued_hash: B::Hash, - /// The role of this node, e.g. light or full - role: Roles, - /// What block attributes we require for this node, usually derived from what role we are, but - /// could be customized - required_block_attributes: message::BlockAttributes, - extra_finality_proofs: ExtraRequests, - extra_justifications: ExtraRequests, - /// A set of hashes of blocks that are being downloaded or have been downloaded and are queued - /// for import. - queue_blocks: HashSet, - /// The best block number that we are currently importing - best_importing_number: NumberFor, - request_builder: Option>, +impl PeerSyncState { + pub fn is_available(&self) -> bool { + if let PeerSyncState::Available = self { + true + } else { + false + } + } } /// Reported sync state. @@ -183,44 +190,93 @@ pub enum SyncState { Downloading } -/// Syncing status and statistics +/// Syncing status and statistics. #[derive(Clone)] -pub struct Status { +pub struct Status { /// Current global sync state. pub state: SyncState, /// Target sync block number. pub best_seen_block: Option>, /// Number of peers participating in syncing. - pub num_peers: u32, + pub num_peers: u32 } -impl Status { - /// Whether the synchronization status is doing major downloading work or - /// is near the head of the chain. - pub fn is_major_syncing(&self) -> bool { - match self.state { - SyncState::Idle => false, - SyncState::Downloading => true, - } +/// A peer did not behave as expected and should be reported. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct BadPeer(pub PeerId, pub i32); + +impl fmt::Display for BadPeer { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "bad peer {}; reputation change: {}", self.0, self.1) } +} + +impl std::error::Error for BadPeer {} - /// Are we all alone? - pub fn is_offline(&self) -> bool { - self.num_peers == 0 +/// Result of [`ChainSync::on_block_data`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum OnBlockData { + /// The block should be imported. + Import(BlockOrigin, Vec>), + /// A new block request needs to be made to the given peer. + Request(PeerId, BlockRequest) +} + +/// Result of [`ChainSync::on_block_announce`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum OnBlockAnnounce { + /// The announcement does not require further handling. + Nothing, + /// The announcement header should be imported. + ImportHeader, + /// Another block request to the given peer is necessary. + Request(PeerId, BlockRequest) +} + +/// Result of [`ChainSync::on_block_justification`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum OnBlockJustification { + /// The justification needs no further handling. + Nothing, + /// The justification should be imported. + Import { + peer: PeerId, + hash: B::Hash, + number: NumberFor, + justification: Justification + } +} + +/// Result of [`ChainSync::on_block_finality_proof`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum OnBlockFinalityProof { + /// The proof needs no further handling. + Nothing, + /// The proof should be imported. + Import { + peer: PeerId, + hash: B::Hash, + number: NumberFor, + proof: Vec } } -impl ChainSync { - /// Create a new instance. Pass the initial known state of the chain. - pub(crate) fn new(role: Roles, info: &ClientInfo) -> Self { - let mut required_block_attributes = - message::BlockAttributes::HEADER | message::BlockAttributes::JUSTIFICATION; +impl ChainSync { + /// Create a new instance. + pub fn new( + role: Roles, + client: Arc>, + info: &ClientInfo, + request_builder: Option> + ) -> Self { + let mut required_block_attributes = BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION; if role.is_full() { - required_block_attributes |= message::BlockAttributes::BODY; + required_block_attributes |= BlockAttributes::BODY } ChainSync { + client, peers: HashMap::new(), blocks: BlockCollection::new(), best_queued_hash: info.chain.best_hash, @@ -231,130 +287,118 @@ impl ChainSync { required_block_attributes, queue_blocks: Default::default(), best_importing_number: Zero::zero(), - request_builder: None, + request_builder } } - /// Returns the number for the best seen blocks among connected peers, if any - fn best_seen_block(&self) -> Option> { - self.peers.values().max_by_key(|p| p.best_number).map(|p| p.best_number) - } - - /// Returns the SyncState that we are currently in based on a provided `best_seen` block number. - /// A chain is classified as downloading if the provided best block is more than `MAJOR_SYNC_BLOCKS` - /// behind the best queued block. - fn state(&self, best_seen: &Option>) -> SyncState { - match best_seen { - &Some(n) if n > self.best_queued_number && n - self.best_queued_number > 5.into() => SyncState::Downloading, - _ => SyncState::Idle, - } + /// Returns the state of the sync of the given peer. + /// + /// Returns `None` if the peer is unknown. + pub fn peer_info(&self, who: &PeerId) -> Option> { + self.peers.get(who).map(|p| PeerInfo { best_hash: p.best_hash, best_number: p.best_number }) } - /// Returns the state of the sync of the given peer. Returns `None` if the peer is unknown. - pub(crate) fn peer_info(&self, who: &PeerId) -> Option> { - self.peers.get(who).map(|peer| { - PeerInfo { - best_hash: peer.best_hash, - best_number: peer.best_number, - } - }) - } + /// Returns the current sync status. + pub fn status(&self) -> Status { + let best_seen = self.peers.values().max_by_key(|p| p.best_number).map(|p| p.best_number); + let sync_state = + if let Some(n) = best_seen { + // A chain is classified as downloading if the provided best block is + // more than `MAJOR_SYNC_BLOCKS` behind the best queued block. + if n > self.best_queued_number && n - self.best_queued_number > MAJOR_SYNC_BLOCKS.into() { + SyncState::Downloading + } else { + SyncState::Idle + } + } else { + SyncState::Idle + }; - /// Returns sync status. - pub(crate) fn status(&self) -> Status { - let best_seen = self.best_seen_block(); - let state = self.state(&best_seen); Status { - state, + state: sync_state, best_seen_block: best_seen, - num_peers: self.peers.len() as u32, + num_peers: self.peers.len() as u32 } } - /// Handle new connected peer. Call this method whenever we connect to a new peer. - pub(crate) fn new_peer( - &mut self, - protocol: &mut dyn Context, - who: PeerId, - info: ProtocolPeerInfo - ) { - // there's nothing sync can get from the node that has no blockchain data - // (the opposite is not true, but all requests are served at protocol level) + /// Handle a new connected peer. + /// + /// Call this method whenever we connect to a new peer. + pub fn new_peer(&mut self, who: PeerId, info: protocol::PeerInfo) -> Result>, BadPeer> { + // There is nothing sync can get from the node that has no blockchain data. if !info.roles.is_full() { - return; + return Ok(None) } - - let status = block_status(&*protocol.client(), &self.queue_blocks, info.best_hash); - match (status, info.best_number) { - (Err(e), _) => { + match self.block_status(&info.best_hash) { + Err(e) => { debug!(target:"sync", "Error reading blockchain: {:?}", e); - protocol.report_peer(who.clone(), BLOCKCHAIN_STATUS_READ_ERROR_REPUTATION_CHANGE); - protocol.disconnect_peer(who); - }, - (Ok(BlockStatus::KnownBad), _) => { + Err(BadPeer(who, BLOCKCHAIN_STATUS_READ_ERROR_REPUTATION_CHANGE)) + } + Ok(BlockStatus::KnownBad) => { info!("New peer with known bad best block {} ({}).", info.best_hash, info.best_number); - protocol.report_peer(who.clone(), i32::min_value()); - protocol.disconnect_peer(who); - }, - (Ok(BlockStatus::Unknown), b) if b.is_zero() => { - info!("New peer with unknown genesis hash {} ({}).", info.best_hash, info.best_number); - protocol.report_peer(who.clone(), i32::min_value()); - protocol.disconnect_peer(who); - }, - (Ok(BlockStatus::Unknown), _) if self.queue_blocks.len() > MAJOR_SYNC_BLOCKS => { + Err(BadPeer(who, i32::min_value())) + } + Ok(BlockStatus::Unknown) => { + if info.best_number.is_zero() { + info!("New peer with unknown genesis hash {} ({}).", info.best_hash, info.best_number); + return Err(BadPeer(who, i32::min_value())) + } + // If there are more than `MAJOR_SYNC_BLOCKS` in the import queue then we have // enough to do in the import queue that it's not worth kicking off // an ancestor search, which is what we do in the next match case below. - debug!( - target:"sync", - "New peer with unknown best hash {} ({}), assuming common block.", - self.best_queued_hash, - self.best_queued_number - ); - self.peers.insert(who, PeerSync { - common_number: self.best_queued_number, - best_hash: info.best_hash, - best_number: info.best_number, - state: PeerSyncState::Available, - recently_announced: Default::default(), - }); - } - (Ok(BlockStatus::Unknown), _) => { - let our_best = self.best_queued_number; - if our_best.is_zero() { - // We are at genesis, just start downloading - debug!(target:"sync", "New peer with best hash {} ({}).", info.best_hash, info.best_number); - self.peers.insert(who.clone(), PeerSync { - common_number: Zero::zero(), + if self.queue_blocks.len() > MAJOR_SYNC_BLOCKS.into() { + debug!( + target:"sync", + "New peer with unknown best hash {} ({}), assuming common block.", + self.best_queued_hash, + self.best_queued_number + ); + self.peers.insert(who, PeerSync { + common_number: self.best_queued_number, best_hash: info.best_hash, best_number: info.best_number, state: PeerSyncState::Available, - recently_announced: Default::default(), + recently_announced: Default::default() }); - self.download_new(protocol, who) - } else { - let common_best = ::std::cmp::min(our_best, info.best_number); - debug!(target:"sync", - "New peer with unknown best hash {} ({}), searching for common ancestor.", - info.best_hash, - info.best_number - ); + return Ok(None) + } + + // If we are at genesis, just start downloading. + if self.best_queued_number.is_zero() { + debug!(target:"sync", "New peer with best hash {} ({}).", info.best_hash, info.best_number); self.peers.insert(who.clone(), PeerSync { common_number: Zero::zero(), best_hash: info.best_hash, best_number: info.best_number, - state: PeerSyncState::AncestorSearch( - common_best, - AncestorSearchState::ExponentialBackoff(One::one()) - ), + state: PeerSyncState::Available, recently_announced: Default::default(), }); - Self::request_ancestry(protocol, who, common_best) + return Ok(self.select_new_blocks(who).map(|(_, req)| req)) } - }, - (Ok(BlockStatus::Queued), _) | - (Ok(BlockStatus::InChainWithState), _) | - (Ok(BlockStatus::InChainPruned), _) => { + + let common_best = std::cmp::min(self.best_queued_number, info.best_number); + + debug!(target:"sync", + "New peer with unknown best hash {} ({}), searching for common ancestor.", + info.best_hash, + info.best_number + ); + + self.peers.insert(who, PeerSync { + common_number: Zero::zero(), + best_hash: info.best_hash, + best_number: info.best_number, + state: PeerSyncState::AncestorSearch( + common_best, + AncestorSearchState::ExponentialBackoff(One::one()) + ), + recently_announced: Default::default() + }); + + Ok(Some(ancestry_request::(common_best))) + } + Ok(BlockStatus::Queued) | Ok(BlockStatus::InChainWithState) | Ok(BlockStatus::InChainPruned) => { debug!(target:"sync", "New peer with known best hash {} ({}).", info.best_hash, info.best_number); self.peers.insert(who.clone(), PeerSync { common_number: info.best_number, @@ -363,395 +407,421 @@ impl ChainSync { state: PeerSyncState::Available, recently_announced: Default::default(), }); + Ok(None) } } } - /// This function handles the ancestor search strategy used. The goal is to find a common point - /// that both our chains agree on that is as close to the tip as possible. - /// The way this works is we first have an exponential backoff strategy, where we try to step - /// forward until we find a block hash mismatch. The size of the step doubles each step we take. - /// - /// When we've found a block hash mismatch we then fall back to a binary search between the two - /// last known points to find the common block closest to the tip. - fn handle_ancestor_search_state( - state: AncestorSearchState, - curr_block_num: NumberFor, - block_hash_match: bool, - ) -> Option<(AncestorSearchState, NumberFor)> { - let two = >::one() + >::one(); - match state { - AncestorSearchState::ExponentialBackoff(next_distance_to_tip) => { - if block_hash_match && next_distance_to_tip == One::one() { - // We found the ancestor in the first step so there is no need to execute binary search. - return None; - } - if block_hash_match { - let left = curr_block_num; - let right = left + next_distance_to_tip / two; - let middle = left + (right - left) / two; - Some((AncestorSearchState::BinarySearch(left, right), middle)) - } else { - let next_block_num = curr_block_num.checked_sub(&next_distance_to_tip) - .unwrap_or_else(Zero::zero); - let next_distance_to_tip = next_distance_to_tip * two; - Some((AncestorSearchState::ExponentialBackoff(next_distance_to_tip), next_block_num)) - } - }, - AncestorSearchState::BinarySearch(mut left, mut right) => { - if left >= curr_block_num { - return None; - } - if block_hash_match { - left = curr_block_num; - } else { - right = curr_block_num; - } - assert!(right >= left); - let middle = left + (right - left) / two; - Some((AncestorSearchState::BinarySearch(left, right), middle)) - }, + /// Signal that `best_header` has been queued for import and update the + /// `ChainSync` state with that information. + pub fn update_chain_info(&mut self, best_header: &B::Header) { + self.on_block_queued(&best_header.hash(), *best_header.number()) + } + + /// Schedule a justification request for the given block. + pub fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { + let client = &self.client; + self.extra_justifications.schedule((*hash, number), |base, block| { + client.is_descendent_of(base, block) + }) + } + + /// Schedule a finality proof request for the given block. + pub fn request_finality_proof(&mut self, hash: &B::Hash, number: NumberFor) { + let client = &self.client; + self.extra_finality_proofs.schedule((*hash, number), |base, block| { + client.is_descendent_of(base, block) + }) + } + + /// Get an iterator over all scheduled justification requests. + pub fn justification_requests(&mut self) -> impl Iterator)> + '_ { + let peers = &mut self.peers; + let mut matcher = self.extra_justifications.matcher(); + std::iter::from_fn(move || { + if let Some((peer, request)) = matcher.next(&peers) { + peers.get_mut(&peer) + .expect("`Matcher::next` guarantees the `PeerId` comes from the given peers; qed") + .state = PeerSyncState::DownloadingJustification(request.0); + let req = message::generic::BlockRequest { + id: 0, + fields: BlockAttributes::JUSTIFICATION, + from: message::FromBlock::Hash(request.0), + to: None, + direction: message::Direction::Ascending, + max: Some(1) + }; + Some((peer, req)) + } else { + None + } + }) + } + + /// Get an iterator over all scheduled finality proof requests. + pub fn finality_proof_requests(&mut self) -> impl Iterator)> + '_ { + let peers = &mut self.peers; + let request_builder = &mut self.request_builder; + let mut matcher = self.extra_finality_proofs.matcher(); + std::iter::from_fn(move || { + if let Some((peer, request)) = matcher.next(&peers) { + peers.get_mut(&peer) + .expect("`Matcher::next` guarantees the `PeerId` comes from the given peers; qed") + .state = PeerSyncState::DownloadingFinalityProof(request.0); + let req = message::generic::FinalityProofRequest { + id: 0, + block: request.0, + request: request_builder.as_mut() + .map(|builder| builder.build_request_data(&request.0)) + .unwrap_or_default() + }; + Some((peer, req)) + } else { + None + } + }) + } + + /// Get an iterator over all block requests of all peers. + pub fn block_requests(&mut self) -> impl Iterator)> + '_ { + if self.queue_blocks.len() > MAX_IMPORTING_BLOCKS { + trace!(target: "sync", "Too many blocks in the queue."); + return Either::Left(std::iter::empty()) } + let blocks = &mut self.blocks; + let attrs = &self.required_block_attributes; + let iter = self.peers.iter_mut().filter_map(move |(id, peer)| { + if !peer.state.is_available() { + trace!(target: "sync", "Peer {} is busy", id); + return None + } + if let Some((range, req)) = peer_block_request(id, peer, blocks, attrs) { + peer.state = PeerSyncState::DownloadingNew(range.start); + trace!(target: "sync", "new block request for {}", id); + Some((id.clone(), req)) + } else { + trace!(target: "sync", "no new block request for {}", id); + None + } + }); + Either::Right(iter) } /// Handle a response from the remote to a block request that we made. /// /// `request` must be the original request that triggered `response`. /// - /// If this corresponds to a valid block, this outputs the block that must be imported in the - /// import queue. - #[must_use] - pub(crate) fn on_block_data( - &mut self, - protocol: &mut dyn Context, - who: PeerId, - request: message::BlockRequest, - response: message::BlockResponse - ) -> Option<(BlockOrigin, Vec>)> { - let new_blocks: Vec> = if let Some(ref mut peer) = self.peers.get_mut(&who) { - let mut blocks = response.blocks; - if request.direction == message::Direction::Descending { - trace!(target: "sync", "Reversing incoming block list"); - blocks.reverse(); - } - let peer_state = peer.state.clone(); - match peer_state { - PeerSyncState::DownloadingNew(start_block) => { - self.blocks.clear_peer_download(&who); - peer.state = PeerSyncState::Available; - self.blocks.insert(start_block, blocks, who); - self.blocks - .drain(self.best_queued_number + One::one()) - .into_iter() - .map(|block_data| { + /// If this corresponds to a valid block, this outputs the block that + /// must be imported in the import queue. + pub fn on_block_data + (&mut self, who: PeerId, request: BlockRequest, response: BlockResponse) -> Result, BadPeer> + { + let new_blocks: Vec> = + if let Some(peer) = self.peers.get_mut(&who) { + let mut blocks = response.blocks; + if request.direction == message::Direction::Descending { + trace!(target: "sync", "Reversing incoming block list"); + blocks.reverse() + } + match &mut peer.state { + PeerSyncState::DownloadingNew(start_block) => { + self.blocks.clear_peer_download(&who); + self.blocks.insert(*start_block, blocks, who); + peer.state = PeerSyncState::Available; + self.blocks + .drain(self.best_queued_number + One::one()) + .into_iter() + .map(|block_data| { + IncomingBlock { + hash: block_data.block.hash, + header: block_data.block.header, + body: block_data.block.body, + justification: block_data.block.justification, + origin: block_data.origin, + } + }).collect() + } + PeerSyncState::DownloadingStale(_) => { + peer.state = PeerSyncState::Available; + blocks.into_iter().map(|b| { IncomingBlock { - hash: block_data.block.hash, - header: block_data.block.header, - body: block_data.block.body, - justification: block_data.block.justification, - origin: block_data.origin, + hash: b.hash, + header: b.header, + body: b.body, + justification: b.justification, + origin: Some(who.clone()), } }).collect() - }, - PeerSyncState::DownloadingStale(_) => { - peer.state = PeerSyncState::Available; - blocks.into_iter().map(|b| { - IncomingBlock { - hash: b.hash, - header: b.header, - body: b.body, - justification: b.justification, - origin: Some(who.clone()), - } - }).collect() - }, - PeerSyncState::AncestorSearch(num, state) => { - let block_hash_match = match (blocks.get(0), protocol.client().block_hash(num)) { - (Some(ref block), Ok(maybe_our_block_hash)) => { - trace!(target: "sync", "Got ancestry block #{} ({}) from peer {}", num, block.hash, who); - maybe_our_block_hash.map_or(false, |x| x == block.hash) - }, - (None, _) => { - debug!(target: "sync", "Invalid response when searching for ancestor from {}", who); - protocol.report_peer(who.clone(), i32::min_value()); - protocol.disconnect_peer(who); - return None - }, - (_, Err(e)) => { - info!("Error answering legitimate blockchain query: {:?}", e); - protocol.report_peer(who.clone(), ANCESTRY_BLOCK_ERROR_REPUTATION_CHANGE); - protocol.disconnect_peer(who); - return None - }, - }; - if block_hash_match && peer.common_number < num { - peer.common_number = num; - } - if !block_hash_match && num.is_zero() { - trace!(target:"sync", "Ancestry search: genesis mismatch for peer {}", who); - protocol.report_peer(who.clone(), GENESIS_MISMATCH_REPUTATION_CHANGE); - protocol.disconnect_peer(who); - return None } - if let Some((next_state, next_block_num)) = - Self::handle_ancestor_search_state(state, num, block_hash_match) { - peer.state = PeerSyncState::AncestorSearch(next_block_num, next_state); - Self::request_ancestry(protocol, who, next_block_num); - return None - } else { - peer.state = PeerSyncState::Available; - vec![] + PeerSyncState::AncestorSearch(num, state) => { + let block_hash_match = match (blocks.get(0), self.client.block_hash(*num)) { + (Some(block), Ok(maybe_our_block_hash)) => { + trace!(target: "sync", "Got ancestry block #{} ({}) from peer {}", num, block.hash, who); + maybe_our_block_hash.map_or(false, |x| x == block.hash) + }, + (None, _) => { + debug!(target: "sync", "Invalid response when searching for ancestor from {}", who); + return Err(BadPeer(who, i32::min_value())) + }, + (_, Err(e)) => { + info!("Error answering legitimate blockchain query: {:?}", e); + return Err(BadPeer(who, ANCESTRY_BLOCK_ERROR_REPUTATION_CHANGE)) + } + }; + if block_hash_match && peer.common_number < *num { + peer.common_number = *num; + } + if !block_hash_match && num.is_zero() { + trace!(target:"sync", "Ancestry search: genesis mismatch for peer {}", who); + return Err(BadPeer(who, GENESIS_MISMATCH_REPUTATION_CHANGE)) + } + if let Some((next_state, next_num)) = handle_ancestor_search_state(state, *num, block_hash_match) { + peer.state = PeerSyncState::AncestorSearch(next_num, next_state); + return Ok(OnBlockData::Request(who, ancestry_request::(next_num))) + } else { + peer.state = PeerSyncState::Available; + Vec::new() + } } - }, - PeerSyncState::Available | - PeerSyncState::DownloadingJustification(..) | - PeerSyncState::DownloadingFinalityProof(..) => Vec::new(), - } - } else { - Vec::new() - }; - let is_recent = new_blocks - .first() - .map(|block| self.peers.iter().any(|(_, peer)| peer.recently_announced.contains(&block.hash))) + | PeerSyncState::Available + | PeerSyncState::DownloadingJustification(..) + | PeerSyncState::DownloadingFinalityProof(..) => Vec::new() + } + } else { + Vec::new() + }; + + let is_recent = new_blocks.first() + .map(|block| { + self.peers.iter().any(|(_, peer)| peer.recently_announced.contains(&block.hash)) + }) .unwrap_or(false); - let origin = if is_recent { BlockOrigin::NetworkBroadcast } else { BlockOrigin::NetworkInitialSync }; - if let Some((hash, number)) = new_blocks.last() - .and_then(|b| b.header.as_ref().map(|h| (b.hash.clone(), *h.number()))) - { - trace!(target:"sync", "Accepted {} blocks ({:?}) with origin {:?}", new_blocks.len(), hash, origin); - self.block_queued(&hash, number); + let origin = + if is_recent { + BlockOrigin::NetworkBroadcast + } else { + BlockOrigin::NetworkInitialSync + }; + + if let Some((h, n)) = new_blocks.last().and_then(|b| b.header.as_ref().map(|h| (&b.hash, *h.number()))) { + trace!(target:"sync", "Accepted {} blocks ({:?}) with origin {:?}", new_blocks.len(), h, origin); + self.on_block_queued(h, n) } - self.maintain_sync(protocol); - let new_best_importing_number = new_blocks - .last() - .and_then(|b| b.header.as_ref().map(|h| h.number().clone())) + + let new_best_importing_number = new_blocks.last() + .and_then(|b| b.header.as_ref().map(|h| *h.number())) .unwrap_or_else(|| Zero::zero()); - self.queue_blocks - .extend(new_blocks.iter().map(|b| b.hash.clone())); - self.best_importing_number = max(new_best_importing_number, self.best_importing_number); - Some((origin, new_blocks)) + + self.queue_blocks.extend(new_blocks.iter().map(|b| b.hash)); + + self.best_importing_number = std::cmp::max(new_best_importing_number, self.best_importing_number); + + Ok(OnBlockData::Import(origin, new_blocks)) } /// Handle a response from the remote to a justification request that we made. /// /// `request` must be the original request that triggered `response`. /// - /// Returns `Some` if this produces a justification that must be imported into the import - /// queue. - #[must_use] - pub(crate) fn on_block_justification_data( - &mut self, - protocol: &mut dyn Context, - who: PeerId, - response: message::BlockResponse, - ) -> Option<(PeerId, B::Hash, NumberFor, Justification)> + /// Returns `Some` if this produces a justification that must be imported + /// into the import queue. + pub fn on_block_justification + (&mut self, who: PeerId, response: BlockResponse) -> Result, BadPeer> { - let peer = if let Some(peer) = self.peers.get_mut(&who) { - peer - } else { - error!(target: "sync", "Called on_block_justification_data with a bad peer ID"); - return None; - }; + let peer = + if let Some(peer) = self.peers.get_mut(&who) { + peer + } else { + error!(target: "sync", "Called on_block_justification with a bad peer ID"); + return Ok(OnBlockJustification::Nothing) + }; if let PeerSyncState::DownloadingJustification(hash) = peer.state { peer.state = PeerSyncState::Available; - // we only request one justification at a time - match response.blocks.into_iter().next() { - Some(response) => { - if hash != response.hash { - info!("Invalid block justification provided by {}: requested: {:?} got: {:?}", - who, hash, response.hash); - protocol.report_peer(who.clone(), i32::min_value()); - protocol.disconnect_peer(who); - return None; - } - return self.extra_justifications.on_response(who, response.justification) - } - None => { - // we might have asked the peer for a justification on a block that we thought it had - // (regardless of whether it had a justification for it or not). - trace!(target: "sync", "Peer {:?} provided empty response for justification request {:?}", - who, - hash, + // We only request one justification at a time + debug_assert_eq!(1, response.blocks.len()); + + if let Some(block) = response.blocks.into_iter().next() { + if hash != block.hash { + info!( + "Invalid block justification provided by {}: requested: {:?} got: {:?}", who, hash, block.hash ); - return None; + return Err(BadPeer(who, i32::min_value())) + } + if let Some((peer, hash, number, j)) = self.extra_justifications.on_response(who, block.justification) { + return Ok(OnBlockJustification::Import { peer, hash, number, justification: j }) } + } else { + // we might have asked the peer for a justification on a block that we thought it had + // (regardless of whether it had a justification for it or not). + trace!(target: "sync", "Peer {:?} provided empty response for justification request {:?}", who, hash) } } - self.maintain_sync(protocol); - None + Ok(OnBlockJustification::Nothing) } /// Handle new finality proof data. - pub(crate) fn on_block_finality_proof_data( - &mut self, - protocol: &mut dyn Context, - who: PeerId, - response: message::FinalityProofResponse, - ) -> Option<(PeerId, B::Hash, NumberFor, Vec)> { - let peer = if let Some(peer) = self.peers.get_mut(&who) { - peer - } else { - error!(target: "sync", "Called on_block_finality_proof_data with a bad peer ID"); - return None; - }; + pub fn on_block_finality_proof + (&mut self, who: PeerId, resp: FinalityProofResponse) -> Result, BadPeer> + { + let peer = + if let Some(peer) = self.peers.get_mut(&who) { + peer + } else { + error!(target: "sync", "Called on_block_finality_proof_data with a bad peer ID"); + return Ok(OnBlockFinalityProof::Nothing) + }; if let PeerSyncState::DownloadingFinalityProof(hash) = peer.state { peer.state = PeerSyncState::Available; - // we only request one finality proof at a time - if hash != response.block { - info!( - "Invalid block finality proof provided: requested: {:?} got: {:?}", - hash, - response.block, - ); - - protocol.report_peer(who.clone(), i32::min_value()); - protocol.disconnect_peer(who); - return None; + // We only request one finality proof at a time. + if hash != resp.block { + info!("Invalid block finality proof provided: requested: {:?} got: {:?}", hash, resp.block); + return Err(BadPeer(who, i32::min_value())) } - return self.extra_finality_proofs.on_response(who, response.proof) + if let Some((peer, hash, number, p)) = self.extra_finality_proofs.on_response(who, resp.proof) { + return Ok(OnBlockFinalityProof::Import { peer, hash, number, proof: p }) + } } - self.maintain_sync(protocol); - None + Ok(OnBlockFinalityProof::Nothing) } /// A batch of blocks have been processed, with or without errors. - /// Call this when a batch of blocks have been processed by the import queue, with or without - /// errors. - pub fn blocks_processed(&mut self, protocol: &mut dyn Context, processed_blocks: Vec, has_error: bool) { - for hash in processed_blocks { - self.queue_blocks.remove(&hash); - } - if has_error { - self.best_importing_number = Zero::zero(); - } - self.maintain_sync(protocol) - } + /// + /// Call this when a batch of blocks have been processed by the import + /// queue, with or without errors. + /// + /// `peer_info` is passed in case of a restart. + pub fn on_blocks_processed<'a>( + &'a mut self, + imported: usize, + count: usize, + results: Vec<(Result>, BlockImportError>, B::Hash)>, + mut peer_info: impl FnMut(&PeerId) -> Option> + ) -> impl Iterator), BadPeer>> + 'a { + trace!(target: "sync", "Imported {} of {}", imported, count); + + let mut output = Vec::new(); + + let mut has_error = false; + let mut hashes = vec![]; + for (result, hash) in results { + hashes.push(hash); + + if has_error { + continue; + } - /// Maintain the sync process (download new blocks, fetch justifications). - fn maintain_sync(&mut self, protocol: &mut dyn Context) { - let peers: Vec = self.peers.keys().map(|p| p.clone()).collect(); - for peer in peers { - self.download_new(protocol, peer); - } - self.tick(protocol) - } + if result.is_err() { + has_error = true; + } - /// Called periodically to perform any time-based actions. Must be called at a regular - /// interval. - pub fn tick(&mut self, protocol: &mut dyn Context) { - self.send_justification_requests(protocol); - self.send_finality_proof_request(protocol) - } + match result { + Ok(BlockImportResult::ImportedKnown(_number)) => {} + Ok(BlockImportResult::ImportedUnknown(number, aux, who)) => { + if aux.clear_justification_requests { + trace!( + target: "sync", + "Block imported clears all pending justification requests {}: {:?}", + number, + hash + ); + self.extra_justifications.reset() + } - fn send_justification_requests(&mut self, protocol: &mut dyn Context) { - let mut matcher = self.extra_justifications.matcher(); - while let Some((peer, request)) = matcher.next(&self.peers) { - self.peers.get_mut(&peer) - .expect("`Matcher::next` guarantees the `PeerId` comes from the given peers; qed") - .state = PeerSyncState::DownloadingJustification(request.0); - protocol.send_block_request(peer, message::generic::BlockRequest { - id: 0, - fields: message::BlockAttributes::JUSTIFICATION, - from: message::FromBlock::Hash(request.0), - to: None, - direction: message::Direction::Ascending, - max: Some(1) - }) - } - } + if aux.needs_justification { + trace!(target: "sync", "Block imported but requires justification {}: {:?}", number, hash); + self.request_justification(&hash, number); + } - fn send_finality_proof_request(&mut self, protocol: &mut dyn Context) { - let mut matcher = self.extra_finality_proofs.matcher(); - while let Some((peer, request)) = matcher.next(&self.peers) { - self.peers.get_mut(&peer) - .expect("`Matcher::next` guarantees the `PeerId` comes from the given peers; qed") - .state = PeerSyncState::DownloadingFinalityProof(request.0); - protocol.send_finality_proof_request(peer, message::generic::FinalityProofRequest { - id: 0, - block: request.0, - request: self.request_builder.as_ref() - .map(|builder| builder.build_request_data(&request.0)) - .unwrap_or_default() - }) + if aux.bad_justification { + if let Some(peer) = who { + info!("Sent block with bad justification to import"); + output.push(Err(BadPeer(peer, BAD_JUSTIFICATION_REPUTATION_CHANGE))); + } + } + + if aux.needs_finality_proof { + trace!(target: "sync", "Block imported but requires finality proof {}: {:?}", number, hash); + self.request_finality_proof(&hash, number); + } + }, + Err(BlockImportError::IncompleteHeader(who)) => { + if let Some(peer) = who { + info!("Peer sent block with incomplete header to import"); + output.push(Err(BadPeer(peer, INCOMPLETE_HEADER_REPUTATION_CHANGE))); + output.extend(self.restart(&mut peer_info)); + } + }, + Err(BlockImportError::VerificationFailed(who, e)) => { + if let Some(peer) = who { + info!("Verification failed from peer: {}", e); + output.push(Err(BadPeer(peer, VERIFICATION_FAIL_REPUTATION_CHANGE))); + output.extend(self.restart(&mut peer_info)); + } + }, + Err(BlockImportError::BadBlock(who)) => { + if let Some(peer) = who { + info!("Bad block"); + output.push(Err(BadPeer(peer, BAD_BLOCK_REPUTATION_CHANGE))); + output.extend(self.restart(&mut peer_info)); + } + }, + Err(BlockImportError::UnknownParent) | + Err(BlockImportError::Cancelled) | + Err(BlockImportError::Other(_)) => { + output.extend(self.restart(&mut peer_info)); + }, + }; } - } - /// Request a justification for the given block. - /// - /// Uses `protocol` to queue a new justification request and tries to dispatch all pending - /// requests. - pub fn request_justification(&mut self, hash: &B::Hash, number: NumberFor, protocol: &mut dyn Context) { - self.extra_justifications.schedule((*hash, number), |base, block| { - protocol.client().is_descendent_of(base, block) - }); - self.send_justification_requests(protocol) - } + for hash in hashes { + self.queue_blocks.remove(&hash); + } + if has_error { + self.best_importing_number = Zero::zero() + } - /// Clears all pending justification requests. - pub fn clear_justification_requests(&mut self) { - self.extra_justifications.reset() + output.into_iter() } - /// Call this when a justification has been processed by the import queue, with or without - /// errors. - pub fn justification_import_result(&mut self, hash: B::Hash, number: NumberFor, success: bool) { + /// Call this when a justification has been processed by the import queue, + /// with or without errors. + pub fn on_justification_import(&mut self, hash: B::Hash, number: NumberFor, success: bool) { let finalization_result = if success { Ok((hash, number)) } else { Err(()) }; if !self.extra_justifications.try_finalize_root((hash, number), finalization_result, true) { debug!(target: "sync", "Got justification import result for unknown justification {:?} {:?} request.", hash, number, - ); + ) } } - /// Request a finality proof for the given block. - /// - /// Queues a new finality proof request and tries to dispatch all pending requests. - pub fn request_finality_proof(&mut self, hash: &B::Hash, number: NumberFor, protocol: &mut dyn Context) { - self.extra_finality_proofs.schedule((*hash, number), |base, block| { - protocol.client().is_descendent_of(base, block) - }); - self.send_finality_proof_request(protocol) - } - - pub fn finality_proof_import_result( - &mut self, - request_block: (B::Hash, NumberFor), - finalization_result: Result<(B::Hash, NumberFor), ()>, - ) { - self.extra_finality_proofs.try_finalize_root(request_block, finalization_result, true); - } - - pub fn set_finality_proof_request_builder(&mut self, builder: SharedFinalityProofRequestBuilder) { - self.request_builder = Some(builder) - } - - /// Log that a block has been successfully imported - pub fn block_imported(&mut self, hash: &B::Hash, number: NumberFor) { - trace!(target: "sync", "Block imported successfully {} ({})", number, hash); + pub fn on_finality_proof_import(&mut self, req: (B::Hash, NumberFor), res: Result<(B::Hash, NumberFor), ()>) { + self.extra_finality_proofs.try_finalize_root(req, res, true); } /// Notify about finalization of the given block. - pub fn on_block_finalized(&mut self, hash: &B::Hash, number: NumberFor, protocol: &mut dyn Context) { + pub fn on_block_finalized(&mut self, hash: &B::Hash, number: NumberFor) { + let client = &self.client; let r = self.extra_finality_proofs.on_block_finalized(hash, number, |base, block| { - protocol.client().is_descendent_of(base, block) + client.is_descendent_of(base, block) }); if let Err(err) = r { - warn!(target: "sync", "Error cleaning up pending extra finality proof data requests: {:?}", err); + warn!(target: "sync", "Error cleaning up pending extra finality proof data requests: {:?}", err) } + let client = &self.client; let r = self.extra_justifications.on_block_finalized(hash, number, |base, block| { - protocol.client().is_descendent_of(base, block) + client.is_descendent_of(base, block) }); if let Err(err) = r { @@ -759,9 +829,11 @@ impl ChainSync { } } - /// Called when a block has been queued for import. Updates our internal state for best queued - /// block and then goes through all peers to update our view of their state as well. - fn block_queued(&mut self, hash: &B::Hash, number: NumberFor) { + /// Called when a block has been queued for import. + /// + /// Updates our internal state for best queued block and then goes + /// through all peers to update our view of their state as well. + fn on_block_queued(&mut self, hash: &B::Hash, number: NumberFor) { if number > self.best_queued_number { self.best_queued_number = number; self.best_queued_hash = *hash; @@ -790,43 +862,29 @@ impl ChainSync { } } - /// Signal that `best_header` has been queued for import and update the `ChainSync` state with - /// that information. - pub(crate) fn update_chain_info(&mut self, best_header: &B::Header) { - let hash = best_header.hash(); - self.block_queued(&hash, best_header.number().clone()) - } - /// Call when a node announces a new block. /// - /// If true is returned, then the caller MUST try to import passed header (call `on_block_data`). - /// The network request isn't sent in this case. - /// Both hash and header is passed as an optimization to avoid rehashing the header. - #[must_use] - pub(crate) fn on_block_announce( - &mut self, - protocol: &mut dyn Context, - who: PeerId, - hash: B::Hash, - header: &B::Header, - ) -> bool { + /// If true is returned, then the caller MUST try to import passed + /// header (call `on_block_data`). The network request isn't sent + /// in this case. Both hash and header is passed as an optimization + /// to avoid rehashing the header. + pub fn on_block_announce(&mut self, who: PeerId, hash: B::Hash, header: &B::Header) -> OnBlockAnnounce { let number = *header.number(); debug!(target: "sync", "Received block announcement with number {:?}", number); if number.is_zero() { - warn!(target: "sync", "Ignored invalid block announcement from {}: {}", who, hash); - return false; + warn!(target: "sync", "Ignored genesis block (#0) announcement from {}: {}", who, hash); + return OnBlockAnnounce::Nothing } - let parent_status = block_status(&*protocol.client(), &self.queue_blocks, header.parent_hash().clone()).ok() - .unwrap_or(BlockStatus::Unknown); + let parent_status = self.block_status(header.parent_hash()).ok().unwrap_or(BlockStatus::Unknown); let known_parent = parent_status != BlockStatus::Unknown; let ancient_parent = parent_status == BlockStatus::InChainPruned; - let known = self.is_known(protocol, &hash); + let known = self.is_known(&hash); let peer = if let Some(peer) = self.peers.get_mut(&who) { peer } else { error!(target: "sync", "Called on_block_announce with a bad peer ID"); - return false; + return OnBlockAnnounce::Nothing }; while peer.recently_announced.len() >= ANNOUNCE_HISTORY_SIZE { peer.recently_announced.pop_front(); @@ -838,7 +896,7 @@ impl ChainSync { peer.best_hash = hash; } if let PeerSyncState::AncestorSearch(_, _) = peer.state { - return false; + return OnBlockAnnounce::Nothing } // We assume that the announced block is the latest they have seen, and so our common number // is either one further ahead or it's the one they just announced, if we know about it. @@ -851,260 +909,284 @@ impl ChainSync { // known block case if known || self.is_already_downloading(&hash) { trace!(target: "sync", "Known block announce from {}: {}", who, hash); - return false; + return OnBlockAnnounce::Nothing } // stale block case let requires_additional_data = !self.role.is_light(); if number <= self.best_queued_number { if !(known_parent || self.is_already_downloading(header.parent_hash())) { - if protocol.client().block_status(&BlockId::Number(*header.number())) - .unwrap_or(BlockStatus::Unknown) == BlockStatus::InChainPruned - { + let block_status = self.client.block_status(&BlockId::Number(*header.number())) + .unwrap_or(BlockStatus::Unknown); + if block_status == BlockStatus::InChainPruned { trace!( target: "sync", - "Ignored unknown ancient block announced from {}: {} {:?}", - who, hash, header + "Ignored unknown ancient block announced from {}: {} {:?}", who, hash, header ); - return false; + return OnBlockAnnounce::Nothing } - trace!( target: "sync", - "Considering new unknown stale block announced from {}: {} {:?}", - who, hash, header + "Considering new unknown stale block announced from {}: {} {:?}", who, hash, header ); - let request = self.download_unknown_stale(&who, &hash); - match request { - Some(request) => if requires_additional_data { - protocol.send_block_request(who, request); - return false; + if let Some(request) = self.download_unknown_stale(&who, &hash) { + if requires_additional_data { + return OnBlockAnnounce::Request(who, request) } else { - return true; - }, - None => return false, + return OnBlockAnnounce::ImportHeader + } + } else { + return OnBlockAnnounce::Nothing } } else { if ancient_parent { - trace!( - target: "sync", - "Ignored ancient stale block announced from {}: {} {:?}", - who, hash, header - ); - return false; + trace!(target: "sync", "Ignored ancient stale block announced from {}: {} {:?}", who, hash, header); + return OnBlockAnnounce::Nothing } - - let request = self.download_stale(&who, &hash); - match request { - Some(request) => if requires_additional_data { - protocol.send_block_request(who, request); - return false; + if let Some(request) = self.download_stale(&who, &hash) { + if requires_additional_data { + return OnBlockAnnounce::Request(who, request) } else { - return true; - }, - None => return false, + return OnBlockAnnounce::ImportHeader + } + } else { + return OnBlockAnnounce::Nothing } } } if ancient_parent { trace!(target: "sync", "Ignored ancient block announced from {}: {} {:?}", who, hash, header); - return false; + return OnBlockAnnounce::Nothing } trace!(target: "sync", "Considering new block announced from {}: {} {:?}", who, hash, header); + let (range, request) = match self.select_new_blocks(who.clone()) { Some((range, request)) => (range, request), - None => return false, + None => return OnBlockAnnounce::Nothing }; - let is_required_data_available = - !requires_additional_data && - range.end - range.start == One::one() && - range.start == *header.number(); - if !is_required_data_available { - protocol.send_block_request(who, request); - return false; - } - true - } + let is_required_data_available = !requires_additional_data + && range.end - range.start == One::one() + && range.start == *header.number(); - /// Convenience function to iterate through all peers and see if there are any that we are - /// downloading this hash from. - fn is_already_downloading(&self, hash: &B::Hash) -> bool { - self.peers.iter().any(|(_, p)| p.state == PeerSyncState::DownloadingStale(*hash)) - } + if !is_required_data_available { + return OnBlockAnnounce::Request(who, request) + } - /// Returns true if the block with given hash exists in the import queue with known status or is - /// already imported. - fn is_known(&self, protocol: &mut dyn Context, hash: &B::Hash) -> bool { - block_status(&*protocol.client(), &self.queue_blocks, *hash).ok().map_or(false, |s| s != BlockStatus::Unknown) + OnBlockAnnounce::ImportHeader } /// Call when a peer has disconnected. - pub(crate) fn peer_disconnected(&mut self, protocol: &mut dyn Context, who: PeerId) { + pub fn peer_disconnected(&mut self, who: PeerId) { self.blocks.clear_peer_download(&who); self.peers.remove(&who); self.extra_justifications.peer_disconnected(&who); self.extra_finality_proofs.peer_disconnected(&who); - self.maintain_sync(protocol); } /// Restart the sync process. - pub(crate) fn restart( - &mut self, - protocol: &mut dyn Context, - mut peer_info: impl FnMut(&PeerId) -> Option> - ) { + fn restart<'a, F> + (&'a mut self, mut peer_info: F) -> impl Iterator), BadPeer>> + 'a + where F: FnMut(&PeerId) -> Option> + 'a + { self.queue_blocks.clear(); self.best_importing_number = Zero::zero(); self.blocks.clear(); - let info = protocol.client().info(); + let info = self.client.info(); self.best_queued_hash = info.chain.best_hash; self.best_queued_number = info.chain.best_number; debug!(target:"sync", "Restarted with {} ({})", self.best_queued_number, self.best_queued_hash); - let ids: Vec = self.peers.drain().map(|(id, _)| id).collect(); - for id in ids { - if let Some(info) = peer_info(&id) { - self.new_peer(protocol, id, info); + let old_peers = std::mem::replace(&mut self.peers, HashMap::new()); + old_peers.into_iter().filter_map(move |(id, _)| { + let info = peer_info(&id)?; + match self.new_peer(id.clone(), info) { + Ok(None) => None, + Ok(Some(x)) => Some(Ok((id, x))), + Err(e) => Some(Err(e)) } - } + }) } - // Download old block with known parent. - fn download_stale( - &mut self, - who: &PeerId, - hash: &B::Hash, - ) -> Option> { + /// Download old block with known parent. + fn download_stale(&mut self, who: &PeerId, hash: &B::Hash) -> Option> { let peer = self.peers.get_mut(who)?; - match peer.state { - PeerSyncState::Available => { - peer.state = PeerSyncState::DownloadingStale(*hash); - Some(message::generic::BlockRequest { - id: 0, - fields: self.required_block_attributes.clone(), - from: message::FromBlock::Hash(*hash), - to: None, - direction: message::Direction::Ascending, - max: Some(1), - }) - }, - _ => None, + if !peer.state.is_available() { + return None } + peer.state = PeerSyncState::DownloadingStale(*hash); + Some(message::generic::BlockRequest { + id: 0, + fields: self.required_block_attributes.clone(), + from: message::FromBlock::Hash(*hash), + to: None, + direction: message::Direction::Ascending, + max: Some(1), + }) } - // Download old block with unknown parent. - fn download_unknown_stale( - &mut self, - who: &PeerId, - hash: &B::Hash, - ) -> Option> { + /// Download old block with unknown parent. + fn download_unknown_stale(&mut self, who: &PeerId, hash: &B::Hash) -> Option> { let peer = self.peers.get_mut(who)?; - match peer.state { - PeerSyncState::Available => { - peer.state = PeerSyncState::DownloadingStale(*hash); - Some(message::generic::BlockRequest { - id: 0, - fields: self.required_block_attributes.clone(), - from: message::FromBlock::Hash(*hash), - to: None, - direction: message::Direction::Descending, - max: Some(MAX_UNKNOWN_FORK_DOWNLOAD_LEN), - }) - }, - _ => None, - } - } - - // Issue a request for a peer to download new blocks, if any are available. - fn download_new(&mut self, protocol: &mut dyn Context, who: PeerId) { - if let Some((_, request)) = self.select_new_blocks(who.clone()) { - protocol.send_block_request(who, request); + if !peer.state.is_available() { + return None } + peer.state = PeerSyncState::DownloadingStale(*hash); + Some(message::generic::BlockRequest { + id: 0, + fields: self.required_block_attributes.clone(), + from: message::FromBlock::Hash(*hash), + to: None, + direction: message::Direction::Descending, + max: Some(MAX_UNKNOWN_FORK_DOWNLOAD_LEN), + }) } - // Select a range of NEW blocks to download from peer. - fn select_new_blocks(&mut self, who: PeerId) -> Option<(Range>, message::BlockRequest)> { + /// Select a range of new blocks to download from the given peer. + fn select_new_blocks(&mut self, who: PeerId) -> Option<(Range>, BlockRequest)> { // when there are too many blocks in the queue => do not try to download new blocks if self.queue_blocks.len() > MAX_IMPORTING_BLOCKS { trace!(target: "sync", "Too many blocks in the queue."); - return None; + return None } let peer = self.peers.get_mut(&who)?; - match peer.state { - PeerSyncState::Available => { - trace!( - target: "sync", - "Considering new block download from {}, common block is {}, best is {:?}", - who, - peer.common_number, - peer.best_number, - ); - let range = self.blocks.needed_blocks( - who.clone(), - MAX_BLOCKS_TO_REQUEST, - peer.best_number, - peer.common_number - ); - match range { - Some(range) => { - trace!(target: "sync", "Requesting blocks from {}, ({} to {})", who, range.start, range.end); - let from = message::FromBlock::Number(range.start); - let max = Some((range.end - range.start).saturated_into::()); - peer.state = PeerSyncState::DownloadingNew(range.start); - Some(( - range, - message::generic::BlockRequest { - id: 0, - fields: self.required_block_attributes.clone(), - from, - to: None, - direction: message::Direction::Ascending, - max, - }, - )) - }, - None => { - trace!(target: "sync", "Nothing to request"); - None - }, - } - }, - _ => { - trace!(target: "sync", "Peer {} is busy", who); - None - }, + + if !peer.state.is_available() { + trace!(target: "sync", "Peer {} is busy", who); + return None } + + trace!( + target: "sync", + "Considering new block download from {}, common block is {}, best is {:?}", + who, + peer.common_number, + peer.best_number + ); + + if let Some((range, req)) = peer_block_request(&who, peer, &mut self.blocks, &self.required_block_attributes) { + trace!(target: "sync", "Requesting blocks from {}, ({} to {})", who, range.start, range.end); + peer.state = PeerSyncState::DownloadingNew(range.start); + Some((range, req)) + } else { + trace!(target: "sync", "Nothing to request from {}", who); + None + } + } + + /// What is the status of the block corresponding to the given hash? + fn block_status(&self, hash: &B::Hash) -> Result { + if self.queue_blocks.contains(hash) { + return Ok(BlockStatus::Queued) + } + self.client.block_status(&BlockId::Hash(*hash)) + } + + /// Is the block corresponding to the given hash known? + fn is_known(&self, hash: &B::Hash) -> bool { + self.block_status(hash).ok().map_or(false, |s| s != BlockStatus::Unknown) + } + + /// Is any peer downloading the given hash? + fn is_already_downloading(&self, hash: &B::Hash) -> bool { + self.peers.iter().any(|(_, p)| p.state == PeerSyncState::DownloadingStale(*hash)) } +} + +/// Request the ancestry for a block. Sends a request for header and justification for the given +/// block number. Used during ancestry search. +fn ancestry_request(block: NumberFor) -> BlockRequest { + message::generic::BlockRequest { + id: 0, + fields: BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION, + from: message::FromBlock::Number(block), + to: None, + direction: message::Direction::Ascending, + max: Some(1) + } +} - /// Request the ancestry for a block. Sends a request for header and justification for the given - /// block number. Used during ancestry search. - fn request_ancestry(protocol: &mut dyn Context, who: PeerId, block: NumberFor) { - trace!(target: "sync", "Requesting ancestry block #{} from {}", block, who); +/// The ancestor search state expresses which algorithm, and its stateful parameters, we are using to +/// try to find an ancestor block +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum AncestorSearchState { + /// Use exponential backoff to find an ancestor, then switch to binary search. + /// We keep track of the exponent. + ExponentialBackoff(NumberFor), + /// Using binary search to find the best ancestor. + /// We keep track of left and right bounds. + BinarySearch(NumberFor, NumberFor), +} + +/// This function handles the ancestor search strategy used. The goal is to find a common point +/// that both our chains agree on that is as close to the tip as possible. +/// The way this works is we first have an exponential backoff strategy, where we try to step +/// forward until we find a block hash mismatch. The size of the step doubles each step we take. +/// +/// When we've found a block hash mismatch we then fall back to a binary search between the two +/// last known points to find the common block closest to the tip. +fn handle_ancestor_search_state( + state: &AncestorSearchState, + curr_block_num: NumberFor, + block_hash_match: bool +) -> Option<(AncestorSearchState, NumberFor)> { + let two = >::one() + >::one(); + match state { + AncestorSearchState::ExponentialBackoff(next_distance_to_tip) => { + let next_distance_to_tip = *next_distance_to_tip; + if block_hash_match && next_distance_to_tip == One::one() { + // We found the ancestor in the first step so there is no need to execute binary search. + return None; + } + if block_hash_match { + let left = curr_block_num; + let right = left + next_distance_to_tip / two; + let middle = left + (right - left) / two; + Some((AncestorSearchState::BinarySearch(left, right), middle)) + } else { + let next_block_num = curr_block_num.checked_sub(&next_distance_to_tip) + .unwrap_or_else(Zero::zero); + let next_distance_to_tip = next_distance_to_tip * two; + Some((AncestorSearchState::ExponentialBackoff(next_distance_to_tip), next_block_num)) + } + } + AncestorSearchState::BinarySearch(mut left, mut right) => { + if left >= curr_block_num { + return None; + } + if block_hash_match { + left = curr_block_num; + } else { + right = curr_block_num; + } + assert!(right >= left); + let middle = left + (right - left) / two; + Some((AncestorSearchState::BinarySearch(left, right), middle)) + } + } +} + +/// Get a new block request for the peer if any. +fn peer_block_request( + id: &PeerId, + peer: &PeerSync, + blocks: &mut BlockCollection, + attrs: &message::BlockAttributes, +) -> Option<(Range>, BlockRequest)> { + if let Some(range) = blocks.needed_blocks(id.clone(), MAX_BLOCKS_TO_REQUEST, peer.best_number, peer.common_number) { let request = message::generic::BlockRequest { id: 0, - fields: message::BlockAttributes::HEADER | message::BlockAttributes::JUSTIFICATION, - from: message::FromBlock::Number(block), + fields: attrs.clone(), + from: message::FromBlock::Number(range.start), to: None, direction: message::Direction::Ascending, - max: Some(1), + max: Some((range.end - range.start).saturated_into::()) }; - protocol.send_block_request(who, request); + Some((range, request)) + } else { + None } } -/// Returns the BlockStatus for given block hash, looking first in the import queue and then in the -/// provided chain. -fn block_status( - chain: &dyn crate::chain::Client, - queue_blocks: &HashSet, - hash: B::Hash) -> Result -{ - if queue_blocks.contains(&hash) { - return Ok(BlockStatus::Queued); - } - - chain.block_status(&BlockId::Hash(hash)) -} diff --git a/core/network/src/service.rs b/core/network/src/service.rs index 83ac5c977884c52f265cf68566d18c864b18269d..5841336b446dbeccd59f88762089df5691e27b2c 100644 --- a/core/network/src/service.rs +++ b/core/network/src/service.rs @@ -14,45 +14,39 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use std::collections::HashMap; -use std::{fs, io, path::Path}; -use std::sync::Arc; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::time::Duration; - -use log::{warn, debug, error, info}; -use libp2p::core::swarm::NetworkBehaviour; -use libp2p::core::{nodes::Substream, transport::boxed::Boxed, muxing::StreamMuxerBox}; -use futures::{prelude::*, sync::oneshot, sync::mpsc}; -use parking_lot::{Mutex, RwLock}; -use crate::custom_proto::{CustomProto, CustomProtoOut}; -use crate::{behaviour::Behaviour, parse_str_addr, ProtocolId}; -use crate::{NetworkState, NetworkStateNotConnectedPeer, NetworkStatePeer}; -use crate::{transport, config::NodeKeyConfig, config::NonReservedPeerMode, config::NetworkConfiguration}; +//! Main entry point of the substrate-network crate. +//! +//! There are two main structs in this module: [`NetworkWorker`] and [`NetworkService`]. +//! The [`NetworkWorker`] *is* the network and implements the `Future` trait. It must be polled in +//! order fo the network to advance. +//! The [`NetworkService`] is merely a shared version of the [`NetworkWorker`]. You can obtain an +//! `Arc` by calling [`NetworkWorker::service`]. +//! +//! The methods of the [`NetworkService`] are implemented by sending a message over a channel, +//! which is then processed by [`NetworkWorker::poll`]. + +use std::{collections::HashMap, fs, marker::PhantomData, io, path::Path}; +use std::sync::{Arc, atomic::{AtomicBool, AtomicUsize, Ordering}}; + +use consensus::import_queue::{ImportQueue, Link}; +use consensus::import_queue::{BlockImportResult, BlockImportError}; +use futures::{prelude::*, sync::mpsc}; +use log::{warn, error, info}; +use libp2p::core::{swarm::NetworkBehaviour, transport::boxed::Boxed, muxing::StreamMuxerBox}; +use libp2p::{PeerId, Multiaddr, multihash::Multihash}; use peerset::PeersetHandle; -use consensus::import_queue::{ImportQueue, Link, SharedFinalityProofRequestBuilder}; use runtime_primitives::{traits::{Block as BlockT, NumberFor}, ConsensusEngineId}; -use crate::AlwaysBadChecker; -use crate::chain::FinalityProofProvider; -use crate::protocol::consensus_gossip::{ConsensusGossip, MessageRecipient as GossipMessageRecipient}; -use crate::protocol::message::Message; -use crate::protocol::on_demand::RequestData; -use crate::protocol::{self, Context, CustomMessageOutcome, Protocol, ConnectedPeer}; -use crate::protocol::{ProtocolStatus, PeerInfo, NetworkOut}; -use crate::config::Params; +use crate::{behaviour::{Behaviour, BehaviourOut}, config::parse_str_addr}; +use crate::{NetworkState, NetworkStateNotConnectedPeer, NetworkStatePeer}; +use crate::{transport, config::NodeKeyConfig, config::NonReservedPeerMode}; +use crate::config::{Params, TransportConfig}; use crate::error::Error; +use crate::protocol::{self, Protocol, Context, CustomMessageOutcome, PeerInfo}; +use crate::protocol::consensus_gossip::{ConsensusGossip, MessageRecipient as GossipMessageRecipient}; +use crate::protocol::{event::Event, on_demand::{AlwaysBadChecker, RequestData}}; use crate::protocol::specialization::NetworkSpecialization; - -/// Interval at which we send status updates on the status stream. -const STATUS_INTERVAL: Duration = Duration::from_millis(5000); -/// Interval at which we update the `peers` field on the main thread. -const CONNECTED_PEERS_INTERVAL: Duration = Duration::from_millis(500); - -pub use libp2p::PeerId; - -/// Type that represents fetch completion future. -pub type FetchFuture = oneshot::Receiver>; +use crate::protocol::sync::SyncState; /// Minimum Requirements for a Hash within Networking pub trait ExHashT: @@ -89,26 +83,23 @@ impl ReportHandle { } /// Substrate network service. Handles network IO and manages connectivity. -pub struct NetworkService> { - /// Sinks to propagate status updates. - status_sinks: Arc>>>>, - /// Are we connected to any peer? - is_offline: Arc, +pub struct NetworkService, H: ExHashT> { + /// Number of peers we're connected to. + num_connected: Arc, /// Are we actively catching up with the chain? is_major_syncing: Arc, - /// Peers whom we are connected with. - peers: Arc>>>, - /// Channel for networking messages processed by the background thread. - network_chan: mpsc::UnboundedSender>, - /// Network service - network: Arc>>, + /// Local copy of the `PeerId` of the local node. + local_peer_id: PeerId, /// Bandwidth logging system. Can be queried to know the average bandwidth consumed. bandwidth: Arc, /// Peerset manager (PSM); manages the reputation of nodes and indicates the network which /// nodes it should be connected to or not. peerset: PeersetHandle, - /// Protocol sender - protocol_sender: mpsc::UnboundedSender>, + /// Channel that sends messages to the actual worker. + to_worker: mpsc::UnboundedSender>, + /// Marker to pin the `H` generic. Serves no purpose except to not break backwards + /// compatibility. + _marker: PhantomData, } impl, H: ExHashT> NetworkWorker { @@ -120,183 +111,193 @@ impl, H: ExHashT> NetworkWorker pub fn new( params: Params, ) -> Result, Error> { - let (network_chan, network_port) = mpsc::unbounded(); - let (protocol_sender, protocol_rx) = mpsc::unbounded(); - let status_sinks = Arc::new(Mutex::new(Vec::new())); + let (to_worker, from_worker) = mpsc::unbounded(); + + if let Some(ref path) = params.network_config.net_config_path { + fs::create_dir_all(Path::new(path))?; + } + + // List of multiaddresses that we know in the network. + let mut known_addresses = Vec::new(); + let mut bootnodes = Vec::new(); + let mut reserved_nodes = Vec::new(); + + // Process the bootnodes. + for bootnode in params.network_config.boot_nodes.iter() { + match parse_str_addr(bootnode) { + Ok((peer_id, addr)) => { + bootnodes.push(peer_id.clone()); + known_addresses.push((peer_id, addr)); + }, + Err(_) => warn!(target: "sub-libp2p", "Not a valid bootnode address: {}", bootnode), + } + } + + // Initialize the reserved peers. + for reserved in params.network_config.reserved_nodes.iter() { + if let Ok((peer_id, addr)) = parse_str_addr(reserved) { + reserved_nodes.push(peer_id.clone()); + known_addresses.push((peer_id, addr)); + } else { + warn!(target: "sub-libp2p", "Not a valid reserved node address: {}", reserved); + } + } + + let peerset_config = peerset::PeersetConfig { + in_peers: params.network_config.in_peers, + out_peers: params.network_config.out_peers, + bootnodes, + reserved_only: params.network_config.non_reserved_mode == NonReservedPeerMode::Deny, + reserved_nodes, + }; - // Start in off-line mode, since we're not connected to any nodes yet. - let is_offline = Arc::new(AtomicBool::new(true)); + // Private and public keys configuration. + if let NodeKeyConfig::Secp256k1(_) = params.network_config.node_key { + warn!(target: "sub-libp2p", "Secp256k1 keys are deprecated in favour of ed25519"); + } + let local_identity = params.network_config.node_key.clone().into_keypair()?; + let local_public = local_identity.public(); + let local_peer_id = local_public.clone().into_peer_id(); + info!(target: "sub-libp2p", "Local node identity is: {}", local_peer_id.to_base58()); + + let num_connected = Arc::new(AtomicUsize::new(0)); let is_major_syncing = Arc::new(AtomicBool::new(false)); - let peers: Arc>>> = Arc::new(Default::default()); - let protocol = Protocol::new( + let (protocol, peerset_handle) = Protocol::new( protocol::ProtocolConfig { roles: params.roles }, params.chain, params.on_demand.as_ref().map(|od| od.checker().clone()) .unwrap_or(Arc::new(AlwaysBadChecker)), params.specialization, + params.transaction_pool, + params.finality_proof_provider, + params.finality_proof_request_builder, + params.protocol_id, + peerset_config, )?; - let versions: Vec<_> = ((protocol::MIN_VERSION as u8)..=(protocol::CURRENT_VERSION as u8)).collect(); - // Start the main service. - let (network, bandwidth, peerset) = - match start_service::(params.network_config, params.protocol_id, &versions) { - Ok((network, bandwidth, peerset)) => (Arc::new(Mutex::new(network)), bandwidth, peerset), - Err(err) => { - warn!("Error starting network: {}", err); - return Err(err.into()) - }, + // Build the swarm. + let (mut swarm, bandwidth) = { + let user_agent = format!( + "{} ({})", + params.network_config.client_version, + params.network_config.node_name + ); + let behaviour = Behaviour::new( + protocol, + user_agent, + local_public, + known_addresses, + match params.network_config.transport { + TransportConfig::MemoryOnly => false, + TransportConfig::Normal { enable_mdns, .. } => enable_mdns, + } + ); + let (transport, bandwidth) = { + let (config_mem, config_wasm) = match params.network_config.transport { + TransportConfig::MemoryOnly => (true, None), + TransportConfig::Normal { wasm_external_transport, .. } => + (false, wasm_external_transport) + }; + transport::build_transport(local_identity, config_mem, config_wasm) }; + (Swarm::::new(transport, behaviour, local_peer_id.clone()), bandwidth) + }; + + // Listen on multiaddresses. + for addr in ¶ms.network_config.listen_addresses { + if let Err(err) = Swarm::::listen_on(&mut swarm, addr.clone()) { + warn!(target: "sub-libp2p", "Can't listen on {} because: {:?}", addr, err) + } + } + + // Add external addresses. + for addr in ¶ms.network_config.public_addresses { + Swarm::::add_external_address(&mut swarm, addr.clone()); + } let service = Arc::new(NetworkService { - status_sinks: status_sinks.clone(), bandwidth, - is_offline: is_offline.clone(), + num_connected: num_connected.clone(), is_major_syncing: is_major_syncing.clone(), - network_chan, - peers: peers.clone(), - peerset: peerset.clone(), - network: network.clone(), - protocol_sender: protocol_sender.clone(), + peerset: peerset_handle, + local_peer_id, + to_worker: to_worker.clone(), + _marker: PhantomData, }); Ok(NetworkWorker { - is_offline, + num_connected, is_major_syncing, - network_service: network, - peerset, + network_service: swarm, service, - protocol, - peers, import_queue: params.import_queue, - transaction_pool: params.transaction_pool, - finality_proof_provider: params.finality_proof_provider, - network_port, - protocol_rx, - status_sinks, + from_worker, on_demand_in: params.on_demand.and_then(|od| od.extract_receiver()), - status_interval: tokio_timer::Interval::new_interval(STATUS_INTERVAL), - connected_peers_interval: tokio_timer::Interval::new_interval(CONNECTED_PEERS_INTERVAL), }) } - /// Return a `NetworkService` that can be shared through the code base and can be used to - /// manipulate the worker. - pub fn service(&self) -> &Arc> { - &self.service - } -} - -impl> NetworkService { /// Returns the downloaded bytes per second averaged over the past few seconds. pub fn average_download_per_sec(&self) -> u64 { - self.bandwidth.average_download_per_sec() + self.service.bandwidth.average_download_per_sec() } /// Returns the uploaded bytes per second averaged over the past few seconds. pub fn average_upload_per_sec(&self) -> u64 { - self.bandwidth.average_upload_per_sec() + self.service.bandwidth.average_upload_per_sec() } - /// Returns the network identity of the node. - pub fn local_peer_id(&self) -> PeerId { - Swarm::::local_peer_id(&*self.network.lock()).clone() + /// Returns the number of peers we're connected to. + pub fn num_connected_peers(&self) -> usize { + self.network_service.user_protocol().num_connected_peers() } - /// Called when a new block is imported by the client. - pub fn on_block_imported(&self, hash: B::Hash, header: B::Header) { - let _ = self - .protocol_sender - .unbounded_send(ProtocolMsg::BlockImported(hash, header)); + /// Returns the number of peers we're connected to and that are being queried. + pub fn num_active_peers(&self) -> usize { + self.network_service.user_protocol().num_active_peers() } - /// Called when a new block is finalized by the client. - pub fn on_block_finalized(&self, hash: B::Hash, header: B::Header) { - let _ = self - .protocol_sender - .unbounded_send(ProtocolMsg::BlockFinalized(hash, header)); + /// Current global sync state. + pub fn sync_state(&self) -> SyncState { + self.network_service.user_protocol().sync_state() } - /// Called when new transactons are imported by the client. - pub fn trigger_repropagate(&self) { - let _ = self.protocol_sender.unbounded_send(ProtocolMsg::PropagateExtrinsics); + /// Target sync block number. + pub fn best_seen_block(&self) -> Option> { + self.network_service.user_protocol().best_seen_block() } - /// Make sure an important block is propagated to peers. - /// - /// In chain-based consensus, we often need to make sure non-best forks are - /// at least temporarily synced. - pub fn announce_block(&self, hash: B::Hash) { - let _ = self.protocol_sender.unbounded_send(ProtocolMsg::AnnounceBlock(hash)); + /// Number of peers participating in syncing. + pub fn num_sync_peers(&self) -> u32 { + self.network_service.user_protocol().num_sync_peers() } - /// Send a consensus message through the gossip - pub fn gossip_consensus_message( - &self, - topic: B::Hash, - engine_id: ConsensusEngineId, - message: Vec, - recipient: GossipMessageRecipient, - ) { - let _ = self - .protocol_sender - .unbounded_send(ProtocolMsg::GossipConsensusMessage( - topic, engine_id, message, recipient, - )); + /// Adds an address for a node. + pub fn add_known_address(&mut self, peer_id: PeerId, addr: Multiaddr) { + self.network_service.add_known_address(peer_id, addr); } - /// Report a given peer as either beneficial (+) or costly (-) according to the - /// given scalar. - pub fn report_peer(&self, who: PeerId, cost_benefit: i32) { - self.peerset.report_peer(who, cost_benefit); - } - - /// Send a message to the given peer. Has no effect if we're not connected to this peer. - /// - /// This method is extremely poor in terms of API and should be eventually removed. - pub fn disconnect_peer(&self, who: PeerId) { - let _ = self.network_chan.unbounded_send(NetworkMsg::DisconnectPeer(who)); - } - - /// Send a message to the given peer. Has no effect if we're not connected to this peer. - /// - /// This method is extremely poor in terms of API and should be eventually removed. - pub fn send_request(&self, who: PeerId, message: Message) { - let _ = self.network_chan.unbounded_send(NetworkMsg::Outgoing(who, message)); - } - - /// Execute a closure with the chain-specific network specialization. - pub fn with_spec(&self, f: F) - where F: FnOnce(&mut S, &mut dyn Context) + Send + 'static - { - let _ = self - .protocol_sender - .unbounded_send(ProtocolMsg::ExecuteWithSpec(Box::new(f))); - } - - /// Execute a closure with the consensus gossip. - pub fn with_gossip(&self, f: F) - where F: FnOnce(&mut ConsensusGossip, &mut dyn Context) + Send + 'static - { - let _ = self - .protocol_sender - .unbounded_send(ProtocolMsg::ExecuteWithGossip(Box::new(f))); + /// Return a `NetworkService` that can be shared through the code base and can be used to + /// manipulate the worker. + pub fn service(&self) -> &Arc> { + &self.service } - /// Are we in the process of downloading the chain? - pub fn is_major_syncing(&self) -> bool { - self.is_major_syncing.load(Ordering::Relaxed) + /// You must call this when a new block is imported by the client. + pub fn on_block_imported(&mut self, hash: B::Hash, header: B::Header) { + self.network_service.user_protocol_mut().on_block_imported(hash, &header); } - /// Get sync status - pub fn status(&self) -> mpsc::UnboundedReceiver> { - let (sink, stream) = mpsc::unbounded(); - self.status_sinks.lock().push(sink); - stream + /// You must call this when a new block is finalized by the client. + pub fn on_block_finalized(&mut self, hash: B::Hash, header: B::Header) { + self.network_service.user_protocol_mut().on_block_finalized(hash, &header); } /// Get network state. - pub fn network_state(&self) -> NetworkState { - let mut swarm = self.network.lock(); + /// + /// **Note**: Use this only for debugging. This API is unstable. There are warnings literaly + /// everywhere about this. Please don't use this function to retreive actual information. + pub fn network_state(&mut self) -> NetworkState { + let swarm = &mut self.network_service; let open = swarm.user_protocol().open_peers().cloned().collect::>(); let connected_peers = { @@ -315,7 +316,8 @@ impl> NetworkService { Some((peer_id.to_base58(), NetworkStatePeer { endpoint, - version_string: swarm.node(peer_id).and_then(|i| i.client_version().map(|s| s.to_owned())).clone(), + version_string: swarm.node(peer_id) + .and_then(|i| i.client_version().map(|s| s.to_owned())).clone(), latest_ping_time: swarm.node(peer_id).and_then(|i| i.latest_ping()), enabled: swarm.user_protocol().is_enabled(&peer_id), open: swarm.user_protocol().is_open(&peer_id), @@ -330,7 +332,8 @@ impl> NetworkService { .cloned().collect::>(); list.into_iter().map(move |peer_id| { (peer_id.to_base58(), NetworkStateNotConnectedPeer { - version_string: swarm.node(&peer_id).and_then(|i| i.client_version().map(|s| s.to_owned())).clone(), + version_string: swarm.node(&peer_id) + .and_then(|i| i.client_version().map(|s| s.to_owned())).clone(), latest_ping_time: swarm.node(&peer_id).and_then(|i| i.latest_ping()), known_addresses: NetworkBehaviour::addresses_of_peer(&mut **swarm, &peer_id) .into_iter().collect(), @@ -339,11 +342,11 @@ impl> NetworkService { }; NetworkState { - peer_id: Swarm::::local_peer_id(&swarm).to_base58(), - listened_addresses: Swarm::::listeners(&swarm).cloned().collect(), - external_addresses: Swarm::::external_addresses(&swarm).cloned().collect(), - average_download_per_sec: self.bandwidth.average_download_per_sec(), - average_upload_per_sec: self.bandwidth.average_upload_per_sec(), + peer_id: Swarm::::local_peer_id(&swarm).to_base58(), + listened_addresses: Swarm::::listeners(&swarm).cloned().collect(), + external_addresses: Swarm::::external_addresses(&swarm).cloned().collect(), + average_download_per_sec: self.service.bandwidth.average_download_per_sec(), + average_upload_per_sec: self.service.bandwidth.average_upload_per_sec(), connected_peers, not_connected_peers, peerset: swarm.user_protocol_mut().peerset_debug_info(), @@ -351,160 +354,186 @@ impl> NetworkService { } /// Get currently connected peers. - /// - /// > **Warning**: This method can return outdated information and should only ever be used - /// > when obtaining outdated information is acceptable. - pub fn peers_debug_info(&self) -> Vec<(PeerId, PeerInfo)> { - let peers = (*self.peers.read()).clone(); - peers.into_iter().map(|(idx, connected)| (idx, connected.peer_info)).collect() + pub fn peers_debug_info(&mut self) -> Vec<(PeerId, PeerInfo)> { + self.network_service.user_protocol_mut() + .peers_info() + .map(|(id, info)| (id.clone(), info.clone())) + .collect() } } -impl> ::consensus::SyncOracle for NetworkService { - fn is_major_syncing(&self) -> bool { - self.is_major_syncing() +impl, H: ExHashT> NetworkService { + /// Returns the network identity of the node. + pub fn local_peer_id(&self) -> PeerId { + self.local_peer_id.clone() } - fn is_offline(&self) -> bool { - self.is_offline.load(Ordering::Relaxed) + /// You must call this when new transactons are imported by the transaction pool. + /// + /// The latest transactions will be fetched from the `TransactionPool` that was passed at + /// initialization as part of the configuration. + pub fn trigger_repropagate(&self) { + let _ = self.to_worker.unbounded_send(ServerToWorkerMsg::PropagateExtrinsics); } -} -/// Trait for managing network -pub trait ManageNetwork { - /// Set to allow unreserved peers to connect - fn accept_unreserved_peers(&self); - /// Set to deny unreserved peers to connect - fn deny_unreserved_peers(&self); - /// Remove reservation for the peer - fn remove_reserved_peer(&self, peer: PeerId); - /// Add reserved peer - fn add_reserved_peer(&self, peer: String) -> Result<(), String>; -} + /// Make sure an important block is propagated to peers. + /// + /// In chain-based consensus, we often need to make sure non-best forks are + /// at least temporarily synced. This function forces such an announcement. + pub fn announce_block(&self, hash: B::Hash) { + let _ = self.to_worker.unbounded_send(ServerToWorkerMsg::AnnounceBlock(hash)); + } + + /// Send a consensus message through the gossip + pub fn gossip_consensus_message( + &self, + topic: B::Hash, + engine_id: ConsensusEngineId, + message: Vec, + recipient: GossipMessageRecipient, + ) { + let _ = self + .to_worker + .unbounded_send(ServerToWorkerMsg::GossipConsensusMessage( + topic, engine_id, message, recipient, + )); + } + + /// Report a given peer as either beneficial (+) or costly (-) according to the + /// given scalar. + pub fn report_peer(&self, who: PeerId, cost_benefit: i32) { + self.peerset.report_peer(who, cost_benefit); + } + + /// Request a justification for the given block from the network. + /// + /// On success, the justification will be passed to the import queue that was part at + /// initialization as part of the configuration. + pub fn request_justification(&self, hash: &B::Hash, number: NumberFor) { + let _ = self + .to_worker + .unbounded_send(ServerToWorkerMsg::RequestJustification(hash.clone(), number)); + } + + /// Execute a closure with the chain-specific network specialization. + pub fn with_spec(&self, f: F) + where F: FnOnce(&mut S, &mut dyn Context) + Send + 'static + { + let _ = self + .to_worker + .unbounded_send(ServerToWorkerMsg::ExecuteWithSpec(Box::new(f))); + } + + /// Execute a closure with the consensus gossip. + pub fn with_gossip(&self, f: F) + where F: FnOnce(&mut ConsensusGossip, &mut dyn Context) + Send + 'static + { + let _ = self + .to_worker + .unbounded_send(ServerToWorkerMsg::ExecuteWithGossip(Box::new(f))); + } -impl> ManageNetwork for NetworkService { - fn accept_unreserved_peers(&self) { + /// Are we in the process of downloading the chain? + pub fn is_major_syncing(&self) -> bool { + self.is_major_syncing.load(Ordering::Relaxed) + } + + /// Start getting a value from the DHT. + /// + /// This will generate either a `ValueFound` or a `ValueNotFound` event and pass it to + /// `on_event` on the network specialization. + pub fn get_value(&self, key: &Multihash) { + let _ = self + .to_worker + .unbounded_send(ServerToWorkerMsg::GetValue(key.clone())); + } + + /// Start putting a value in the DHT. + /// + /// This will generate either a `ValuePut` or a `ValuePutFailed` event and pass it to + /// `on_event` on the network specialization. + pub fn put_value(&self, key: Multihash, value: Vec) { + let _ = self + .to_worker + .unbounded_send(ServerToWorkerMsg::PutValue(key, value)); + } + + /// Connect to unreserved peers and allow unreserved peers to connect. + pub fn accept_unreserved_peers(&self) { self.peerset.set_reserved_only(false); } - fn deny_unreserved_peers(&self) { + /// Disconnect from unreserved peers and deny new unreserved peers to connect. + pub fn deny_unreserved_peers(&self) { self.peerset.set_reserved_only(true); } - fn remove_reserved_peer(&self, peer: PeerId) { + /// Removes a `PeerId` from the list of reserved peers. + pub fn remove_reserved_peer(&self, peer: PeerId) { self.peerset.remove_reserved_peer(peer); } - fn add_reserved_peer(&self, peer: String) -> Result<(), String> { + /// Adds a `PeerId` and its address as reserved. + pub fn add_reserved_peer(&self, peer: String) -> Result<(), String> { let (peer_id, addr) = parse_str_addr(&peer).map_err(|e| format!("{:?}", e))?; self.peerset.add_reserved_peer(peer_id.clone()); - self.network.lock().add_known_address(peer_id, addr); + let _ = self + .to_worker + .unbounded_send(ServerToWorkerMsg::AddKnownAddress(peer_id, addr)); Ok(()) } + + /// Returns the number of peers we're connected to. + pub fn num_connected(&self) -> usize { + self.num_connected.load(Ordering::Relaxed) + } } -/// Messages to be handled by Libp2pNetService. -#[derive(Debug)] -pub enum NetworkMsg { - /// Send an outgoing custom message. - Outgoing(PeerId, Message), - /// Disconnect a peer we're connected to, or do nothing if we're not connected. - DisconnectPeer(PeerId), - /// Performs a reputation adjustement on a peer. - ReportPeer(PeerId, i32), - /// Synchronization response. - #[cfg(any(test, feature = "test-helpers"))] - Synchronized, +impl, H: ExHashT> + ::consensus::SyncOracle for NetworkService { + fn is_major_syncing(&self) -> bool { + self.is_major_syncing() + } + + fn is_offline(&self) -> bool { + self.num_connected.load(Ordering::Relaxed) == 0 + } } -/// Messages sent to Protocol from elsewhere inside the system. -pub enum ProtocolMsg> { - /// A batch of blocks has been processed, with or without errors. - BlocksProcessed(Vec, bool), - /// Tell protocol to restart sync. - RestartSync, - /// Tell protocol to propagate extrinsics. +/// Messages sent from the `NetworkService` to the `NetworkWorker`. +/// +/// Each entry corresponds to a method of `NetworkService`. +enum ServerToWorkerMsg> { PropagateExtrinsics, - /// Tell protocol that a block was imported (sent by the import-queue). - BlockImportedSync(B::Hash, NumberFor), - /// Tell protocol to clear all pending justification requests. - ClearJustificationRequests, - /// Tell protocol to request justification for a block. RequestJustification(B::Hash, NumberFor), - /// Inform protocol whether a justification was successfully imported. - JustificationImportResult(B::Hash, NumberFor, bool), - /// Set finality proof request builder. - SetFinalityProofRequestBuilder(SharedFinalityProofRequestBuilder), - /// Tell protocol to request finality proof for a block. - RequestFinalityProof(B::Hash, NumberFor), - /// Inform protocol whether a finality proof was successfully imported. - FinalityProofImportResult((B::Hash, NumberFor), Result<(B::Hash, NumberFor), ()>), - /// Propagate a block to peers. AnnounceBlock(B::Hash), - /// A block has been imported (sent by the client). - BlockImported(B::Hash, B::Header), - /// A block has been finalized (sent by the client). - BlockFinalized(B::Hash, B::Header), - /// Execute a closure with the chain-specific network specialization. - ExecuteWithSpec(Box + Send + 'static>), - /// Execute a closure with the consensus gossip. - ExecuteWithGossip(Box + Send + 'static>), - /// Incoming gossip consensus message. + ExecuteWithSpec(Box) + Send>), + ExecuteWithGossip(Box, &mut dyn Context) + Send>), GossipConsensusMessage(B::Hash, ConsensusEngineId, Vec, GossipMessageRecipient), - /// Tell protocol to perform regular maintenance. - #[cfg(any(test, feature = "test-helpers"))] - Tick, - /// Synchronization request. - #[cfg(any(test, feature = "test-helpers"))] - Synchronize, -} - -/// A task, consisting of a user-provided closure, to be executed on the Protocol thread. -pub trait SpecTask> { - fn call_box(self: Box, spec: &mut S, context: &mut dyn Context); -} - -impl, F: FnOnce(&mut S, &mut dyn Context)> SpecTask for F { - fn call_box(self: Box, spec: &mut S, context: &mut dyn Context) { - (*self)(spec, context) - } -} - -/// A task, consisting of a user-provided closure, to be executed on the Protocol thread. -pub trait GossipTask { - fn call_box(self: Box, gossip: &mut ConsensusGossip, context: &mut dyn Context); + GetValue(Multihash), + PutValue(Multihash, Vec), + AddKnownAddress(PeerId, Multiaddr), } -impl, &mut dyn Context)> GossipTask for F { - fn call_box(self: Box, gossip: &mut ConsensusGossip, context: &mut dyn Context) { - (*self)(gossip, context) - } -} - -/// Future tied to the `Network` service and that must be polled in order for the network to -/// advance. +/// Main network worker. Must be polled in order for the network to advance. +/// +/// You are encouraged to poll this in a separate background thread or task. #[must_use = "The NetworkWorker must be polled in order for the network to work"] pub struct NetworkWorker, H: ExHashT> { - is_offline: Arc, + /// Updated by the `NetworkWorker` and loaded by the `NetworkService`. + num_connected: Arc, + /// Updated by the `NetworkWorker` and loaded by the `NetworkService`. is_major_syncing: Arc, - protocol: Protocol, /// The network service that can be extracted and shared through the codebase. - service: Arc>, - network_service: Arc>>, - peers: Arc>>>, + service: Arc>, + /// The *actual* network. + network_service: Swarm, + /// The import queue that was passed as initialization. import_queue: Box>, - transaction_pool: Arc>, - finality_proof_provider: Option>>, - network_port: mpsc::UnboundedReceiver>, - protocol_rx: mpsc::UnboundedReceiver>, - status_sinks: Arc>>>>, - peerset: PeersetHandle, + /// Messages from the `NetworkService` and that must be processed. + from_worker: mpsc::UnboundedReceiver>, + /// Receiver for queries from the on-demand that must be processed. on_demand_in: Option>>, - - /// Interval at which we send status updates on the `status_sinks`. - status_interval: tokio_timer::Interval, - /// Interval at which we update the `connected_peers` Arc. - connected_peers_interval: tokio_timer::Interval, } impl, H: ExHashT> Future for NetworkWorker { @@ -512,219 +541,67 @@ impl, H: ExHashT> Future for Ne type Error = io::Error; fn poll(&mut self) -> Poll { - // Implementation of `protocol::NetworkOut` trait using the available local variables. - struct Context<'a, B: BlockT>(&'a mut Swarm, &'a PeersetHandle); - impl<'a, B: BlockT> NetworkOut for Context<'a, B> { - fn report_peer(&mut self, who: PeerId, reputation: i32) { - self.1.report_peer(who, reputation) - } - fn disconnect_peer(&mut self, who: PeerId) { - self.0.user_protocol_mut().disconnect_peer(&who) - } - fn send_message(&mut self, who: PeerId, message: Message) { - self.0.user_protocol_mut().send_packet(&who, message) - } - } - - // Implementation of `import_queue::Link` trait using the available local variables. - struct NetworkLink<'a, B: BlockT, S: NetworkSpecialization, H: ExHashT> { - protocol: &'a mut Protocol, - context: Context<'a, B>, - } - impl<'a, B: BlockT, S: NetworkSpecialization, H: ExHashT> Link for NetworkLink<'a, B, S, H> { - fn block_imported(&mut self, hash: &B::Hash, number: NumberFor) { - self.protocol.block_imported(&hash, number) - } - fn blocks_processed(&mut self, hashes: Vec, has_error: bool) { - self.protocol.blocks_processed(&mut self.context, hashes, has_error) - } - fn justification_imported(&mut self, who: PeerId, hash: &B::Hash, number: NumberFor, success: bool) { - self.protocol.justification_import_result(hash.clone(), number, success); - if !success { - info!("Invalid justification provided by {} for #{}", who, hash); - self.context.0.user_protocol_mut().disconnect_peer(&who); - self.context.1.report_peer(who, i32::min_value()); - } - } - fn clear_justification_requests(&mut self) { - self.protocol.clear_justification_requests() - } - fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { - self.protocol.request_justification(&mut self.context, hash, number) - } - fn request_finality_proof(&mut self, hash: &B::Hash, number: NumberFor) { - self.protocol.request_finality_proof(&mut self.context, hash, number) - } - fn finality_proof_imported( - &mut self, - who: PeerId, - request_block: (B::Hash, NumberFor), - finalization_result: Result<(B::Hash, NumberFor), ()>, - ) { - let success = finalization_result.is_ok(); - self.protocol.finality_proof_import_result(request_block, finalization_result); - if !success { - info!("Invalid finality proof provided by {} for #{}", who, request_block.0); - self.context.0.user_protocol_mut().disconnect_peer(&who); - self.context.1.report_peer(who, i32::min_value()); - } - } - fn report_peer(&mut self, who: PeerId, reputation_change: i32) { - self.context.1.report_peer(who, reputation_change) - } - fn restart(&mut self) { - self.protocol.restart(&mut self.context) - } - fn set_finality_proof_request_builder(&mut self, builder: SharedFinalityProofRequestBuilder) { - self.protocol.set_finality_proof_request_builder(builder) - } - } - - while let Ok(Async::Ready(_)) = self.status_interval.poll() { - let status = self.protocol.status(); - self.status_sinks.lock().retain(|sink| sink.unbounded_send(status.clone()).is_ok()); - } - - { - let mut network_service = self.network_service.lock(); - let mut link = NetworkLink { - protocol: &mut self.protocol, - context: Context(&mut network_service, &self.peerset), - }; - self.import_queue.poll_actions(&mut link); - } - - while let Ok(Async::Ready(_)) = self.connected_peers_interval.poll() { - let infos = self.protocol.peers_info().map(|(id, info)| { - (id.clone(), ConnectedPeer { peer_info: info.clone() }) - }).collect(); - *self.peers.write() = infos; - } - - { - let mut network_service = self.network_service.lock(); - let mut ctxt = Context(&mut *network_service, &self.peerset); - match self.protocol.poll(&mut ctxt, &*self.transaction_pool) { - Ok(Async::Ready(v)) => void::unreachable(v), - Ok(Async::NotReady) => {} - Err(err) => void::unreachable(err), - } - } + // Poll the import queue for actions to perform. + self.import_queue.poll_actions(&mut NetworkLink { + protocol: &mut self.network_service, + }); // Check for new incoming on-demand requests. if let Some(on_demand_in) = self.on_demand_in.as_mut() { while let Ok(Async::Ready(Some(rq))) = on_demand_in.poll() { - self.protocol.add_on_demand_request(&mut Context(&mut self.network_service.lock(), &self.peerset), rq); + self.network_service.user_protocol_mut().add_on_demand_request(rq); } } loop { - match self.network_port.poll() { - Ok(Async::NotReady) => break, - Ok(Async::Ready(Some(NetworkMsg::Outgoing(who, outgoing_message)))) => - self.network_service.lock().user_protocol_mut().send_packet(&who, outgoing_message), - Ok(Async::Ready(Some(NetworkMsg::ReportPeer(who, reputation)))) => - self.peerset.report_peer(who, reputation), - Ok(Async::Ready(Some(NetworkMsg::DisconnectPeer(who)))) => - self.network_service.lock().user_protocol_mut().disconnect_peer(&who), - - #[cfg(any(test, feature = "test-helpers"))] - Ok(Async::Ready(Some(NetworkMsg::Synchronized))) => {} - - Ok(Async::Ready(None)) | Err(_) => return Ok(Async::Ready(())), - } - } - - loop { - let msg = match self.protocol_rx.poll() { + // Process the next message coming from the `NetworkService`. + let msg = match self.from_worker.poll() { Ok(Async::Ready(Some(msg))) => msg, Ok(Async::Ready(None)) | Err(_) => return Ok(Async::Ready(())), Ok(Async::NotReady) => break, }; - let mut network_service = self.network_service.lock(); - let mut network_out = Context(&mut network_service, &self.peerset); - match msg { - ProtocolMsg::BlockImported(hash, header) => - self.protocol.on_block_imported(&mut network_out, hash, &header), - ProtocolMsg::BlockFinalized(hash, header) => - self.protocol.on_block_finalized(&mut network_out, hash, &header), - ProtocolMsg::ExecuteWithSpec(task) => { - let (mut context, spec) = self.protocol.specialization_lock(&mut network_out); - task.call_box(spec, &mut context); + ServerToWorkerMsg::ExecuteWithSpec(task) => { + let protocol = self.network_service.user_protocol_mut(); + let (mut context, spec) = protocol.specialization_lock(); + task(spec, &mut context); }, - ProtocolMsg::ExecuteWithGossip(task) => { - let (mut context, gossip) = self.protocol.consensus_gossip_lock(&mut network_out); - task.call_box(gossip, &mut context); + ServerToWorkerMsg::ExecuteWithGossip(task) => { + let protocol = self.network_service.user_protocol_mut(); + let (mut context, gossip) = protocol.consensus_gossip_lock(); + task(gossip, &mut context); } - ProtocolMsg::GossipConsensusMessage(topic, engine_id, message, recipient) => - self.protocol.gossip_consensus_message(&mut network_out, topic, engine_id, message, recipient), - ProtocolMsg::BlocksProcessed(hashes, has_error) => - self.protocol.blocks_processed(&mut network_out, hashes, has_error), - ProtocolMsg::RestartSync => - self.protocol.restart(&mut network_out), - ProtocolMsg::AnnounceBlock(hash) => - self.protocol.announce_block(&mut network_out, hash), - ProtocolMsg::BlockImportedSync(hash, number) => - self.protocol.block_imported(&hash, number), - ProtocolMsg::ClearJustificationRequests => - self.protocol.clear_justification_requests(), - ProtocolMsg::RequestJustification(hash, number) => - self.protocol.request_justification(&mut network_out, &hash, number), - ProtocolMsg::JustificationImportResult(hash, number, success) => - self.protocol.justification_import_result(hash, number, success), - ProtocolMsg::SetFinalityProofRequestBuilder(builder) => - self.protocol.set_finality_proof_request_builder(builder), - ProtocolMsg::RequestFinalityProof(hash, number) => - self.protocol.request_finality_proof(&mut network_out, &hash, number), - ProtocolMsg::FinalityProofImportResult(requested_block, finalziation_result) => - self.protocol.finality_proof_import_result(requested_block, finalziation_result), - ProtocolMsg::PropagateExtrinsics => - self.protocol.propagate_extrinsics(&mut network_out, &*self.transaction_pool), - #[cfg(any(test, feature = "test-helpers"))] - ProtocolMsg::Tick => self.protocol.tick(&mut network_out), - #[cfg(any(test, feature = "test-helpers"))] - ProtocolMsg::Synchronize => {}, + ServerToWorkerMsg::GossipConsensusMessage(topic, engine_id, message, recipient) => + self.network_service.user_protocol_mut().gossip_consensus_message(topic, engine_id, message, recipient), + ServerToWorkerMsg::AnnounceBlock(hash) => + self.network_service.user_protocol_mut().announce_block(hash), + ServerToWorkerMsg::RequestJustification(hash, number) => + self.network_service.user_protocol_mut().request_justification(&hash, number), + ServerToWorkerMsg::PropagateExtrinsics => + self.network_service.user_protocol_mut().propagate_extrinsics(), + ServerToWorkerMsg::GetValue(key) => + self.network_service.get_value(&key), + ServerToWorkerMsg::PutValue(key, value) => + self.network_service.put_value(key, value), + ServerToWorkerMsg::AddKnownAddress(peer_id, addr) => + self.network_service.add_known_address(peer_id, addr), } } loop { - let mut network_service = self.network_service.lock(); - let poll_value = network_service.poll(); - let mut network_out = Context(&mut network_service, &self.peerset); + // Process the next action coming from the network. + let poll_value = self.network_service.poll(); let outcome = match poll_value { Ok(Async::NotReady) => break, - Ok(Async::Ready(Some(CustomProtoOut::CustomProtocolOpen { peer_id, version, .. }))) => { - debug_assert!( - version <= protocol::CURRENT_VERSION as u8 - && version >= protocol::MIN_VERSION as u8 - ); - self.protocol.on_peer_connected(&mut network_out, peer_id); - CustomMessageOutcome::None - } - Ok(Async::Ready(Some(CustomProtoOut::CustomProtocolClosed { peer_id, .. }))) => { - self.protocol.on_peer_disconnected(&mut network_out, peer_id); + Ok(Async::Ready(Some(BehaviourOut::SubstrateAction(outcome)))) => outcome, + Ok(Async::Ready(Some(BehaviourOut::Dht(ev)))) => { + self.network_service.user_protocol_mut() + .on_event(Event::Dht(ev)); CustomMessageOutcome::None }, - Ok(Async::Ready(Some(CustomProtoOut::CustomMessage { peer_id, message }))) => - self.protocol.on_custom_message( - &mut network_out, - &*self.transaction_pool, - peer_id, - message, - self.finality_proof_provider.as_ref().map(|p| &**p) - ), - Ok(Async::Ready(Some(CustomProtoOut::Clogged { peer_id, messages, .. }))) => { - debug!(target: "sync", "{} clogging messages:", messages.len()); - for msg in messages.into_iter().take(5) { - debug!(target: "sync", "{:?}", msg); - self.protocol.on_clogged_peer(&mut network_out, peer_id.clone(), Some(msg)); - } - CustomMessageOutcome::None - } - Ok(Async::Ready(None)) => return Ok(Async::Ready(())), + Ok(Async::Ready(None)) => CustomMessageOutcome::None, Err(err) => { error!(target: "sync", "Error in the network: {:?}", err); return Err(err) @@ -742,99 +619,63 @@ impl, H: ExHashT> Future for Ne } } - self.is_offline.store(self.protocol.is_offline(), Ordering::Relaxed); - self.is_major_syncing.store(self.protocol.is_major_syncing(), Ordering::Relaxed); + // Update the variables shared with the `NetworkService`. + self.num_connected.store(self.network_service.user_protocol_mut().num_connected_peers(), Ordering::Relaxed); + self.is_major_syncing.store(match self.network_service.user_protocol_mut().sync_state() { + SyncState::Idle => false, + SyncState::Downloading => true, + }, Ordering::Relaxed); Ok(Async::NotReady) } } /// The libp2p swarm, customized for our needs. -type Swarm = libp2p::core::Swarm< +type Swarm = libp2p::core::Swarm< Boxed<(PeerId, StreamMuxerBox), io::Error>, - Behaviour, Substream>, CustomProtoOut>, Substream> + Behaviour >; -/// Starts the substrate libp2p service. -/// -/// Returns a stream that must be polled regularly in order for the networking to function. -fn start_service>( - config: NetworkConfiguration, - protocol_id: Pid, - versions: &[u8], -) -> Result<(Swarm, Arc, peerset::PeersetHandle), io::Error> { - - if let Some(ref path) = config.net_config_path { - fs::create_dir_all(Path::new(path))?; - } - - // List of multiaddresses that we know in the network. - let mut known_addresses = Vec::new(); - let mut bootnodes = Vec::new(); - let mut reserved_nodes = Vec::new(); - - // Process the bootnodes. - for bootnode in config.boot_nodes.iter() { - match parse_str_addr(bootnode) { - Ok((peer_id, addr)) => { - bootnodes.push(peer_id.clone()); - known_addresses.push((peer_id, addr)); - }, - Err(_) => warn!(target: "sub-libp2p", "Not a valid bootnode address: {}", bootnode), - } - } +// Implementation of `import_queue::Link` trait using the available local variables. +struct NetworkLink<'a, B: BlockT, S: NetworkSpecialization, H: ExHashT> { + protocol: &'a mut Swarm, +} - // Initialize the reserved peers. - for reserved in config.reserved_nodes.iter() { - if let Ok((peer_id, addr)) = parse_str_addr(reserved) { - reserved_nodes.push(peer_id.clone()); - known_addresses.push((peer_id, addr)); - } else { - warn!(target: "sub-libp2p", "Not a valid reserved node address: {}", reserved); +impl<'a, B: BlockT, S: NetworkSpecialization, H: ExHashT> Link for NetworkLink<'a, B, S, H> { + fn blocks_processed( + &mut self, + imported: usize, + count: usize, + results: Vec<(Result>, BlockImportError>, B::Hash)> + ) { + self.protocol.user_protocol_mut().blocks_processed(imported, count, results) + } + fn justification_imported(&mut self, who: PeerId, hash: &B::Hash, number: NumberFor, success: bool) { + self.protocol.user_protocol_mut().justification_import_result(hash.clone(), number, success); + if !success { + info!("Invalid justification provided by {} for #{}", who, hash); + self.protocol.user_protocol_mut().disconnect_peer(&who); + self.protocol.user_protocol_mut().report_peer(who, i32::min_value()); } } - - // Build the peerset. - let (peerset, peerset_handle) = peerset::Peerset::from_config(peerset::PeersetConfig { - in_peers: config.in_peers, - out_peers: config.out_peers, - bootnodes, - reserved_only: config.non_reserved_mode == NonReservedPeerMode::Deny, - reserved_nodes, - }); - - // Private and public keys configuration. - if let NodeKeyConfig::Secp256k1(_) = config.node_key { - warn!(target: "sub-libp2p", "Secp256k1 keys are deprecated in favour of ed25519"); - } - let local_identity = config.node_key.clone().into_keypair()?; - let local_public = local_identity.public(); - let local_peer_id = local_public.clone().into_peer_id(); - info!(target: "sub-libp2p", "Local node identity is: {}", local_peer_id.to_base58()); - - // Build the swarm. - let (mut swarm, bandwidth) = { - let user_agent = format!("{} ({})", config.client_version, config.node_name); - let proto = CustomProto::new(protocol_id, versions, peerset); - let behaviour = Behaviour::new(proto, user_agent, local_public, known_addresses, config.enable_mdns); - let (transport, bandwidth) = transport::build_transport( - local_identity, - config.wasm_external_transport - ); - (Swarm::::new(transport, behaviour, local_peer_id.clone()), bandwidth) - }; - - // Listen on multiaddresses. - for addr in &config.listen_addresses { - if let Err(err) = Swarm::::listen_on(&mut swarm, addr.clone()) { - warn!(target: "sub-libp2p", "Can't listen on {} because: {:?}", addr, err) - } + fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { + self.protocol.user_protocol_mut().request_justification(hash, number) } - - // Add external addresses. - for addr in &config.public_addresses { - Swarm::::add_external_address(&mut swarm, addr.clone()); + fn request_finality_proof(&mut self, hash: &B::Hash, number: NumberFor) { + self.protocol.user_protocol_mut().request_finality_proof(hash, number) + } + fn finality_proof_imported( + &mut self, + who: PeerId, + request_block: (B::Hash, NumberFor), + finalization_result: Result<(B::Hash, NumberFor), ()>, + ) { + let success = finalization_result.is_ok(); + self.protocol.user_protocol_mut().finality_proof_import_result(request_block, finalization_result); + if !success { + info!("Invalid finality proof provided by {} for #{}", who, request_block.0); + self.protocol.user_protocol_mut().disconnect_peer(&who); + self.protocol.user_protocol_mut().report_peer(who, i32::min_value()); + } } - - Ok((swarm, bandwidth, peerset_handle)) } diff --git a/core/network/src/test/block_import.rs b/core/network/src/test/block_import.rs index b5a03ae23a5a3be53c6404252024b55c77b14da1..eb49dbda7ae433f348059aa45bd6058e937052a6 100644 --- a/core/network/src/test/block_import.rs +++ b/core/network/src/test/block_import.rs @@ -16,16 +16,14 @@ //! Testing block import logic. -use consensus::import_queue::{import_single_block, BasicQueue, BlockImportError, BlockImportResult}; +use consensus::import_queue::{ + import_single_block, IncomingBlock, BasicQueue, BlockImportError, BlockImportResult +}; use test_client::{self, prelude::*}; use test_client::runtime::{Block, Hash}; use runtime_primitives::generic::BlockId; use super::*; -struct TestLink {} - -impl Link for TestLink {} - fn prepare_good_block() -> (TestClient, Hash, u64, PeerId, IncomingBlock) { let client = test_client::new(); let block = client.new_block(Default::default()).unwrap().bake().unwrap(); @@ -47,29 +45,30 @@ fn prepare_good_block() -> (TestClient, Hash, u64, PeerId, IncomingBlock) #[test] fn import_single_good_block_works() { let (_, _hash, number, peer_id, block) = prepare_good_block(); - assert_eq!( - import_single_block(&test_client::new(), BlockOrigin::File, block, Arc::new(PassThroughVerifier(true))), - Ok(BlockImportResult::ImportedUnknown(number, Default::default(), Some(peer_id))) - ); + match import_single_block(&mut test_client::new(), BlockOrigin::File, block, Arc::new(PassThroughVerifier(true))) { + Ok(BlockImportResult::ImportedUnknown(ref num, ref aux, ref org)) + if *num == number && *aux == Default::default() && *org == Some(peer_id) => {} + _ => panic!() + } } #[test] fn import_single_good_known_block_is_ignored() { - let (client, _hash, number, _, block) = prepare_good_block(); - assert_eq!( - import_single_block(&client, BlockOrigin::File, block, Arc::new(PassThroughVerifier(true))), - Ok(BlockImportResult::ImportedKnown(number)) - ); + let (mut client, _hash, number, _, block) = prepare_good_block(); + match import_single_block(&mut client, BlockOrigin::File, block, Arc::new(PassThroughVerifier(true))) { + Ok(BlockImportResult::ImportedKnown(ref n)) if *n == number => {} + _ => panic!() + } } #[test] fn import_single_good_block_without_header_fails() { let (_, _, _, peer_id, mut block) = prepare_good_block(); block.header = None; - assert_eq!( - import_single_block(&test_client::new(), BlockOrigin::File, block, Arc::new(PassThroughVerifier(true))), - Err(BlockImportError::IncompleteHeader(Some(peer_id))) - ); + match import_single_block(&mut test_client::new(), BlockOrigin::File, block, Arc::new(PassThroughVerifier(true))) { + Err(BlockImportError::IncompleteHeader(ref org)) if *org == Some(peer_id) => {} + _ => panic!() + } } #[test] @@ -77,7 +76,7 @@ fn async_import_queue_drops() { // Perform this test multiple times since it exhibits non-deterministic behavior. for _ in 0..100 { let verifier = Arc::new(PassThroughVerifier(true)); - let mut queue = BasicQueue::new(verifier, Arc::new(test_client::new()), None, None, None); + let queue = BasicQueue::new(verifier, Box::new(test_client::new()), None, None); drop(queue); } } diff --git a/core/network/src/test/mod.rs b/core/network/src/test/mod.rs index 95646cd74b31fa96ec2f2aabecf7524236be1d11..59a3680d40038b8c761b4588ccff363f4fcbb5a7 100644 --- a/core/network/src/test/mod.rs +++ b/core/network/src/test/mod.rs @@ -21,36 +21,36 @@ mod block_import; #[cfg(test)] mod sync; -use std::collections::{HashMap, HashSet, VecDeque}; +use std::collections::HashMap; use std::sync::Arc; -use crate::AlwaysBadChecker; +use crate::config::build_multiaddr; use log::trace; use crate::chain::FinalityProofProvider; -use client::{self, ClientInfo, BlockchainEvents, FinalityNotifications}; +use client::{self, ClientInfo, BlockchainEvents, BlockImportNotification, FinalityNotifications, FinalityNotification}; use client::{in_mem::Backend as InMemoryBackend, error::Result as ClientResult}; use client::block_builder::BlockBuilder; use client::backend::AuxStore; use crate::config::Roles; -use consensus::import_queue::{BasicQueue, ImportQueue, IncomingBlock}; +use consensus::import_queue::BasicQueue; use consensus::import_queue::{ - Link, SharedBlockImport, SharedJustificationImport, Verifier, SharedFinalityProofImport, - SharedFinalityProofRequestBuilder, + BoxBlockImport, BoxJustificationImport, Verifier, BoxFinalityProofImport, }; +use consensus::block_import::{BlockImport, ImportResult}; use consensus::{Error as ConsensusError, well_known_cache_keys::{self, Id as CacheKeyId}}; use consensus::{BlockOrigin, ForkChoiceStrategy, ImportBlock, JustificationImport}; -use crate::consensus_gossip::{ConsensusGossip, MessageRecipient as GossipMessageRecipient, TopicNotification}; -use futures::{prelude::*, sync::{mpsc, oneshot}}; -use log::info; -use crate::message::Message; +use futures::prelude::*; +use futures03::{StreamExt as _, TryStreamExt as _}; +use crate::{NetworkWorker, NetworkService, config::ProtocolId}; +use crate::config::{NetworkConfiguration, TransportConfig, BoxFinalityProofRequestBuilder}; use libp2p::PeerId; -use parking_lot::{Mutex, RwLock}; +use parking_lot::Mutex; use primitives::{H256, Blake2Hasher}; -use crate::protocol::{Context, Protocol, ProtocolConfig, ProtocolStatus, CustomMessageOutcome, NetworkOut}; +use crate::protocol::{Context, ProtocolConfig}; use runtime_primitives::generic::{BlockId, OpaqueDigestItemId}; use runtime_primitives::traits::{Block as BlockT, Header, NumberFor}; -use runtime_primitives::{Justification, ConsensusEngineId}; -use crate::service::{NetworkMsg, ProtocolMsg, TransactionPool}; +use runtime_primitives::Justification; +use crate::service::TransactionPool; use crate::specialization::NetworkSpecialization; use test_client::{self, AccountKeyring}; @@ -93,84 +93,6 @@ impl Verifier for PassThroughVerifier { } } -/// A link implementation that does nothing. -pub struct NoopLink { } - -impl Link for NoopLink { } - -/// A link implementation that connects to the network. -#[derive(Clone)] -pub struct NetworkLink> { - /// The protocol sender - pub(crate) protocol_sender: mpsc::UnboundedSender>, - /// The network sender - pub(crate) network_sender: mpsc::UnboundedSender>, -} - -impl> Link for NetworkLink { - fn block_imported(&mut self, hash: &B::Hash, number: NumberFor) { - let _ = self.protocol_sender.unbounded_send(ProtocolMsg::BlockImportedSync(hash.clone(), number)); - } - - fn blocks_processed(&mut self, processed_blocks: Vec, has_error: bool) { - let _ = self.protocol_sender.unbounded_send(ProtocolMsg::BlocksProcessed(processed_blocks, has_error)); - } - - fn justification_imported(&mut self, who: PeerId, hash: &B::Hash, number: NumberFor, success: bool) { - let _ = self.protocol_sender.unbounded_send(ProtocolMsg::JustificationImportResult(hash.clone(), number, success)); - if !success { - info!("Invalid justification provided by {} for #{}", who, hash); - let _ = self.network_sender.unbounded_send(NetworkMsg::ReportPeer(who.clone(), i32::min_value())); - let _ = self.network_sender.unbounded_send(NetworkMsg::DisconnectPeer(who.clone())); - } - } - - fn clear_justification_requests(&mut self) { - let _ = self.protocol_sender.unbounded_send(ProtocolMsg::ClearJustificationRequests); - } - - fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { - let _ = self.protocol_sender.unbounded_send(ProtocolMsg::RequestJustification(hash.clone(), number)); - } - - fn request_finality_proof(&mut self, hash: &B::Hash, number: NumberFor) { - let _ = self.protocol_sender.unbounded_send(ProtocolMsg::RequestFinalityProof( - hash.clone(), - number, - )); - } - - fn finality_proof_imported( - &mut self, - who: PeerId, - request_block: (B::Hash, NumberFor), - finalization_result: Result<(B::Hash, NumberFor), ()>, - ) { - let success = finalization_result.is_ok(); - let _ = self.protocol_sender.unbounded_send(ProtocolMsg::FinalityProofImportResult( - request_block, - finalization_result, - )); - if !success { - info!("Invalid finality proof provided by {} for #{}", who, request_block.0); - let _ = self.network_sender.unbounded_send(NetworkMsg::ReportPeer(who.clone(), i32::min_value())); - let _ = self.network_sender.unbounded_send(NetworkMsg::DisconnectPeer(who.clone())); - } - } - - fn report_peer(&mut self, who: PeerId, reputation_change: i32) { - let _ = self.network_sender.unbounded_send(NetworkMsg::ReportPeer(who, reputation_change)); - } - - fn restart(&mut self) { - let _ = self.protocol_sender.unbounded_send(ProtocolMsg::RestartSync); - } - - fn set_finality_proof_request_builder(&mut self, request_builder: SharedFinalityProofRequestBuilder) { - let _ = self.protocol_sender.unbounded_send(ProtocolMsg::SetFinalityProofRequestBuilder(request_builder)); - } -} - /// The test specialization. #[derive(Clone)] pub struct DummySpecialization; @@ -193,7 +115,12 @@ impl NetworkSpecialization for DummySpecialization { &mut self, _ctx: &mut dyn Context, _peer_id: PeerId, - _message: &mut Option>, + _message: Vec, + ) {} + + fn on_event( + &mut self, + _event: crate::specialization::Event ) {} } @@ -216,10 +143,10 @@ impl PeersClient { } } - pub fn as_block_import(&self) -> SharedBlockImport { + pub fn as_block_import(&self) -> BoxBlockImport { match *self { - PeersClient::Full(ref client) => client.clone() as _, - PeersClient::Light(ref client) => client.clone() as _, + PeersClient::Full(ref client) => Box::new(client.clone()) as _, + PeersClient::Light(ref client) => Box::new(client.clone()) as _, } } @@ -280,426 +207,48 @@ impl PeersClient { } } -/// A Link that can wait for a block to have been imported. -pub struct TestLink> { - link: NetworkLink, - - #[cfg(any(test, feature = "test-helpers"))] - network_to_protocol_sender: mpsc::UnboundedSender>, -} - -impl> TestLink { - fn new( - protocol_sender: mpsc::UnboundedSender>, - _network_to_protocol_sender: mpsc::UnboundedSender>, - network_sender: mpsc::UnboundedSender> - ) -> TestLink { - TestLink { - #[cfg(any(test, feature = "test-helpers"))] - network_to_protocol_sender: _network_to_protocol_sender, - link: NetworkLink { - protocol_sender, - network_sender, - } - } - } -} - -impl> Link for TestLink { - fn block_imported(&mut self, hash: &Hash, number: NumberFor) { - self.link.block_imported(hash, number); - } - - fn blocks_processed(&mut self, processed_blocks: Vec, has_error: bool) { - self.link.blocks_processed(processed_blocks, has_error); - } - - fn justification_imported(&mut self, who: PeerId, hash: &Hash, number:NumberFor, success: bool) { - self.link.justification_imported(who, hash, number, success); - } - - fn request_justification(&mut self, hash: &Hash, number: NumberFor) { - self.link.request_justification(hash, number); - } - - fn finality_proof_imported( - &mut self, - who: PeerId, - request_block: (Hash, NumberFor), - finalization_result: Result<(Hash, NumberFor), ()>, - ) { - self.link.finality_proof_imported(who, request_block, finalization_result); - } - - fn request_finality_proof(&mut self, hash: &Hash, number: NumberFor) { - self.link.request_finality_proof(hash, number); - } - - fn set_finality_proof_request_builder(&mut self, request_builder: SharedFinalityProofRequestBuilder) { - self.link.set_finality_proof_request_builder(request_builder); - } - - fn report_peer(&mut self, who: PeerId, reputation_change: i32) { - self.link.report_peer(who, reputation_change); - } - - fn restart(&mut self) { - self.link.restart(); - } - - /// Send synchronization request to the block import channel. - /// - /// The caller should wait for the `Link::synchronized` call to ensure that it has synchronized - /// with `ImportQueue`. - #[cfg(any(test, feature = "test-helpers"))] - fn synchronized(&mut self) { - drop(self.network_to_protocol_sender.unbounded_send(FromNetworkMsg::Synchronize)) - } -} - pub struct Peer> { - peer_id: PeerId, - client: PeersClient, - net_proto_channel: ProtocolChannel, - /// This field is used only in test code, but maintaining different - /// instantiation paths or field names is too much hassle, hence - /// we allow it to be unused. - #[cfg_attr(not(test), allow(unused))] - protocol_status: Arc>>, - import_queue: Arc>>>, pub data: D, - best_hash: Mutex>, - finalized_hash: Mutex>, -} - -type MessageFilter = dyn Fn(&NetworkMsg) -> bool; - -pub enum FromNetworkMsg { - /// A peer connected. - PeerConnected(PeerId), - /// A peer disconnected. - PeerDisconnected(PeerId), - /// A custom message from another peer. - CustomMessage(PeerId, Message), - /// Synchronization request. - Synchronize, -} - -struct ProtocolChannel> { - /// If true, we expect a tokio executor to be available. If false, we spawn our own. - use_tokio: bool, - buffered_messages: Mutex>>, - network_to_protocol_sender: mpsc::UnboundedSender>, - client_to_protocol_sender: mpsc::UnboundedSender>, - protocol_to_network_receiver: Mutex>>, -} - -impl> ProtocolChannel { - /// Create new buffered network port. - pub fn new( - use_tokio: bool, - network_to_protocol_sender: mpsc::UnboundedSender>, - client_to_protocol_sender: mpsc::UnboundedSender>, - protocol_to_network_receiver: mpsc::UnboundedReceiver>, - ) -> Self { - ProtocolChannel { - use_tokio, - buffered_messages: Mutex::new(VecDeque::new()), - network_to_protocol_sender, - client_to_protocol_sender, - protocol_to_network_receiver: Mutex::new(protocol_to_network_receiver), - } - } - - /// Send message from network to protocol. - pub fn send_from_net(&self, message: FromNetworkMsg) { - let _ = self.network_to_protocol_sender.unbounded_send(message); - - let _ = self.network_to_protocol_sender.unbounded_send(FromNetworkMsg::Synchronize); - let _ = self.wait_sync(); - } - - /// Send message from client to protocol. - pub fn send_from_client(&self, message: ProtocolMsg) { - let _ = self.client_to_protocol_sender.unbounded_send(message); - - let _ = self.client_to_protocol_sender.unbounded_send(ProtocolMsg::Synchronize); - let _ = self.wait_sync(); - } - - /// Wait until synchronization response is generated by the protocol. - pub fn wait_sync(&self) -> Result<(), ()> { - let fut = futures::future::poll_fn(|| { - loop { - let mut protocol_to_network_receiver = self.protocol_to_network_receiver.lock(); - match protocol_to_network_receiver.poll() { - Ok(Async::Ready(Some(NetworkMsg::Synchronized))) => return Ok(Async::Ready(())), - Ok(Async::Ready(None)) | Err(_) => return Err(()), - Ok(Async::NotReady) => return Ok(Async::NotReady), - Ok(Async::Ready(Some(msg))) => self.buffered_messages.lock().push_back(msg), - } - } - }); - - if self.use_tokio { - fut.wait() - } else { - tokio::runtime::current_thread::block_on_all(fut) - } - } - - /// Produce the next pending message to send to another peer. - fn pending_message(&self, message_filter: &MessageFilter) -> Option> { - if let Some(message) = self.buffered_message(message_filter) { - return Some(message); - } - - while let Some(message) = self.channel_message() { - if message_filter(&message) { - return Some(message) - } else { - self.buffered_messages.lock().push_back(message); - } - } - - None - } - - /// Whether this peer is done syncing (has no messages to send). - fn is_done(&self) -> bool { - let mut buffered_messages = self.buffered_messages.lock(); - if let Some(msg) = self.channel_message() { - buffered_messages.push_back(msg); - false - } else { - buffered_messages.is_empty() - } - } - - /// Return oldest buffered message if it exists. - fn buffered_message(&self, message_filter: &MessageFilter) -> Option> { - let mut buffered_messages = self.buffered_messages.lock(); - for i in 0..buffered_messages.len() { - if message_filter(&buffered_messages[i]) { - return buffered_messages.remove(i); - } - } - - None - } - - /// Receive message from the channel. - fn channel_message(&self) -> Option> { - let fut = futures::future::poll_fn(|| -> Result<_, ()> { - Ok(Async::Ready(match self.protocol_to_network_receiver.lock().poll() { - Ok(Async::Ready(Some(m))) => Some(m), - Ok(Async::NotReady) => None, - Err(_) => None, - Ok(Async::Ready(None)) => None, - })) - }); - - if self.use_tokio { - fut.wait() - } else { - tokio::runtime::current_thread::block_on_all(fut) - }.ok().and_then(|a| a) - } + client: PeersClient, + /// We keep a copy of the verifier so that we can invoke it for locally-generated blocks, + /// instead of going through the import queue. + verifier: Arc>, + /// We keep a copy of the block_import so that we can invoke it for locally-generated blocks, + /// instead of going through the import queue. + block_import: Box>, + network: NetworkWorker::Hash>, + imported_blocks_stream: Box, Error = ()> + Send>, + finality_notification_stream: Box, Error = ()> + Send>, } impl> Peer { - fn new( - protocol_status: Arc>>, - client: PeersClient, - import_queue: Arc>>>, - use_tokio: bool, - network_to_protocol_sender: mpsc::UnboundedSender>, - protocol_sender: mpsc::UnboundedSender>, - network_sender: mpsc::UnboundedSender>, - network_port: mpsc::UnboundedReceiver>, - data: D, - ) -> Self { - let net_proto_channel = ProtocolChannel::new( - use_tokio, - network_to_protocol_sender.clone(), - protocol_sender.clone(), - network_port, - ); - Peer { - protocol_status, - peer_id: PeerId::random(), - client, - import_queue, - net_proto_channel, - data, - best_hash: Mutex::new(None), - finalized_hash: Mutex::new(None), - } - } - /// Called after blockchain has been populated to updated current state. - fn start(&self) { - // Update the sync state to the latest chain state. - let info = self.client.info(); - let header = self - .client - .header(&BlockId::Hash(info.chain.best_hash)) - .unwrap() - .unwrap(); - self.net_proto_channel.send_from_client(ProtocolMsg::BlockImported(info.chain.best_hash, header)); - } - - #[cfg(test)] - fn on_block_imported( - &self, - hash: ::Hash, - header: &::Header, - ) { - self.net_proto_channel.send_from_client(ProtocolMsg::BlockImported(hash, header.clone())); - } - - /// SyncOracle: are we connected to any peer? - #[cfg(test)] - fn is_offline(&self) -> bool { - self.protocol_status.read().sync.is_offline() - } - - /// SyncOracle: are we in the process of catching-up with the chain? - #[cfg(test)] - fn is_major_syncing(&self) -> bool { - self.protocol_status.read().sync.is_major_syncing() - } - - /// Get protocol status. - #[cfg(test)] - fn protocol_status(&self) -> ProtocolStatus { - self.protocol_status.read().clone() - } - - /// Called on connection to other indicated peer. - fn on_connect(&self, other: &Self) { - self.net_proto_channel.send_from_net(FromNetworkMsg::PeerConnected(other.peer_id.clone())); - } - - /// Called on disconnect from other indicated peer. - fn on_disconnect(&self, other: &Self) { - self.net_proto_channel.send_from_net(FromNetworkMsg::PeerDisconnected(other.peer_id.clone())); - } - - /// Receive a message from another peer. Return a set of peers to disconnect. - fn receive_message(&self, from: &PeerId, msg: Message) { - self.net_proto_channel.send_from_net(FromNetworkMsg::CustomMessage(from.clone(), msg)); - } - - /// Produce the next pending message to send to another peer. - fn pending_message(&self, message_filter: &MessageFilter) -> Option> { - self.net_proto_channel.pending_message(message_filter) + /// Returns true if we're major syncing. + pub fn is_major_syncing(&self) -> bool { + self.network.service().is_major_syncing() } - /// Whether this peer is done syncing (has no messages to send). - fn is_done(&self) -> bool { - self.net_proto_channel.is_done() + /// Returns the number of peers we're connected to. + pub fn num_peers(&self) -> usize { + self.network.num_connected_peers() } - /// Synchronize with import queue. - #[cfg(any(test, feature = "test-helpers"))] - pub fn import_queue_sync(&self) { - self.import_queue.lock().synchronize(); - let _ = self.net_proto_channel.wait_sync(); + /// Returns true if we have no peer. + pub fn is_offline(&self) -> bool { + self.num_peers() == 0 } - /// Execute a "sync step". This is called for each peer after it sends a packet. - fn sync_step(&self) { - self.net_proto_channel.send_from_client(ProtocolMsg::Tick); - } - - /// Send block import notifications. - fn send_import_notifications(&self) { - let info = self.client.info(); - - let mut best_hash = self.best_hash.lock(); - match *best_hash { - None => {}, - Some(hash) if hash != info.chain.best_hash => {}, - _ => return, - } - - let header = self.client.header(&BlockId::Hash(info.chain.best_hash)).unwrap().unwrap(); - self.net_proto_channel.send_from_client(ProtocolMsg::BlockImported(info.chain.best_hash, header)); - *best_hash = Some(info.chain.best_hash); - } - - /// Send block finalization notifications. - fn send_finality_notifications(&self) { - let info = self.client.info(); - - let mut finalized_hash = self.finalized_hash.lock(); - match *finalized_hash { - None => {}, - Some(hash) if hash != info.chain.finalized_hash => {}, - _ => return, - } - - let header = self.client.header(&BlockId::Hash(info.chain.finalized_hash)).unwrap().unwrap(); - self.net_proto_channel.send_from_client( - ProtocolMsg::BlockFinalized(info.chain.finalized_hash, header.clone()) - ); - *finalized_hash = Some(info.chain.finalized_hash); - } - - /// Push a message into the gossip network and relay to peers. - /// `TestNet::sync_step` needs to be called to ensure it's propagated. - pub fn gossip_message( - &self, - topic: ::Hash, - engine_id: ConsensusEngineId, - data: Vec, - force: bool, - ) { - let recipient = if force { - GossipMessageRecipient::BroadcastToAll - } else { - GossipMessageRecipient::BroadcastNew - }; - self.net_proto_channel.send_from_client( - ProtocolMsg::GossipConsensusMessage(topic, engine_id, data, recipient), - ); - } - - /// access the underlying consensus gossip handler - pub fn consensus_gossip_messages_for( - &self, - engine_id: ConsensusEngineId, - topic: ::Hash, - ) -> mpsc::UnboundedReceiver { - let (tx, rx) = oneshot::channel(); - self.with_gossip(move |gossip, _| { - let inner_rx = gossip.messages_for(engine_id, topic); - let _ = tx.send(inner_rx); - }); - rx.wait().ok().expect("1. Network is running, 2. it should handle the above closure successfully") - } - - /// Execute a closure with the consensus gossip. - pub fn with_gossip(&self, f: F) - where F: FnOnce(&mut ConsensusGossip, &mut dyn Context) + Send + 'static - { - self.net_proto_channel.send_from_client(ProtocolMsg::ExecuteWithGossip(Box::new(f))); - } - - /// Announce a block to peers. - #[cfg(test)] - fn announce_block(&self, block: Hash) { - self.net_proto_channel.send_from_client(ProtocolMsg::AnnounceBlock(block)); + /// Request a justification for the given block. + pub fn request_justification(&self, hash: &::Hash, number: NumberFor) { + self.network.service().request_justification(hash, number); } - /// Request a justification for the given block. - #[cfg(test)] - fn request_justification(&self, hash: &::primitives::H256, number: NumberFor) { - self.net_proto_channel.send_from_client(ProtocolMsg::RequestJustification(hash.clone(), number)); + /// Announces an important block on the network. + pub fn announce_block(&self, hash: ::Hash) { + self.network.service().announce_block(hash); } /// Add blocks to the peer -- edit the block before adding - pub fn generate_blocks(&self, count: usize, origin: BlockOrigin, edit_block: F) -> H256 + pub fn generate_blocks(&mut self, count: usize, origin: BlockOrigin, edit_block: F) -> H256 where F: FnMut(BlockBuilder) -> Block { let best_hash = self.client.info().chain.best_hash; @@ -709,7 +258,7 @@ impl> Peer { /// Add blocks to the peer -- edit the block before adding. The chain will /// start at the given block iD. fn generate_blocks_at( - &self, + &mut self, at: BlockId, count: usize, origin: BlockOrigin, @@ -730,34 +279,35 @@ impl> Peer { block.header.parent_hash ); let header = block.header.clone(); - at = hash; - self.import_queue.lock().import_blocks( + let (import_block, cache) = self.verifier.verify( origin, - vec![IncomingBlock { - origin: None, - hash, - header: Some(header), - body: Some(block.extrinsics), - justification: None, - }], - ); - - // make sure block import has completed - self.import_queue_sync(); + header.clone(), + None, + Some(block.extrinsics) + ).unwrap(); + let cache = if let Some(cache) = cache { + cache.into_iter().collect() + } else { + Default::default() + }; + self.block_import.import_block(import_block, cache).expect("block_import failed"); + self.network.on_block_imported(hash, header); + at = hash; } + self.network.service().announce_block(at.clone()); at } /// Push blocks to the peer (simplified: with or without a TX) - pub fn push_blocks(&self, count: usize, with_tx: bool) -> H256 { + pub fn push_blocks(&mut self, count: usize, with_tx: bool) -> H256 { let best_hash = self.client.info().chain.best_hash; self.push_blocks_at(BlockId::Hash(best_hash), count, with_tx) } /// Push blocks to the peer (simplified: with or without a TX) starting from /// given hash. - pub fn push_blocks_at(&self, at: BlockId, count: usize, with_tx: bool) -> H256 { + pub fn push_blocks_at(&mut self, at: BlockId, count: usize, with_tx: bool) -> H256 { let mut nonce = 0; if with_tx { self.generate_blocks_at(at, count, BlockOrigin::File, |mut builder| { @@ -776,7 +326,7 @@ impl> Peer { } } - pub fn push_authorities_change_block(&self, new_authorities: Vec) -> H256 { + pub fn push_authorities_change_block(&mut self, new_authorities: Vec) -> H256 { self.generate_blocks(1, BlockOrigin::File, |mut builder| { builder.push(Extrinsic::AuthoritiesChange(new_authorities.clone())).unwrap(); builder.bake().unwrap() @@ -787,6 +337,11 @@ impl> Peer { pub fn client(&self) -> &PeersClient { &self.client } + + /// Get a reference to the network service. + pub fn network_service(&self) -> &Arc::Hash>> { + &self.network.service() + } } pub struct EmptyTransactionPool; @@ -813,6 +368,33 @@ impl SpecializationFactory for DummySpecialization { } } +/// Implements `BlockImport` on an `Arc>`. Used internally. Necessary to overcome the way the +/// `TestNet` trait is designed, more specifically `make_block_import` returning a `Box` makes it +/// impossible to clone the underlying object. +struct BlockImportAdapter(Arc>>); + +impl Clone for BlockImportAdapter { + fn clone(&self) -> Self { + BlockImportAdapter(self.0.clone()) + } +} + +impl> BlockImport for BlockImportAdapter { + type Error = T::Error; + + fn check_block(&mut self, hash: Hash, parent_hash: Hash) -> Result { + self.0.lock().check_block(hash, parent_hash) + } + + fn import_block( + &mut self, + block: ImportBlock, + cache: HashMap>, + ) -> Result { + self.0.lock().import_block(block, cache) + } +} + pub trait TestNetFactory: Sized { type Specialization: NetworkSpecialization + SpecializationFactory; type Verifier: 'static + Verifier; @@ -823,20 +405,17 @@ pub trait TestNetFactory: Sized { fn make_verifier(&self, client: PeersClient, config: &ProtocolConfig) -> Arc; /// Get reference to peer. - fn peer(&self, i: usize) -> &Peer; - fn peers(&self) -> &Vec>>; - fn mut_peers>>)>(&mut self, closure: F); - - fn started(&self) -> bool; - fn set_started(&mut self, now: bool); + fn peer(&mut self, i: usize) -> &mut Peer; + fn peers(&self) -> &Vec>; + fn mut_peers>)>(&mut self, closure: F); /// Get custom block import handle for fresh client, along with peer data. fn make_block_import(&self, client: PeersClient) -> ( - SharedBlockImport, - Option>, - Option>, - Option>, + BoxBlockImport, + Option>, + Option>, + Option>, Self::PeerData, ) { @@ -852,11 +431,6 @@ pub trait TestNetFactory: Sized { ProtocolConfig::default() } - /// Must return true if the testnet is going to be used from within a tokio context. - fn uses_tokio(&self) -> bool { - false - } - /// Create new test network with this many peers. fn new(n: usize) -> Self { trace!(target: "test_network", "Creating test network"); @@ -870,214 +444,60 @@ pub trait TestNetFactory: Sized { net } - /// Add created peer. - fn add_peer( - &mut self, - protocol_status: Arc>>, - import_queue: Arc>>>, - tx_pool: EmptyTransactionPool, - finality_proof_provider: Option>>, - mut protocol: Protocol, - protocol_sender: mpsc::UnboundedSender>, - network_to_protocol_sender: mpsc::UnboundedSender>, - network_sender: mpsc::UnboundedSender>, - mut network_to_protocol_rx: mpsc::UnboundedReceiver>, - mut protocol_rx: mpsc::UnboundedReceiver>, - peer: Arc>, - ) { - std::thread::spawn(move || { - // Implementation of `protocol::NetworkOut` using the available local variables. - struct Ctxt<'a, B: BlockT>(&'a mpsc::UnboundedSender>); - impl<'a, B: BlockT> NetworkOut for Ctxt<'a, B> { - fn report_peer(&mut self, who: PeerId, reputation: i32) { - let _ = self.0.unbounded_send(NetworkMsg::ReportPeer(who, reputation)); - } - fn disconnect_peer(&mut self, who: PeerId) { - let _ = self.0.unbounded_send(NetworkMsg::DisconnectPeer(who)); - } - fn send_message(&mut self, who: PeerId, message: Message) { - let _ = self.0.unbounded_send(NetworkMsg::Outgoing(who, message)); - } - } - - tokio::runtime::current_thread::run(futures::future::poll_fn(move || { - import_queue.lock().poll_actions(&mut TestLink::new( - protocol_sender.clone(), - network_to_protocol_sender.clone(), - network_sender.clone(), - )); - - while let Async::Ready(msg) = network_to_protocol_rx.poll().unwrap() { - let outcome = match msg { - Some(FromNetworkMsg::PeerConnected(peer_id)) => { - protocol.on_peer_connected(&mut Ctxt(&network_sender), peer_id); - CustomMessageOutcome::None - }, - Some(FromNetworkMsg::PeerDisconnected(peer_id)) => { - protocol.on_peer_disconnected(&mut Ctxt(&network_sender), peer_id); - CustomMessageOutcome::None - }, - Some(FromNetworkMsg::CustomMessage(peer_id, message)) => - protocol.on_custom_message( - &mut Ctxt(&network_sender), - &tx_pool, - peer_id, - message, - finality_proof_provider.as_ref().map(|p| &**p) - ), - Some(FromNetworkMsg::Synchronize) => { - let _ = network_sender.unbounded_send(NetworkMsg::Synchronized); - CustomMessageOutcome::None - }, - None => return Ok(Async::Ready(())), - }; - - match outcome { - CustomMessageOutcome::BlockImport(origin, blocks) => - import_queue.lock().import_blocks(origin, blocks), - CustomMessageOutcome::JustificationImport(origin, hash, nb, justification) => - import_queue.lock().import_justification(origin, hash, nb, justification), - CustomMessageOutcome::FinalityProofImport(origin, hash, nb, proof) => - import_queue.lock().import_finality_proof(origin, hash, nb, proof), - CustomMessageOutcome::None => {} - } - } - - loop { - let msg = match protocol_rx.poll() { - Ok(Async::Ready(Some(msg))) => msg, - Ok(Async::Ready(None)) | Err(_) => return Ok(Async::Ready(())), - Ok(Async::NotReady) => break, - }; - - match msg { - ProtocolMsg::BlockImported(hash, header) => - protocol.on_block_imported(&mut Ctxt(&network_sender), hash, &header), - ProtocolMsg::BlockFinalized(hash, header) => - protocol.on_block_finalized(&mut Ctxt(&network_sender), hash, &header), - ProtocolMsg::ExecuteWithSpec(task) => { - let mut ctxt = Ctxt(&network_sender); - let (mut context, spec) = protocol.specialization_lock(&mut ctxt); - task.call_box(spec, &mut context); - }, - ProtocolMsg::ExecuteWithGossip(task) => { - let mut ctxt = Ctxt(&network_sender); - let (mut context, gossip) = protocol.consensus_gossip_lock(&mut ctxt); - task.call_box(gossip, &mut context); - } - ProtocolMsg::GossipConsensusMessage(topic, engine_id, message, recipient) => - protocol.gossip_consensus_message( - &mut Ctxt(&network_sender), - topic, - engine_id, - message, - recipient - ), - ProtocolMsg::BlocksProcessed(hashes, has_error) => - protocol.blocks_processed(&mut Ctxt(&network_sender), hashes, has_error), - ProtocolMsg::RestartSync => - protocol.restart(&mut Ctxt(&network_sender)), - ProtocolMsg::AnnounceBlock(hash) => - protocol.announce_block(&mut Ctxt(&network_sender), hash), - ProtocolMsg::BlockImportedSync(hash, number) => - protocol.block_imported(&hash, number), - ProtocolMsg::ClearJustificationRequests => - protocol.clear_justification_requests(), - ProtocolMsg::RequestJustification(hash, number) => - protocol.request_justification(&mut Ctxt(&network_sender), &hash, number), - ProtocolMsg::JustificationImportResult(hash, number, success) => - protocol.justification_import_result(hash, number, success), - ProtocolMsg::SetFinalityProofRequestBuilder(builder) => - protocol.set_finality_proof_request_builder(builder), - ProtocolMsg::RequestFinalityProof(hash, number) => - protocol.request_finality_proof(&mut Ctxt(&network_sender), &hash, number), - ProtocolMsg::FinalityProofImportResult(requested_block, finalziation_result) => - protocol.finality_proof_import_result(requested_block, finalziation_result), - ProtocolMsg::PropagateExtrinsics => - protocol.propagate_extrinsics(&mut Ctxt(&network_sender), &tx_pool), - #[cfg(any(test, feature = "test-helpers"))] - ProtocolMsg::Tick => protocol.tick(&mut Ctxt(&network_sender)), - #[cfg(any(test, feature = "test-helpers"))] - ProtocolMsg::Synchronize => { - trace!(target: "sync", "handle_client_msg: received Synchronize msg"); - let _ = network_sender.unbounded_send(NetworkMsg::Synchronized); - } - } - } - - if let Async::Ready(_) = protocol.poll(&mut Ctxt(&network_sender), &tx_pool).unwrap() { - return Ok(Async::Ready(())) - } - - *protocol_status.write() = protocol.status(); - Ok(Async::NotReady) - })); - }); - - if self.started() { - peer.start(); - self.peers().iter().for_each(|other| { - other.on_connect(&*peer); - peer.on_connect(other); - }); - } - - self.mut_peers(|peers| { - peers.push(peer) - }); - } - /// Add a full peer. fn add_full_peer(&mut self, config: &ProtocolConfig) { let client = Arc::new(test_client::new()); let verifier = self.make_verifier(PeersClient::Full(client.clone()), config); let (block_import, justification_import, finality_proof_import, finality_proof_request_builder, data) = self.make_block_import(PeersClient::Full(client.clone())); - let (network_sender, network_port) = mpsc::unbounded(); + let block_import = BlockImportAdapter(Arc::new(Mutex::new(block_import))); - let import_queue = Arc::new(Mutex::new(Box::new(BasicQueue::new( - verifier, - block_import, + let import_queue = Box::new(BasicQueue::new( + verifier.clone(), + Box::new(block_import.clone()), justification_import, finality_proof_import, + )); + + let listen_addr = build_multiaddr![Memory(rand::random::())]; + + let network = NetworkWorker::new(crate::config::Params { + roles: config.roles, + network_config: NetworkConfiguration { + listen_addresses: vec![listen_addr.clone()], + transport: TransportConfig::MemoryOnly, + ..NetworkConfiguration::default() + }, + chain: client.clone(), + finality_proof_provider: self.make_finality_proof_provider(PeersClient::Full(client.clone())), finality_proof_request_builder, - )))); - let specialization = self::SpecializationFactory::create(); - - let (network_to_protocol_sender, network_to_protocol_rx) = mpsc::unbounded(); - let (protocol_sender, protocol_rx) = mpsc::unbounded(); - - let protocol = Protocol::new( - config.clone(), - client.clone(), - Arc::new(AlwaysBadChecker), - specialization, - ).unwrap(); - - let protocol_status = Arc::new(RwLock::new(protocol.status())); - self.add_peer( - protocol_status.clone(), - import_queue.clone(), - EmptyTransactionPool, - self.make_finality_proof_provider(PeersClient::Full(client.clone())), - protocol, - protocol_sender.clone(), - network_to_protocol_sender.clone(), - network_sender.clone(), - network_to_protocol_rx, - protocol_rx, - Arc::new(Peer::new( - protocol_status, - PeersClient::Full(client), - import_queue, - self.uses_tokio(), - network_to_protocol_sender, - protocol_sender, - network_sender, - network_port, + on_demand: None, + transaction_pool: Arc::new(EmptyTransactionPool), + protocol_id: ProtocolId::from(&b"test-protocol-name"[..]), + import_queue, + specialization: self::SpecializationFactory::create(), + }).unwrap(); + + self.mut_peers(|peers| { + for peer in peers.iter_mut() { + peer.network.add_known_address(network.service().local_peer_id(), listen_addr.clone()); + } + + let imported_blocks_stream = Box::new(client.import_notification_stream() + .map(|v| Ok::<_, ()>(v)).compat().fuse()); + let finality_notification_stream = Box::new(client.finality_notification_stream() + .map(|v| Ok::<_, ()>(v)).compat().fuse()); + + peers.push(Peer { data, - )), - ); + client: PeersClient::Full(client), + imported_blocks_stream, + finality_notification_stream, + block_import: Box::new(block_import), + verifier, + network, + }); + }); } /// Add a light peer. @@ -1089,188 +509,107 @@ pub trait TestNetFactory: Sized { let verifier = self.make_verifier(PeersClient::Light(client.clone()), &config); let (block_import, justification_import, finality_proof_import, finality_proof_request_builder, data) = self.make_block_import(PeersClient::Light(client.clone())); - let (network_sender, network_port) = mpsc::unbounded(); + let block_import = BlockImportAdapter(Arc::new(Mutex::new(block_import))); - let import_queue = Arc::new(Mutex::new(Box::new(BasicQueue::new( - verifier, - block_import, + let import_queue = Box::new(BasicQueue::new( + verifier.clone(), + Box::new(block_import.clone()), justification_import, finality_proof_import, + )); + + let listen_addr = build_multiaddr![Memory(rand::random::())]; + + let network = NetworkWorker::new(crate::config::Params { + roles: config.roles, + network_config: NetworkConfiguration { + listen_addresses: vec![listen_addr.clone()], + transport: TransportConfig::MemoryOnly, + ..NetworkConfiguration::default() + }, + chain: client.clone(), + finality_proof_provider: self.make_finality_proof_provider(PeersClient::Light(client.clone())), finality_proof_request_builder, - )))); - let specialization = self::SpecializationFactory::create(); - - let (network_to_protocol_sender, network_to_protocol_rx) = mpsc::unbounded(); - let (protocol_sender, protocol_rx) = mpsc::unbounded(); - - let protocol = Protocol::new( - config, - client.clone(), - Arc::new(AlwaysBadChecker), - specialization, - ).unwrap(); - - let protocol_status = Arc::new(RwLock::new(protocol.status())); - self.add_peer( - protocol_status.clone(), - import_queue.clone(), - EmptyTransactionPool, - self.make_finality_proof_provider(PeersClient::Light(client.clone())), - protocol, - protocol_sender.clone(), - network_to_protocol_sender.clone(), - network_sender.clone(), - network_to_protocol_rx, - protocol_rx, - Arc::new(Peer::new( - protocol_status, - PeersClient::Light(client), - import_queue, - self.uses_tokio(), - network_to_protocol_sender, - protocol_sender, - network_sender, - network_port, - data, - )), - ); - } + on_demand: None, + transaction_pool: Arc::new(EmptyTransactionPool), + protocol_id: ProtocolId::from(&b"test-protocol-name"[..]), + import_queue, + specialization: self::SpecializationFactory::create(), + }).unwrap(); - /// Start network. - fn start(&mut self) { - if self.started() { - return; - } - for peer in self.peers() { - peer.start(); - for client in self.peers() { - if peer.peer_id != client.peer_id { - peer.on_connect(client); - } + self.mut_peers(|peers| { + for peer in peers.iter_mut() { + peer.network.add_known_address(network.service().local_peer_id(), listen_addr.clone()); } - } - loop { - // we only deliver Status messages during start - let need_continue = self.route_single(true, None, &|msg| match *msg { - NetworkMsg::Outgoing(_, crate::message::generic::Message::Status(_)) => true, - NetworkMsg::Outgoing(_, _) => false, - NetworkMsg::DisconnectPeer(_) | - NetworkMsg::ReportPeer(_, _) | NetworkMsg::Synchronized => true, - }); - if !need_continue { - break; - } - } + let imported_blocks_stream = Box::new(client.import_notification_stream() + .map(|v| Ok::<_, ()>(v)).compat().fuse()); + let finality_notification_stream = Box::new(client.finality_notification_stream() + .map(|v| Ok::<_, ()>(v)).compat().fuse()); - self.set_started(true); + peers.push(Peer { + data, + verifier, + block_import: Box::new(block_import), + client: PeersClient::Light(client), + imported_blocks_stream, + finality_notification_stream, + network, + }); + }); } - /// Do single round of message routing: single message from every peer is routed. - fn route_single( - &mut self, - disconnect: bool, - disconnected: Option>, - message_filter: &MessageFilter, - ) -> bool { - let mut had_messages = false; - let mut to_disconnect = HashSet::new(); - let peers = self.peers(); - for peer in peers { - if let Some(message) = peer.pending_message(message_filter) { - match message { - NetworkMsg::Outgoing(recipient_id, packet) => { - had_messages = true; - - let sender_pos = peers.iter().position(|p| p.peer_id == peer.peer_id).unwrap(); - let recipient_pos = peers.iter().position(|p| p.peer_id == recipient_id).unwrap(); - if disconnect { - if let Some(ref disconnected) = disconnected { - let mut current = HashSet::new(); - current.insert(sender_pos); - current.insert(recipient_pos); - // Not routing message between "disconnected" nodes. - if disconnected.is_subset(¤t) { - continue; - } - } - } - - peers[recipient_pos].receive_message(&peer.peer_id, packet); - }, - NetworkMsg::DisconnectPeer(who) => { - if disconnect { - to_disconnect.insert(who); - } - }, - _ => (), - } - } - } - - for d in to_disconnect { - if let Some(d) = peers.iter().find(|p| p.peer_id == d) { - for peer in 0..peers.len() { - peers[peer].on_disconnect(d); - } + /// Polls the testnet until all nodes are in sync. + /// + /// Must be executed in a task context. + fn poll_until_sync(&mut self) -> Async<()> { + self.poll(); + + // Return `NotReady` if there's a mismatch in the highest block number. + let mut highest = None; + for peer in self.peers().iter() { + match (highest, peer.client.info().chain.best_number) { + (None, b) => highest = Some(b), + (Some(ref a), ref b) if a == b => {}, + (Some(_), _) => return Async::NotReady, } } - - // make sure that the protocol(s) has processed all messages that have been queued - self.peers().iter().for_each(|peer| peer.import_queue_sync()); - - had_messages - } - - /// Send block import notifications for all peers. - fn send_import_notifications(&mut self) { - self.peers().iter().for_each(|peer| peer.send_import_notifications()) - } - - /// Send block finalization notifications for all peers. - fn send_finality_notifications(&mut self) { - self.peers().iter().for_each(|peer| peer.send_finality_notifications()) + Async::Ready(()) } - /// Perform synchronization until complete, if provided the - /// given nodes set are excluded from sync. - fn sync_with(&mut self, disconnect: bool, disconnected: Option>) { - self.start(); - while self.route_single(disconnect, disconnected.clone(), &|_| true) { - // give protocol a chance to do its maintain procedures - self.peers().iter().for_each(|peer| peer.sync_step()); - } - } - - /// Deliver at most 1 pending message from every peer. - fn sync_step(&mut self) { - self.route_single(true, None, &|_| true); - } - - /// Maintain sync for a peer. - fn tick_peer(&mut self, i: usize) { - self.peers()[i].sync_step(); + /// Blocks the current thread until we are sync'ed. + /// + /// Calls `poll_until_sync` repeatidely with the runtime passed as parameter. + fn block_until_sync(&mut self, runtime: &mut tokio::runtime::current_thread::Runtime) { + runtime.block_on(futures::future::poll_fn::<(), (), _>(|| Ok(self.poll_until_sync()))).unwrap(); } - /// Deliver pending messages until there are no more. - fn sync(&mut self) { - self.sync_with(true, None) - } + /// Polls the testnet. Processes all the pending actions and returns `NotReady`. + fn poll(&mut self) { + self.mut_peers(|peers| { + for peer in peers { + peer.network.poll().unwrap(); - /// Deliver pending messages until there are no more. Do not disconnect nodes. - fn sync_without_disconnects(&mut self) { - self.sync_with(false, None) - } + // We poll `imported_blocks_stream`. + while let Ok(Async::Ready(Some(notification))) = peer.imported_blocks_stream.poll() { + peer.network.on_block_imported(notification.hash, notification.header); + } - /// Whether all peers have no pending outgoing messages. - fn done(&self) -> bool { - self.peers().iter().all(|p| p.is_done()) + // We poll `finality_notification_stream`, but we only take the last event. + let mut last = None; + while let Ok(Async::Ready(Some(item))) = peer.finality_notification_stream.poll() { + last = Some(item); + } + if let Some(notification) = last { + peer.network.on_block_finalized(notification.hash, notification.header); + } + } + }); } } pub struct TestNet { - peers: Vec>>, - started: bool, + peers: Vec>, } impl TestNetFactory for TestNet { @@ -1282,7 +621,6 @@ impl TestNetFactory for TestNet { fn from_config(_config: &ProtocolConfig) -> Self { TestNet { peers: Vec::new(), - started: false } } @@ -1292,25 +630,17 @@ impl TestNetFactory for TestNet { Arc::new(PassThroughVerifier(false)) } - fn peer(&self, i: usize) -> &Peer<(), Self::Specialization> { - &self.peers[i] + fn peer(&mut self, i: usize) -> &mut Peer<(), Self::Specialization> { + &mut self.peers[i] } - fn peers(&self) -> &Vec>> { + fn peers(&self) -> &Vec> { &self.peers } - fn mut_peers>>)>(&mut self, closure: F) { + fn mut_peers>)>(&mut self, closure: F) { closure(&mut self.peers); } - - fn started(&self) -> bool { - self.started - } - - fn set_started(&mut self, new: bool) { - self.started = new; - } } pub struct ForceFinalized(PeersClient); @@ -1319,7 +649,7 @@ impl JustificationImport for ForceFinalized { type Error = ConsensusError; fn import_justification( - &self, + &mut self, hash: H256, _number: NumberFor, justification: Justification, @@ -1346,35 +676,27 @@ impl TestNetFactory for JustificationTestNet { self.0.make_verifier(client, config) } - fn peer(&self, i: usize) -> &Peer { + fn peer(&mut self, i: usize) -> &mut Peer { self.0.peer(i) } - fn peers(&self) -> &Vec>> { + fn peers(&self) -> &Vec> { self.0.peers() } - fn mut_peers>>)>(&mut self, closure: F) { + fn mut_peers>)>(&mut self, closure: F) { self.0.mut_peers(closure) } - fn started(&self) -> bool { - self.0.started() - } - - fn set_started(&mut self, new: bool) { - self.0.set_started(new) - } - fn make_block_import(&self, client: PeersClient) -> ( - SharedBlockImport, - Option>, - Option>, - Option>, + BoxBlockImport, + Option>, + Option>, + Option>, Self::PeerData, ) { - (client.as_block_import(), Some(Arc::new(ForceFinalized(client))), None, None, Default::default()) + (client.as_block_import(), Some(Box::new(ForceFinalized(client))), None, None, Default::default()) } } diff --git a/core/network/src/test/sync.rs b/core/network/src/test/sync.rs index 1e9e2948f3a1cf7b1761a2d29838b41849ca1df1..a7603f755191c7c5a67ad89a3f20efa6ed90fb1f 100644 --- a/core/network/src/test/sync.rs +++ b/core/network/src/test/sync.rs @@ -16,13 +16,14 @@ use client::{backend::Backend, blockchain::HeaderBackend}; use crate::config::Roles; -use crate::message; use consensus::BlockOrigin; -use std::collections::HashSet; +use std::{time::Duration, time::Instant}; +use tokio::runtime::current_thread; use super::*; fn test_ancestor_search_when_common_is(n: usize) { let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let mut net = TestNet::new(3); net.peer(0).push_blocks(n, false); @@ -33,7 +34,7 @@ fn test_ancestor_search_when_common_is(n: usize) { net.peer(1).push_blocks(100, false); net.peer(2).push_blocks(100, false); - net.sync(); + net.block_until_sync(&mut runtime); assert!(net.peer(0).client.as_in_memory_backend().blockchain() .canon_equals_to(net.peer(1).client.as_in_memory_backend().blockchain())); } @@ -41,29 +42,24 @@ fn test_ancestor_search_when_common_is(n: usize) { #[test] fn sync_peers_works() { let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let mut net = TestNet::new(3); - net.sync(); - for peer in 0..3 { - // Assert peers is up to date. - assert_eq!(net.peer(peer).protocol_status.read().num_peers, 2); - // And then disconnect. - for other in 0..3 { - if other != peer { - net.peer(peer).on_disconnect(net.peer(other)); + + runtime.block_on(futures::future::poll_fn::<(), (), _>(|| -> Result<_, ()> { + net.poll(); + for peer in 0..3 { + if net.peer(peer).num_peers() != 2 { + return Ok(Async::NotReady) } } - } - net.sync(); - // Now peers are disconnected. - for peer in 0..3 { - let status = net.peer(peer).protocol_status.read(); - assert_eq!(status.num_peers, 0); - } + Ok(Async::Ready(())) + })).unwrap(); } #[test] fn sync_cycle_from_offline_to_syncing_to_offline() { let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let mut net = TestNet::new(3); for peer in 0..3 { // Offline, and not major syncing. @@ -73,63 +69,92 @@ fn sync_cycle_from_offline_to_syncing_to_offline() { // Generate blocks. net.peer(2).push_blocks(100, false); - net.start(); - for peer in 0..3 { - // Online - assert!(!net.peer(peer).is_offline()); - if peer < 2 { - // Major syncing. - assert!(net.peer(peer).is_major_syncing()); - } - } - net.sync(); - for peer in 0..3 { - // All done syncing. - assert!(!net.peer(peer).is_major_syncing()); - } - // Now disconnect them all. - for peer in 0..3 { - for other in 0..3 { - if other != peer { - net.peer(peer).on_disconnect(net.peer(other)); + // Block until all nodes are online and nodes 0 and 1 and major syncing. + runtime.block_on(futures::future::poll_fn::<(), (), _>(|| -> Result<_, ()> { + net.poll(); + for peer in 0..3 { + // Online + if net.peer(peer).is_offline() { + return Ok(Async::NotReady) + } + if peer < 2 { + // Major syncing. + if !net.peer(peer).is_major_syncing() { + return Ok(Async::NotReady) + } } } - net.sync(); - assert!(net.peer(peer).is_offline()); - assert!(!net.peer(peer).is_major_syncing()); - } + Ok(Async::Ready(())) + })).unwrap(); + + // Block until all nodes are done syncing. + runtime.block_on(futures::future::poll_fn::<(), (), _>(|| -> Result<_, ()> { + net.poll(); + for peer in 0..3 { + if net.peer(peer).is_major_syncing() { + return Ok(Async::NotReady) + } + } + Ok(Async::Ready(())) + })).unwrap(); + + // Now drop nodes 1 and 2, and check that node 0 is offline. + net.peers.remove(2); + net.peers.remove(1); + runtime.block_on(futures::future::poll_fn::<(), (), _>(|| -> Result<_, ()> { + net.poll(); + if !net.peer(0).is_offline() { + Ok(Async::NotReady) + } else { + Ok(Async::Ready(())) + } + })).unwrap(); } #[test] fn syncing_node_not_major_syncing_when_disconnected() { let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let mut net = TestNet::new(3); // Generate blocks. net.peer(2).push_blocks(100, false); - net.start(); - net.sync_step(); - - // Peer 1 is major-syncing. - assert!(net.peer(1).is_major_syncing()); - - // Disconnect peer 1 form everyone else. - net.peer(1).on_disconnect(net.peer(0)); - net.peer(1).on_disconnect(net.peer(2)); - // Peer 1 is not major-syncing. - net.sync(); + // Check that we're not major syncing when disconnected. assert!(!net.peer(1).is_major_syncing()); + + // Check that we switch to major syncing. + runtime.block_on(futures::future::poll_fn::<(), (), _>(|| -> Result<_, ()> { + net.poll(); + if !net.peer(1).is_major_syncing() { + Ok(Async::NotReady) + } else { + Ok(Async::Ready(())) + } + })).unwrap(); + + // Destroy two nodes, and check that we switch to non-major syncing. + net.peers.remove(2); + net.peers.remove(0); + runtime.block_on(futures::future::poll_fn::<(), (), _>(|| -> Result<_, ()> { + net.poll(); + if net.peer(0).is_major_syncing() { + Ok(Async::NotReady) + } else { + Ok(Async::Ready(())) + } + })).unwrap(); } #[test] fn sync_from_two_peers_works() { let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let mut net = TestNet::new(3); net.peer(1).push_blocks(100, false); net.peer(2).push_blocks(100, false); - net.sync(); + net.block_until_sync(&mut runtime); assert!(net.peer(0).client.as_in_memory_backend().blockchain() .equals_to(net.peer(1).client.as_in_memory_backend().blockchain())); assert!(!net.peer(0).is_major_syncing()); @@ -138,11 +163,12 @@ fn sync_from_two_peers_works() { #[test] fn sync_from_two_peers_with_ancestry_search_works() { let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let mut net = TestNet::new(3); net.peer(0).push_blocks(10, true); net.peer(1).push_blocks(100, false); net.peer(2).push_blocks(100, false); - net.sync(); + net.block_until_sync(&mut runtime); assert!(net.peer(0).client.as_in_memory_backend().blockchain() .canon_equals_to(net.peer(1).client.as_in_memory_backend().blockchain())); } @@ -150,13 +176,14 @@ fn sync_from_two_peers_with_ancestry_search_works() { #[test] fn ancestry_search_works_when_backoff_is_one() { let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let mut net = TestNet::new(3); net.peer(0).push_blocks(1, false); net.peer(1).push_blocks(2, false); net.peer(2).push_blocks(2, false); - net.sync(); + net.block_until_sync(&mut runtime); assert!(net.peer(0).client.as_in_memory_backend().blockchain() .canon_equals_to(net.peer(1).client.as_in_memory_backend().blockchain())); } @@ -164,13 +191,14 @@ fn ancestry_search_works_when_backoff_is_one() { #[test] fn ancestry_search_works_when_ancestor_is_genesis() { let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let mut net = TestNet::new(3); net.peer(0).push_blocks(13, true); net.peer(1).push_blocks(100, false); net.peer(2).push_blocks(100, false); - net.sync(); + net.block_until_sync(&mut runtime); assert!(net.peer(0).client.as_in_memory_backend().blockchain() .canon_equals_to(net.peer(1).client.as_in_memory_backend().blockchain())); } @@ -192,9 +220,11 @@ fn ancestry_search_works_when_common_is_hundred() { #[test] fn sync_long_chain_works() { + let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let mut net = TestNet::new(2); net.peer(1).push_blocks(500, false); - net.sync(); + net.block_until_sync(&mut runtime); assert!(net.peer(0).client.as_in_memory_backend().blockchain() .equals_to(net.peer(1).client.as_in_memory_backend().blockchain())); } @@ -202,10 +232,11 @@ fn sync_long_chain_works() { #[test] fn sync_no_common_longer_chain_fails() { let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let mut net = TestNet::new(3); net.peer(0).push_blocks(20, true); net.peer(1).push_blocks(20, false); - net.sync(); + net.block_until_sync(&mut runtime); assert!(!net.peer(0).client.as_in_memory_backend().blockchain() .canon_equals_to(net.peer(1).client.as_in_memory_backend().blockchain())); } @@ -213,9 +244,10 @@ fn sync_no_common_longer_chain_fails() { #[test] fn sync_justifications() { let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let mut net = JustificationTestNet::new(3); net.peer(0).push_blocks(20, false); - net.sync(); + net.block_until_sync(&mut runtime); // there's currently no justification for block #10 assert_eq!(net.peer(0).client().justification(&BlockId::Number(10)).unwrap(), None); @@ -235,17 +267,26 @@ fn sync_justifications() { net.peer(1).request_justification(&h2.hash().into(), 15); net.peer(1).request_justification(&h3.hash().into(), 20); - net.sync(); + runtime.block_on(futures::future::poll_fn::<(), (), _>(|| { + net.poll(); - for height in (10..21).step_by(5) { - assert_eq!(net.peer(0).client().justification(&BlockId::Number(height)).unwrap(), Some(Vec::new())); - assert_eq!(net.peer(1).client().justification(&BlockId::Number(height)).unwrap(), Some(Vec::new())); - } + for height in (10..21).step_by(5) { + if net.peer(0).client().justification(&BlockId::Number(height)).unwrap() != Some(Vec::new()) { + return Ok(Async::NotReady); + } + if net.peer(1).client().justification(&BlockId::Number(height)).unwrap() != Some(Vec::new()) { + return Ok(Async::NotReady); + } + } + + Ok(Async::Ready(())) + })).unwrap(); } #[test] fn sync_justifications_across_forks() { let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let mut net = JustificationTestNet::new(3); // we push 5 blocks net.peer(0).push_blocks(5, false); @@ -255,24 +296,31 @@ fn sync_justifications_across_forks() { // peer 1 will only see the longer fork. but we'll request justifications // for both and finalize the small fork instead. - net.sync(); + net.block_until_sync(&mut runtime); net.peer(0).client().finalize_block(BlockId::Hash(f1_best), Some(Vec::new()), true).unwrap(); net.peer(1).request_justification(&f1_best, 10); net.peer(1).request_justification(&f2_best, 11); - net.sync(); + runtime.block_on(futures::future::poll_fn::<(), (), _>(|| { + net.poll(); - assert_eq!(net.peer(0).client().justification(&BlockId::Number(10)).unwrap(), Some(Vec::new())); - assert_eq!(net.peer(1).client().justification(&BlockId::Number(10)).unwrap(), Some(Vec::new())); + if net.peer(0).client().justification(&BlockId::Number(10)).unwrap() == Some(Vec::new()) && + net.peer(1).client().justification(&BlockId::Number(10)).unwrap() == Some(Vec::new()) + { + Ok(Async::Ready(())) + } else { + Ok(Async::NotReady) + } + })).unwrap(); } #[test] fn sync_after_fork_works() { let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let mut net = TestNet::new(3); - net.sync_step(); net.peer(0).push_blocks(30, false); net.peer(1).push_blocks(30, false); net.peer(2).push_blocks(30, false); @@ -286,7 +334,7 @@ fn sync_after_fork_works() { // peer 1 has the best chain let peer1_chain = net.peer(1).client.as_in_memory_backend().blockchain().clone(); - net.sync(); + net.block_until_sync(&mut runtime); assert!(net.peer(0).client.as_in_memory_backend().blockchain().canon_equals_to(&peer1_chain)); assert!(net.peer(1).client.as_in_memory_backend().blockchain().canon_equals_to(&peer1_chain)); assert!(net.peer(2).client.as_in_memory_backend().blockchain().canon_equals_to(&peer1_chain)); @@ -295,15 +343,15 @@ fn sync_after_fork_works() { #[test] fn syncs_all_forks() { let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let mut net = TestNet::new(4); - net.sync_step(); net.peer(0).push_blocks(2, false); net.peer(1).push_blocks(2, false); net.peer(0).push_blocks(2, true); net.peer(1).push_blocks(4, false); - net.sync(); + net.block_until_sync(&mut runtime); // Check that all peers have all of the blocks. assert_eq!(9, net.peer(0).client.as_in_memory_backend().blockchain().blocks_count()); assert_eq!(9, net.peer(1).client.as_in_memory_backend().blockchain().blocks_count()); @@ -312,13 +360,12 @@ fn syncs_all_forks() { #[test] fn own_blocks_are_announced() { let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let mut net = TestNet::new(3); - net.sync(); // connect'em + net.block_until_sync(&mut runtime); // connect'em net.peer(0).generate_blocks(1, BlockOrigin::Own, |builder| builder.bake().unwrap()); - let header = net.peer(0).client().header(&BlockId::Number(1)).unwrap().unwrap(); - net.peer(0).on_block_imported(header.hash(), &header); - net.sync(); + net.block_until_sync(&mut runtime); assert_eq!(net.peer(0).client.as_in_memory_backend().blockchain().info().best_number, 1); assert_eq!(net.peer(1).client.as_in_memory_backend().blockchain().info().best_number, 1); @@ -330,6 +377,7 @@ fn own_blocks_are_announced() { #[test] fn blocks_are_not_announced_by_light_nodes() { let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let mut net = TestNet::new(0); // full peer0 is connected to light peer @@ -337,35 +385,32 @@ fn blocks_are_not_announced_by_light_nodes() { let mut light_config = ProtocolConfig::default(); light_config.roles = Roles::LIGHT; net.add_full_peer(&ProtocolConfig::default()); - net.add_full_peer(&light_config); - net.add_full_peer(&ProtocolConfig::default()); + net.add_light_peer(&light_config); + // Sync between 0 and 1. net.peer(0).push_blocks(1, false); - net.peer(0).start(); - net.peer(1).start(); - net.peer(2).start(); - net.peer(0).on_connect(net.peer(1)); - net.peer(1).on_connect(net.peer(2)); - - // Only sync between 0 -> 1, and 1 -> 2 - let mut disconnected = HashSet::new(); - disconnected.insert(0); - disconnected.insert(2); - net.sync_with(true, Some(disconnected)); - - // peer 0 has the best chain - // peer 1 has the best chain - // peer 2 has genesis-chain only assert_eq!(net.peer(0).client.info().chain.best_number, 1); + net.block_until_sync(&mut runtime); assert_eq!(net.peer(1).client.info().chain.best_number, 1); - assert_eq!(net.peer(2).client.info().chain.best_number, 0); + + // Add another node and remove node 0. + net.add_full_peer(&ProtocolConfig::default()); + net.peers.remove(0); + + // Poll for a few seconds and make sure 1 and 2 (now 0 and 1) don't sync together. + let mut delay = tokio_timer::Delay::new(Instant::now() + Duration::from_secs(5)); + runtime.block_on(futures::future::poll_fn::<(), (), _>(|| { + net.poll(); + delay.poll().map_err(|_| ()) + })).unwrap(); + assert_eq!(net.peer(1).client.info().chain.best_number, 0); } #[test] fn can_sync_small_non_best_forks() { let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); let mut net = TestNet::new(2); - net.sync_step(); net.peer(0).push_blocks(30, false); net.peer(1).push_blocks(30, false); @@ -382,7 +427,15 @@ fn can_sync_small_non_best_forks() { assert!(net.peer(0).client().header(&BlockId::Hash(small_hash)).unwrap().is_some()); assert!(net.peer(1).client().header(&BlockId::Hash(small_hash)).unwrap().is_none()); - net.sync(); + // poll until the two nodes connect, otherwise announcing the block will not work + runtime.block_on(futures::future::poll_fn::<(), (), _>(|| -> Result<_, ()> { + net.poll(); + if net.peer(0).num_peers() == 0 { + Ok(Async::NotReady) + } else { + Ok(Async::Ready(())) + } + })).unwrap(); // synchronization: 0 synced to longer chain and 1 didn't sync to small chain. @@ -392,17 +445,24 @@ fn can_sync_small_non_best_forks() { assert!(!net.peer(1).client().header(&BlockId::Hash(small_hash)).unwrap().is_some()); net.peer(0).announce_block(small_hash); - net.sync(); // after announcing, peer 1 downloads the block. - assert!(net.peer(0).client().header(&BlockId::Hash(small_hash)).unwrap().is_some()); - assert!(net.peer(1).client().header(&BlockId::Hash(small_hash)).unwrap().is_some()); + runtime.block_on(futures::future::poll_fn::<(), (), _>(|| -> Result<_, ()> { + net.poll(); + + assert!(net.peer(0).client().header(&BlockId::Hash(small_hash)).unwrap().is_some()); + if net.peer(1).client().header(&BlockId::Hash(small_hash)).unwrap().is_none() { + return Ok(Async::NotReady) + } + Ok(Async::Ready(())) + })).unwrap(); } #[test] fn can_not_sync_from_light_peer() { let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); // given the network with 1 full nodes (#0) and 1 light node (#1) let mut net = TestNet::new(1); @@ -412,8 +472,7 @@ fn can_not_sync_from_light_peer() { net.peer(0).push_blocks(1, false); // and let the light client sync from this node - // (mind the #1 is disconnected && not syncing) - net.sync(); + net.block_until_sync(&mut runtime); // ensure #0 && #1 have the same best block let full0_info = net.peer(0).client.info().chain; @@ -422,52 +481,34 @@ fn can_not_sync_from_light_peer() { assert_eq!(light_info.best_number, 1); assert_eq!(light_info.best_hash, full0_info.best_hash); - // add new full client (#2) && sync without #0 + // add new full client (#2) && remove #0 net.add_full_peer(&Default::default()); - net.peer(1).on_connect(net.peer(2)); - net.peer(2).on_connect(net.peer(1)); - net.peer(1).announce_block(light_info.best_hash); - net.sync_with(true, Some(vec![0].into_iter().collect())); - - // ensure that the #2 has failed to sync block #1 - assert_eq!(net.peer(2).client.info().chain.best_number, 0); - // and that the #1 is still connected to #2 - // (because #2 has not tried to fetch block data from the #1 light node) - assert_eq!(net.peer(1).protocol_status().num_peers, 2); - - // and now try to fetch block data from light peer #1 - // (this should result in disconnect) - net.peer(1).receive_message( - &net.peer(2).peer_id, - message::generic::Message::BlockRequest(message::generic::BlockRequest { - id: 0, - fields: message::BlockAttributes::HEADER, - from: message::FromBlock::Hash(light_info.best_hash), - to: None, - direction: message::Direction::Ascending, - max: Some(1), - }), - ); - net.sync(); - // check that light #1 has disconnected from #2 - assert_eq!(net.peer(1).protocol_status().num_peers, 1); + net.peers.remove(0); + + // ensure that the #2 (now #1) fails to sync block #1 even after 5 seconds + let mut test_finished = tokio_timer::Delay::new(Instant::now() + Duration::from_secs(5)); + runtime.block_on(futures::future::poll_fn::<(), (), _>(|| -> Result<_, ()> { + net.poll(); + test_finished.poll().map_err(|_| ()) + })).unwrap(); } #[test] fn light_peer_imports_header_from_announce() { let _ = ::env_logger::try_init(); + let mut runtime = current_thread::Runtime::new().unwrap(); - fn import_with_announce(net: &mut TestNet, hash: H256) { - let header = net.peer(0).client().header(&BlockId::Hash(hash)).unwrap().unwrap(); - net.peer(1).receive_message( - &net.peer(0).peer_id, - message::generic::Message::BlockAnnounce(message::generic::BlockAnnounce { - header, - }), - ); - - net.peer(1).import_queue_sync(); - assert!(net.peer(1).client().header(&BlockId::Hash(hash)).unwrap().is_some()); + fn import_with_announce(net: &mut TestNet, runtime: &mut current_thread::Runtime, hash: H256) { + net.peer(0).announce_block(hash); + + runtime.block_on(futures::future::poll_fn::<(), (), _>(|| { + net.poll(); + if net.peer(1).client().header(&BlockId::Hash(hash)).unwrap().is_some() { + Ok(Async::Ready(())) + } else { + Ok(Async::NotReady) + } + })).unwrap(); } // given the network with 1 full nodes (#0) and 1 light node (#1) @@ -475,13 +516,13 @@ fn light_peer_imports_header_from_announce() { net.add_light_peer(&Default::default()); // let them connect to each other - net.sync(); + net.block_until_sync(&mut runtime); // check that NEW block is imported from announce message let new_hash = net.peer(0).push_blocks(1, false); - import_with_announce(&mut net, new_hash); + import_with_announce(&mut net, &mut runtime, new_hash); // check that KNOWN STALE block is imported from announce message let known_stale_hash = net.peer(0).push_blocks_at(BlockId::Number(0), 1, true); - import_with_announce(&mut net, known_stale_hash); + import_with_announce(&mut net, &mut runtime, known_stale_hash); } diff --git a/core/network/src/transport.rs b/core/network/src/transport.rs index ac6cc633a8c017c60bafb47d8f8db14258664ec7..901ec18581e1d3e851034bb8a97e9154c786890d 100644 --- a/core/network/src/transport.rs +++ b/core/network/src/transport.rs @@ -30,10 +30,14 @@ pub use self::bandwidth::BandwidthSinks; /// Builds the transport that serves as a common ground for all connections. /// +/// If `memory_only` is true, then only communication within the same process are allowed. Only +/// addresses with the format `/memory/...` are allowed. +/// /// Returns a `BandwidthSinks` object that allows querying the average bandwidth produced by all /// the connections spawned with this transport. pub fn build_transport( keypair: identity::Keypair, + memory_only: bool, wasm_external_transport: Option ) -> (Boxed<(PeerId, StreamMuxerBox), io::Error>, Arc) { // Build configuration objects for encryption mechanisms. @@ -63,12 +67,21 @@ pub fn build_transport( OptionalTransport::none() }; #[cfg(not(target_os = "unknown"))] - let transport = { + let transport = transport.or_transport(if !memory_only { let desktop_trans = tcp::TcpConfig::new(); let desktop_trans = websocket::WsConfig::new(desktop_trans.clone()) .or_transport(desktop_trans); - transport.or_transport(dns::DnsConfig::new(desktop_trans)) - }; + OptionalTransport::some(dns::DnsConfig::new(desktop_trans)) + } else { + OptionalTransport::none() + }); + + let transport = transport.or_transport(if memory_only { + OptionalTransport::some(libp2p::core::transport::MemoryTransport::default()) + } else { + OptionalTransport::none() + }); + let (transport, sinks) = bandwidth::BandwidthLogging::new(transport, Duration::from_secs(5)); // Encryption diff --git a/core/offchain/Cargo.toml b/core/offchain/Cargo.toml index a7b94bdc567e81c797dafe055d85a8d161e0393f..758865b49c423effe51db083344ff8f50f7ab6d6 100644 --- a/core/offchain/Cargo.toml +++ b/core/offchain/Cargo.toml @@ -8,20 +8,20 @@ edition = "2018" [dependencies] client = { package = "substrate-client", path = "../../core/client" } -consensus = { package = "substrate-consensus-common", path = "../../core/consensus/common" } futures = "0.1.25" log = "0.4" offchain-primitives = { package = "substrate-offchain-primitives", path = "./primitives" } -parity-codec = { version = "3.3", features = ["derive"] } +parity-codec = { version = "4.1.1", features = ["derive"] } parking_lot = "0.8.0" primitives = { package = "substrate-primitives", path = "../../core/primitives" } runtime_primitives = { package = "sr-primitives", path = "../../core/sr-primitives" } -tokio = "0.1.7" transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" } [dev-dependencies] env_logger = "0.6" +client-db = { package = "substrate-client-db", path = "../../core/client/db/", default-features = true } test-client = { package = "substrate-test-runtime-client", path = "../../core/test-runtime/client" } +tokio = "0.1.7" [features] default = [] diff --git a/core/offchain/src/api.rs b/core/offchain/src/api.rs index d2c7630c249d8adaebd770899b5d0a802e85f5c6..b6aba784b36a97c047178e89703179829daf1f54 100644 --- a/core/offchain/src/api.rs +++ b/core/offchain/src/api.rs @@ -15,14 +15,19 @@ // along with Substrate. If not, see . use std::sync::Arc; +use client::backend::OffchainStorage; +use crate::AuthorityKeyProvider; use futures::{Stream, Future, sync::mpsc}; use log::{info, debug, warn, error}; -use parity_codec::Decode; +use parity_codec::{Encode, Decode}; use primitives::offchain::{ Timestamp, HttpRequestId, HttpRequestStatus, HttpError, Externalities as OffchainExt, CryptoKind, CryptoKeyId, + StorageKind, }; +use primitives::crypto::{Pair, Protected}; +use primitives::{ed25519, sr25519}; use runtime_primitives::{ generic::BlockId, traits::{self, Extrinsic}, @@ -34,47 +39,152 @@ enum ExtMessage { SubmitExtrinsic(Vec), } +/// A persisted key seed. +#[derive(Encode, Decode)] +struct CryptoKey { + kind: CryptoKind, + phrase: String, +} + +enum Key { + Sr25519(sr25519::Pair), + Ed25519(ed25519::Pair), +} + /// Asynchronous offchain API. /// /// NOTE this is done to prevent recursive calls into the runtime (which are not supported currently). -pub(crate) struct AsyncApi(mpsc::UnboundedSender); +pub(crate) struct Api { + sender: mpsc::UnboundedSender, + db: Storage, + keys_password: Protected, + key_provider: KeyProvider, +} fn unavailable_yet(name: &str) -> R { - error!("This {:?} API is not available for offchain workers yet. Follow + error!("The {:?} API is not available for offchain workers yet. Follow \ https://github.com/paritytech/substrate/issues/1458 for details", name); Default::default() } -impl OffchainExt for AsyncApi { +const LOCAL_DB: &str = "LOCAL (fork-aware) DB"; +const STORAGE_PREFIX: &[u8] = b"storage"; +const KEYS_PREFIX: &[u8] = b"keys"; + +const NEXT_ID: &[u8] = b"crypto_key_id"; + +impl Api where + Storage: OffchainStorage, + KeyProvider: AuthorityKeyProvider, +{ + fn keypair(&self, phrase: &str) -> Result { + P::from_phrase(phrase, Some(self.keys_password.as_ref())) + .map_err(|e| { + warn!("Error recovering Offchain Worker key. Password invalid? {:?}", e); + () + }) + .map(|x| x.0) + } + + fn read_key(&self, id: Option, kind: CryptoKind) -> Result { + if let Some(id) = id { + let key = self.db.get(KEYS_PREFIX, &id.0.encode()) + .and_then(|key| CryptoKey::decode(&mut &*key)) + .ok_or(())?; + if key.kind != kind { + warn!( + "Invalid crypto kind (got: {:?}, expected: {:?}), when requesting key {:?}", + key.kind, + kind, + id + ); + return Err(()) + } + + Ok(match key.kind { + CryptoKind::Sr25519 => Key::Sr25519(self.keypair(&key.phrase)?), + CryptoKind::Ed25519 => Key::Ed25519(self.keypair(&key.phrase)?), + }) + } else { + let key = match kind { + CryptoKind::Sr25519 => self.key_provider.authority_key().map(Key::Sr25519), + CryptoKind::Ed25519 => self.key_provider.authority_key().map(Key::Ed25519), + }; + + key.ok_or_else(|| { + warn!("AuthorityKey is not configured, yet offchain worker tried to access it."); + () + }) + } + } +} + +impl OffchainExt for Api where + Storage: OffchainStorage, + KeyProvider: AuthorityKeyProvider, +{ fn submit_transaction(&mut self, ext: Vec) -> Result<(), ()> { - self.0.unbounded_send(ExtMessage::SubmitExtrinsic(ext)) + self.sender + .unbounded_send(ExtMessage::SubmitExtrinsic(ext)) .map(|_| ()) .map_err(|_| ()) } - fn new_crypto_key(&mut self, _crypto: CryptoKind) -> Result { - unavailable_yet::<()>("new_crypto_key"); - Err(()) + fn new_crypto_key(&mut self, kind: CryptoKind) -> Result { + let phrase = match kind { + CryptoKind::Ed25519 => { + ed25519::Pair::generate_with_phrase(Some(self.keys_password.as_ref())).1 + }, + CryptoKind::Sr25519 => { + sr25519::Pair::generate_with_phrase(Some(self.keys_password.as_ref())).1 + }, + }; + + let (id, id_encoded) = loop { + let encoded = self.db.get(KEYS_PREFIX, NEXT_ID); + let encoded_slice = encoded.as_ref().map(|x| x.as_slice()); + let new_id = encoded_slice.and_then(|mut x| u16::decode(&mut x)).unwrap_or_default() + .checked_add(1) + .ok_or(())?; + let new_id_encoded = new_id.encode(); + + if self.db.compare_and_set(KEYS_PREFIX, NEXT_ID, encoded_slice, &new_id_encoded) { + break (new_id, new_id_encoded); + } + }; + + self.db.set(KEYS_PREFIX, &id_encoded, &CryptoKey { phrase, kind } .encode()); + + Ok(CryptoKeyId(id)) } - fn encrypt(&mut self, _key: Option, _data: &[u8]) -> Result, ()> { + fn encrypt(&mut self, _key: Option, _kind: CryptoKind, _data: &[u8]) -> Result, ()> { unavailable_yet::<()>("encrypt"); Err(()) } - fn decrypt(&mut self, _key: Option, _data: &[u8]) -> Result, ()> { + fn decrypt(&mut self, _key: Option, _kind: CryptoKind, _data: &[u8]) -> Result, ()> { unavailable_yet::<()>("decrypt"); Err(()) + } - fn sign(&mut self, _key: Option, _data: &[u8]) -> Result, ()> { - unavailable_yet::<()>("sign"); - Err(()) + fn sign(&mut self, key: Option, kind: CryptoKind, data: &[u8]) -> Result, ()> { + let key = self.read_key(key, kind)?; + + Ok(match key { + Key::Sr25519(pair) => pair.sign(data).0.to_vec(), + Key::Ed25519(pair) => pair.sign(data).0.to_vec(), + }) } - fn verify(&mut self, _key: Option, _msg: &[u8], _signature: &[u8]) -> Result { - unavailable_yet::<()>("verify"); - Err(()) + fn verify(&mut self, key: Option, kind: CryptoKind, msg: &[u8], signature: &[u8]) -> Result { + let key = self.read_key(key, kind)?; + + Ok(match key { + Key::Sr25519(pair) => sr25519::Pair::verify_weak(signature, msg, pair.public()), + Key::Ed25519(pair) => ed25519::Pair::verify_weak(signature, msg, pair.public()), + }) } fn timestamp(&mut self) -> Timestamp { @@ -89,16 +199,33 @@ impl OffchainExt for AsyncApi { unavailable_yet("random_seed") } - fn local_storage_set(&mut self, _key: &[u8], _value: &[u8]) { - unavailable_yet("local_storage_set") + fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]) { + match kind { + StorageKind::PERSISTENT => self.db.set(STORAGE_PREFIX, key, value), + StorageKind::LOCAL => unavailable_yet(LOCAL_DB), + } } - fn local_storage_compare_and_set(&mut self, _key: &[u8], _old_value: &[u8], _new_value: &[u8]) { - unavailable_yet("local_storage_compare_and_set") + fn local_storage_compare_and_set( + &mut self, + kind: StorageKind, + key: &[u8], + old_value: &[u8], + new_value: &[u8], + ) -> bool { + match kind { + StorageKind::PERSISTENT => { + self.db.compare_and_set(STORAGE_PREFIX, key, Some(old_value), new_value) + }, + StorageKind::LOCAL => unavailable_yet(LOCAL_DB), + } } - fn local_storage_get(&mut self, _key: &[u8]) -> Option> { - unavailable_yet("local_storage_get") + fn local_storage_get(&mut self, kind: StorageKind, key: &[u8]) -> Option> { + match kind { + StorageKind::PERSISTENT => self.db.get(STORAGE_PREFIX, key), + StorageKind::LOCAL => unavailable_yet(LOCAL_DB), + } } fn http_request_start( @@ -159,24 +286,39 @@ impl OffchainExt for AsyncApi { } /// Offchain extensions implementation API -pub(crate) struct Api { +/// +/// This is the asynchronous processing part of the API. +pub(crate) struct AsyncApi { receiver: Option>, transaction_pool: Arc>, at: BlockId, } -impl Api { - pub fn new( +impl AsyncApi { + /// Creates new Offchain extensions API implementation an the asynchronous processing part. + pub fn new( transaction_pool: Arc>, + db: S, + keys_password: Protected, + key_provider: P, at: BlockId, - ) -> (AsyncApi, Self) { - let (tx, rx) = mpsc::unbounded(); - let api = Self { + ) -> (Api, AsyncApi) { + let (sender, rx) = mpsc::unbounded(); + + let api = Api { + sender, + db, + keys_password, + key_provider, + }; + + let async_api = AsyncApi { receiver: Some(rx), transaction_pool, at, }; - (AsyncApi(tx), api) + + (api, async_api) } /// Run a processing task for the API @@ -209,3 +351,108 @@ impl Api { } } } + +#[cfg(test)] +mod tests { + use super::*; + use client_db::offchain::LocalStorage; + use crate::tests::TestProvider; + + fn offchain_api() -> (Api, AsyncApi) { + let _ = env_logger::try_init(); + let db = LocalStorage::new_test(); + let client = Arc::new(test_client::new()); + let pool = Arc::new( + Pool::new(Default::default(), transaction_pool::ChainApi::new(client.clone())) + ); + + AsyncApi::new(pool, db, "pass".to_owned().into(), TestProvider::default(), BlockId::Number(0)) + } + + #[test] + fn should_set_and_get_local_storage() { + // given + let kind = StorageKind::PERSISTENT; + let mut api = offchain_api().0; + let key = b"test"; + + // when + assert_eq!(api.local_storage_get(kind, key), None); + api.local_storage_set(kind, key, b"value"); + + // then + assert_eq!(api.local_storage_get(kind, key), Some(b"value".to_vec())); + } + + #[test] + fn should_compare_and_set_local_storage() { + // given + let kind = StorageKind::PERSISTENT; + let mut api = offchain_api().0; + let key = b"test"; + api.local_storage_set(kind, key, b"value"); + + // when + assert_eq!(api.local_storage_compare_and_set(kind, key, b"val", b"xxx"), false); + assert_eq!(api.local_storage_get(kind, key), Some(b"value".to_vec())); + + // when + assert_eq!(api.local_storage_compare_and_set(kind, key, b"value", b"xxx"), true); + assert_eq!(api.local_storage_get(kind, key), Some(b"xxx".to_vec())); + } + + #[test] + fn should_create_a_new_key_and_sign_and_verify_stuff() { + let test = |kind: CryptoKind| { + // given + let mut api = offchain_api().0; + let msg = b"Hello world!"; + + // when + let key_id = api.new_crypto_key(kind).unwrap(); + let signature = api.sign(Some(key_id), kind, msg).unwrap(); + + // then + let res = api.verify(Some(key_id), kind, msg, &signature).unwrap(); + assert_eq!(res, true); + let res = api.verify(Some(key_id), kind, msg, &[]).unwrap(); + assert_eq!(res, false); + let res = api.verify(Some(key_id), kind, b"Different msg", &signature).unwrap(); + assert_eq!(res, false); + + assert_eq!( + api.verify(Some(key_id), CryptoKind::Sr25519, msg, &signature).is_err(), + kind != CryptoKind::Sr25519 + ); + + }; + + test(CryptoKind::Ed25519); + test(CryptoKind::Sr25519); + } + + #[test] + fn should_sign_and_verify_with_authority_key() { + // given + let mut api = offchain_api().0; + api.key_provider.ed_key = Some(ed25519::Pair::generate().0); + let msg = b"Hello world!"; + let kind = CryptoKind::Ed25519; + + // when + let signature = api.sign(None, kind, msg).unwrap(); + + // then + let res = api.verify(None, kind, msg, &signature).unwrap(); + assert_eq!(res, true); + let res = api.verify(None, kind, msg, &[]).unwrap(); + assert_eq!(res, false); + let res = api.verify(None, kind, b"Different msg", &signature).unwrap(); + assert_eq!(res, false); + + assert!( + api.verify(None, CryptoKind::Sr25519, msg, &signature).is_err(), + "Invalid kind should trigger a missing key error." + ); + } +} diff --git a/core/offchain/src/lib.rs b/core/offchain/src/lib.rs index 081ae61a5bcaeecc975bab74f911a4f2cfa7a41f..de3a5da08441ac41ca5de454f7f6e020a31db326 100644 --- a/core/offchain/src/lib.rs +++ b/core/offchain/src/lib.rs @@ -34,18 +34,22 @@ #![warn(missing_docs)] use std::{ + fmt, marker::PhantomData, sync::Arc, }; use client::runtime_api::ApiExt; use log::{debug, warn}; -use primitives::ExecutionContext; +use primitives::{ + ExecutionContext, + crypto, +}; use runtime_primitives::{ generic::BlockId, traits::{self, ProvideRuntimeApi}, }; -use tokio::runtime::TaskExecutor; +use futures::future::Future; use transaction_pool::txpool::{Pool, ChainApi}; mod api; @@ -54,39 +58,79 @@ pub mod testing; pub use offchain_primitives::OffchainWorkerApi; +/// Provides currently configured authority key. +pub trait AuthorityKeyProvider: Clone + 'static { + /// Returns currently configured authority key. + fn authority_key(&self) -> Option; +} + /// An offchain workers manager. -#[derive(Debug)] -pub struct OffchainWorkers { - client: Arc, - executor: TaskExecutor, +pub struct OffchainWorkers< + Client, + Storage, + KeyProvider, + Block: traits::Block, +> { + client: Arc, + db: Storage, + authority_key: KeyProvider, + keys_password: crypto::Protected, _block: PhantomData, } -impl OffchainWorkers { +impl OffchainWorkers< + Client, + Storage, + KeyProvider, + Block, +> { /// Creates new `OffchainWorkers`. pub fn new( - client: Arc, - executor: TaskExecutor, + client: Arc, + db: Storage, + authority_key: KeyProvider, + keys_password: crypto::Protected, ) -> Self { Self { client, - executor, + db, + authority_key, + keys_password, _block: PhantomData, } } } -impl OffchainWorkers where +impl fmt::Debug for OffchainWorkers< + Client, + Storage, + KeyProvider, + Block, +> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("OffchainWorkers").finish() + } +} + +impl OffchainWorkers< + Client, + Storage, + KeyProvider, + Block, +> where Block: traits::Block, - C: ProvideRuntimeApi, - C::Api: OffchainWorkerApi, + Client: ProvideRuntimeApi, + Client::Api: OffchainWorkerApi, + KeyProvider: AuthorityKeyProvider, + Storage: client::backend::OffchainStorage + 'static, { /// Start the offchain workers after given block. + #[must_use] pub fn on_block_imported( &self, number: &::Number, pool: &Arc>, - ) where + ) -> impl Future where A: ChainApi + 'static, { let runtime = self.client.runtime_api(); @@ -95,12 +139,19 @@ impl OffchainWorkers where debug!("Checking offchain workers at {:?}: {:?}", at, has_api); if has_api.unwrap_or(false) { - let (api, runner) = api::Api::new(pool.clone(), at.clone()); - self.executor.spawn(runner.process()); - + let (api, runner) = api::AsyncApi::new( + pool.clone(), + self.db.clone(), + self.keys_password.clone(), + self.authority_key.clone(), + at.clone(), + ); debug!("Running offchain workers at {:?}", at); let api = Box::new(api); runtime.offchain_worker_with_context(&at, ExecutionContext::OffchainWorker(api), *number).unwrap(); + futures::future::Either::A(runner.process()) + } else { + futures::future::Either::B(futures::future::ok(())) } } } @@ -109,6 +160,23 @@ impl OffchainWorkers where mod tests { use super::*; use futures::Future; + use primitives::{ed25519, sr25519, crypto::{TypedKey, Pair}}; + + #[derive(Clone, Default)] + pub(crate) struct TestProvider { + pub(crate) sr_key: Option, + pub(crate) ed_key: Option, + } + + impl AuthorityKeyProvider for TestProvider { + fn authority_key(&self) -> Option { + TPair::from_seed_slice(&match TPair::KEY_TYPE { + sr25519::Pair::KEY_TYPE => self.sr_key.as_ref().map(|key| key.to_raw_vec()), + ed25519::Pair::KEY_TYPE => self.ed_key.as_ref().map(|key| key.to_raw_vec()), + _ => None, + }?).ok() + } + } #[test] fn should_call_into_runtime_and_produce_extrinsic() { @@ -117,10 +185,11 @@ mod tests { let runtime = tokio::runtime::Runtime::new().unwrap(); let client = Arc::new(test_client::new()); let pool = Arc::new(Pool::new(Default::default(), ::transaction_pool::ChainApi::new(client.clone()))); + let db = client_db::offchain::LocalStorage::new_test(); // when - let offchain = OffchainWorkers::new(client, runtime.executor()); - offchain.on_block_imported(&0u64, &pool); + let offchain = OffchainWorkers::new(client, db, TestProvider::default(), "".to_owned().into()); + runtime.executor().spawn(offchain.on_block_imported(&0u64, &pool)); // then runtime.shutdown_on_idle().wait().unwrap(); diff --git a/core/offchain/src/testing.rs b/core/offchain/src/testing.rs index 3419665d0a2f2873693168d89950eceb7eb363d8..2d8c690e9a6df3a4d7d1c1ef75e85b4b8a24a268 100644 --- a/core/offchain/src/testing.rs +++ b/core/offchain/src/testing.rs @@ -20,6 +20,7 @@ use std::{ collections::BTreeMap, sync::Arc, }; +use client::backend::OffchainStorage; use parking_lot::RwLock; use primitives::offchain::{ self, @@ -29,6 +30,7 @@ use primitives::offchain::{ Timestamp, CryptoKind, CryptoKeyId, + StorageKind, }; /// Pending request. @@ -61,6 +63,11 @@ pub struct PendingRequest { pub struct State { /// A list of pending requests. pub requests: BTreeMap, + expected_requests: BTreeMap, + /// Persistent local storage + pub persistent_storage: client::in_mem::OffchainStorage, + /// Local storage + pub local_storage: client::in_mem::OffchainStorage, } impl State { @@ -74,7 +81,7 @@ impl State { ) { match self.requests.get_mut(&RequestId(id)) { None => { - panic!("Missing expected request: {:?}.\n\nAll: {:?}", id, self.requests); + panic!("Missing pending request: {:?}.\n\nAll: {:?}", id, self.requests); } Some(req) => { assert_eq!( @@ -86,12 +93,47 @@ impl State { } } } + + fn fulfill_expected(&mut self, id: u16) { + if let Some(mut req) = self.expected_requests.remove(&RequestId(id)) { + let response = std::mem::replace(&mut req.response, vec![]); + let headers = std::mem::replace(&mut req.response_headers, vec![]); + self.fulfill_pending_request(id, req, response, headers); + } + } + + /// Add expected HTTP request. + /// + /// This method can be used to initialize expected HTTP requests and their responses + /// before running the actual code that utilizes them (for instance before calling into runtime). + /// Expected request has to be fulfilled before this struct is dropped, + /// the `response` and `response_headers` fields will be used to return results to the callers. + pub fn expect_request(&mut self, id: u16, expected: PendingRequest) { + self.expected_requests.insert(RequestId(id), expected); + } +} + +impl Drop for State { + fn drop(&mut self) { + if !self.expected_requests.is_empty() { + panic!("Unfulfilled expected requests: {:?}", self.expected_requests); + } + } } /// Implementation of offchain externalities used for tests. #[derive(Clone, Default, Debug)] pub struct TestOffchainExt(pub Arc>); +impl TestOffchainExt { + /// Create new `TestOffchainExt` and a reference to the internal state. + pub fn new() -> (Self, Arc>) { + let ext = Self::default(); + let state = ext.0.clone(); + (ext, state) + } +} + impl offchain::Externalities for TestOffchainExt { fn submit_transaction(&mut self, _ex: Vec) -> Result<(), ()> { unimplemented!("not needed in tests so far") @@ -101,19 +143,40 @@ impl offchain::Externalities for TestOffchainExt { unimplemented!("not needed in tests so far") } - fn encrypt(&mut self, _key: Option, _data: &[u8]) -> Result, ()> { + fn encrypt( + &mut self, + _key: Option, + _kind: CryptoKind, + _data: &[u8], + ) -> Result, ()> { unimplemented!("not needed in tests so far") } - fn decrypt(&mut self, _key: Option, _data: &[u8]) -> Result, ()> { + fn decrypt( + &mut self, + _key: Option, + _kind: CryptoKind, + _data: &[u8], + ) -> Result, ()> { unimplemented!("not needed in tests so far") } - fn sign(&mut self, _key: Option, _data: &[u8]) -> Result, ()> { + fn sign( + &mut self, + _key: Option, + _kind: CryptoKind, + _data: &[u8], + ) -> Result, ()> { unimplemented!("not needed in tests so far") } - fn verify(&mut self, _key: Option, _msg: &[u8], _signature: &[u8]) -> Result { + fn verify( + &mut self, + _key: Option, + _kind: CryptoKind, + _msg: &[u8], + _signature: &[u8], + ) -> Result { unimplemented!("not needed in tests so far") } @@ -129,21 +192,34 @@ impl offchain::Externalities for TestOffchainExt { unimplemented!("not needed in tests so far") } - fn local_storage_set(&mut self, _key: &[u8], _value: &[u8]) { - unimplemented!("not needed in tests so far") + fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]) { + let mut state = self.0.write(); + match kind { + StorageKind::LOCAL => &mut state.local_storage, + StorageKind::PERSISTENT => &mut state.persistent_storage, + }.set(b"", key, value); } fn local_storage_compare_and_set( &mut self, - _key: &[u8], - _old_value: &[u8], - _new_value: &[u8] - ) { - unimplemented!("not needed in tests so far") + kind: StorageKind, + key: &[u8], + old_value: &[u8], + new_value: &[u8] + ) -> bool { + let mut state = self.0.write(); + match kind { + StorageKind::LOCAL => &mut state.local_storage, + StorageKind::PERSISTENT => &mut state.persistent_storage, + }.compare_and_set(b"", key, Some(old_value), new_value) } - fn local_storage_get(&mut self, _key: &[u8]) -> Option> { - unimplemented!("not needed in tests so far") + fn local_storage_get(&mut self, kind: StorageKind, key: &[u8]) -> Option> { + let state = self.0.read(); + match kind { + StorageKind::LOCAL => &state.local_storage, + StorageKind::PERSISTENT => &state.persistent_storage, + }.get(b"", key) } fn http_request_start(&mut self, method: &str, uri: &str, meta: &[u8]) -> Result { @@ -180,15 +256,21 @@ impl offchain::Externalities for TestOffchainExt { _deadline: Option ) -> Result<(), HttpError> { let mut state = self.0.write(); - if let Some(req) = state.requests.get_mut(&request_id) { + + let sent = { + let req = state.requests.get_mut(&request_id).ok_or(HttpError::IoError)?; + req.body.extend(chunk); if chunk.is_empty() { req.sent = true; } - req.body.extend(chunk); - Ok(()) - } else { - Err(HttpError::IoError) + req.sent + }; + + if sent { + state.fulfill_expected(request_id.0); } + + Ok(()) } fn http_response_wait( diff --git a/core/peerset/Cargo.toml b/core/peerset/Cargo.toml index aa08c8ca997a5d32546567bbb806cf778bac6d7a..91e9d58e0a6b42d74690dce7cbbf1fc65309d6e5 100644 --- a/core/peerset/Cargo.toml +++ b/core/peerset/Cargo.toml @@ -8,8 +8,8 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -futures = "0.1" -libp2p = { version = "0.9.0", default-features = false } +futures-preview = "0.3.0-alpha.17" +libp2p = { version = "0.10.0", default-features = false } linked-hash-map = "0.5" log = "0.4" lru-cache = "0.1.2" @@ -17,4 +17,3 @@ serde_json = "1.0.24" [dev-dependencies] rand = "0.6" -tokio = "0.1" diff --git a/core/peerset/src/lib.rs b/core/peerset/src/lib.rs index aa3ce02076d56d5cf42605d6a8aa76cd444df581..763c94d0d642298c6a50c0835193c0ba1bcdd00c 100644 --- a/core/peerset/src/lib.rs +++ b/core/peerset/src/lib.rs @@ -20,10 +20,11 @@ mod peersstate; use std::{collections::{HashSet, HashMap}, collections::VecDeque, time::Instant}; -use futures::{prelude::*, sync::mpsc, try_ready}; +use futures::{prelude::*, channel::mpsc, stream::Fuse}; use libp2p::PeerId; use log::{debug, error, trace}; use serde_json::json; +use std::{pin::Pin, task::Context, task::Poll}; /// We don't accept nodes whose reputation is under this value. const BANNED_THRESHOLD: i32 = 82 * (i32::min_value() / 100); @@ -155,7 +156,7 @@ pub struct Peerset { data: peersstate::PeersState, /// If true, we only accept reserved nodes. reserved_only: bool, - rx: mpsc::UnboundedReceiver, + rx: Fuse>, message_queue: VecDeque, /// When the `Peerset` was created. created: Instant, @@ -174,7 +175,7 @@ impl Peerset { let mut peerset = Peerset { data: peersstate::PeersState::new(config.in_peers, config.out_peers), - rx, + rx: rx.fuse(), reserved_only: config.reserved_only, message_queue: VecDeque::new(), created: Instant::now(), @@ -353,7 +354,7 @@ impl Peerset { /// a corresponding `Accept` or `Reject`, except if we were already connected to this peer. /// /// Note that this mechanism is orthogonal to `Connect`/`Drop`. Accepting an incoming - /// connection implicitely means `Connect`, but incoming connections aren't cancelled by + /// connection implicitly means `Connect`, but incoming connections aren't cancelled by /// `dropped`. /// // Implementation note: because of concurrency issues, it is possible that we push a `Connect` @@ -457,24 +458,34 @@ impl Peerset { impl Stream for Peerset { type Item = Message; - type Error = (); - fn poll(&mut self) -> Poll, Self::Error> { + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { loop { if let Some(message) = self.message_queue.pop_front() { - return Ok(Async::Ready(Some(message))); + return Poll::Ready(Some(message)); } - match try_ready!(self.rx.poll()) { - None => return Ok(Async::NotReady), - Some(action) => match action { - Action::AddReservedPeer(peer_id) => self.on_add_reserved_peer(peer_id), - Action::RemoveReservedPeer(peer_id) => self.on_remove_reserved_peer(peer_id), - Action::SetReservedOnly(reserved) => self.on_set_reserved_only(reserved), - Action::ReportPeer(peer_id, score_diff) => self.on_report_peer(peer_id, score_diff), - Action::SetPriorityGroup(group_id, peers) => self.on_set_priority_group(&group_id, peers), - Action::AddToPriorityGroup(group_id, peer_id) => self.on_add_to_priority_group(&group_id, peer_id), - Action::RemoveFromPriorityGroup(group_id, peer_id) => self.on_remove_from_priority_group(&group_id, peer_id), - } + + let action = match Stream::poll_next(Pin::new(&mut self.rx), cx) { + Poll::Pending => return Poll::Pending, + Poll::Ready(Some(event)) => event, + Poll::Ready(None) => return Poll::Pending, + }; + + match action { + Action::AddReservedPeer(peer_id) => + self.on_add_reserved_peer(peer_id), + Action::RemoveReservedPeer(peer_id) => + self.on_remove_reserved_peer(peer_id), + Action::SetReservedOnly(reserved) => + self.on_set_reserved_only(reserved), + Action::ReportPeer(peer_id, score_diff) => + self.on_report_peer(peer_id, score_diff), + Action::SetPriorityGroup(group_id, peers) => + self.on_set_priority_group(&group_id, peers), + Action::AddToPriorityGroup(group_id, peer_id) => + self.on_add_to_priority_group(&group_id, peer_id), + Action::RemoveFromPriorityGroup(group_id, peer_id) => + self.on_remove_from_priority_group(&group_id, peer_id), } } } @@ -485,7 +496,7 @@ mod tests { use libp2p::PeerId; use futures::prelude::*; use super::{PeersetConfig, Peerset, Message, IncomingIndex, BANNED_THRESHOLD}; - use std::{thread, time::Duration}; + use std::{pin::Pin, task::Poll, thread, time::Duration}; fn assert_messages(mut peerset: Peerset, messages: Vec) -> Peerset { for expected_message in messages { @@ -497,10 +508,8 @@ mod tests { peerset } - fn next_message(peerset: Peerset) -> Result<(Message, Peerset), ()> { - let (next, peerset) = peerset.into_future() - .wait() - .map_err(|_| ())?; + fn next_message(mut peerset: Peerset) -> Result<(Message, Peerset), ()> { + let next = futures::executor::block_on_stream(&mut peerset).next(); let message = next.ok_or_else(|| ())?; Ok((message, peerset)) } @@ -598,13 +607,13 @@ mod tests { let peer_id = PeerId::random(); handle.report_peer(peer_id.clone(), BANNED_THRESHOLD - 1); - let fut = futures::future::poll_fn(move || -> Result<_, ()> { + let fut = futures::future::poll_fn(move |cx| { // We need one polling for the message to be processed. - assert_eq!(peerset.poll().unwrap(), Async::NotReady); + assert_eq!(Stream::poll_next(Pin::new(&mut peerset), cx), Poll::Pending); // Check that an incoming connection from that node gets refused. peerset.incoming(peer_id.clone(), IncomingIndex(1)); - if let Async::Ready(msg) = peerset.poll().unwrap() { + if let Poll::Ready(msg) = Stream::poll_next(Pin::new(&mut peerset), cx) { assert_eq!(msg.unwrap(), Message::Reject(IncomingIndex(1))); } else { panic!() @@ -615,14 +624,14 @@ mod tests { // Try again. This time the node should be accepted. peerset.incoming(peer_id.clone(), IncomingIndex(2)); - while let Async::Ready(msg) = peerset.poll().unwrap() { + while let Poll::Ready(msg) = Stream::poll_next(Pin::new(&mut peerset), cx) { assert_eq!(msg.unwrap(), Message::Accept(IncomingIndex(2))); } - Ok(Async::Ready(())) + Poll::Ready(()) }); - tokio::runtime::current_thread::Runtime::new().unwrap().block_on(fut).unwrap(); + futures::executor::block_on(fut); } } diff --git a/core/peerset/tests/fuzz.rs b/core/peerset/tests/fuzz.rs index 42a7f2770cc9ccfe64d5d455a1a1046be254bfd1..be29916c34f2057fe37edd2496b243998b65f38d 100644 --- a/core/peerset/tests/fuzz.rs +++ b/core/peerset/tests/fuzz.rs @@ -18,7 +18,7 @@ use futures::prelude::*; use libp2p::PeerId; use rand::distributions::{Distribution, Uniform, WeightedIndex}; use rand::seq::IteratorRandom; -use std::{collections::HashMap, collections::HashSet, iter}; +use std::{collections::HashMap, collections::HashSet, iter, pin::Pin, task::Poll}; use substrate_peerset::{IncomingIndex, Message, PeersetConfig, Peerset}; #[test] @@ -54,7 +54,7 @@ fn test_once() { out_peers: Uniform::new_inclusive(0, 25).sample(&mut rng), }); - tokio::runtime::current_thread::Runtime::new().unwrap().block_on(futures::future::poll_fn(move || -> Result<_, ()> { + futures::executor::block_on(futures::future::poll_fn(move |cx| { // List of nodes the user of `peerset` assumes it's connected to. Always a subset of // `known_nodes`. let mut connected_nodes = HashSet::::new(); @@ -71,20 +71,20 @@ fn test_once() { let action_weights = [150, 90, 90, 30, 30, 1, 1, 4, 4]; match WeightedIndex::new(&action_weights).unwrap().sample(&mut rng) { // If we generate 0, poll the peerset. - 0 => match peerset.poll().unwrap() { - Async::Ready(Some(Message::Connect(id))) => { + 0 => match Stream::poll_next(Pin::new(&mut peerset), cx) { + Poll::Ready(Some(Message::Connect(id))) => { if let Some(id) = incoming_nodes.iter().find(|(_, v)| **v == id).map(|(&id, _)| id) { incoming_nodes.remove(&id); } assert!(connected_nodes.insert(id)); } - Async::Ready(Some(Message::Drop(id))) => { connected_nodes.remove(&id); } - Async::Ready(Some(Message::Accept(n))) => + Poll::Ready(Some(Message::Drop(id))) => { connected_nodes.remove(&id); } + Poll::Ready(Some(Message::Accept(n))) => assert!(connected_nodes.insert(incoming_nodes.remove(&n).unwrap())), - Async::Ready(Some(Message::Reject(n))) => + Poll::Ready(Some(Message::Reject(n))) => assert!(!connected_nodes.contains(&incoming_nodes.remove(&n).unwrap())), - Async::Ready(None) => panic!(), - Async::NotReady => {} + Poll::Ready(None) => panic!(), + Poll::Pending => {} } // If we generate 1, discover a new node. @@ -133,6 +133,6 @@ fn test_once() { } } - Ok(Async::Ready(())) - })).unwrap(); + Poll::Ready(()) + })); } diff --git a/core/primitives/Cargo.toml b/core/primitives/Cargo.toml index ab34cfcd1336081448f37778d98e888931c248af..94dac26bec96c02d960b5244e3afff649ef6638e 100644 --- a/core/primitives/Cargo.toml +++ b/core/primitives/Cargo.toml @@ -6,27 +6,28 @@ edition = "2018" [dependencies] rstd = { package = "sr-std", path = "../sr-std", default-features = false } -parity-codec = { version = "3.4.0", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } rustc-hex = { version = "2.0", default-features = false } serde = { version = "1.0", optional = true, features = ["derive"] } twox-hash = { version = "1.2.0", optional = true } byteorder = { version = "1.3.1", default-features = false } -primitive-types = { version = "0.2.3", default-features = false, features = ["codec"] } +primitive-types = { version = "0.4.0", default-features = false, features = ["codec"] } impl-serde = { version = "0.1", optional = true } wasmi = { version = "0.4.3", optional = true } -hash-db = { version = "0.12", default-features = false } -hash256-std-hasher = { version = "0.12", default-features = false } +hash-db = { version = "0.14.0", default-features = false } +hash256-std-hasher = { version = "0.14.0", default-features = false } ed25519-dalek = { version = "1.0.0-pre.1", optional = true } base58 = { version = "0.1", optional = true } blake2-rfc = { version = "0.2.18", optional = true } -schnorrkel = { version = "0.1", optional = true } +schnorrkel = { version = "0.1.1", optional = true } rand = { version = "0.6", optional = true } sha2 = { version = "0.8", optional = true } -substrate-bip39 = { git = "https://github.com/paritytech/substrate-bip39", optional = true } +substrate-bip39 = { version = "0.2.2", optional = true } tiny-bip39 = { version = "0.6.1", optional = true } hex = { version = "0.3", optional = true } regex = { version = "1.1", optional = true } num-traits = { version = "0.2", default-features = false } +zeroize = { version = "0.9.2", default-features = false } [dev-dependencies] substrate-serializer = { path = "../serializer" } @@ -48,7 +49,6 @@ std = [ "wasmi", "primitive-types/std", "primitive-types/serde", - "primitive-types/heapsize", "primitive-types/byteorder", "primitive-types/rustc-hex", "primitive-types/libc", @@ -73,4 +73,5 @@ std = [ "schnorrkel", "regex", "num-traits/std", + "zeroize/std" ] diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 9ddc9a93f773c9e083138dc529a7274443399e08..6aac4e08bcdc69e6bc89501035e57c66a0def5c7 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -26,6 +26,9 @@ use parity_codec::{Encode, Decode}; use regex::Regex; #[cfg(feature = "std")] use base58::{FromBase58, ToBase58}; +#[cfg(feature = "std")] +use std::hash::Hash; +use zeroize::Zeroize; /// The root phrase for our publicly known keys. pub const DEV_PHRASE: &str = "bottom drive obey lake curtain smoke basket hold race lonely fit walk"; @@ -64,6 +67,43 @@ impl> UncheckedInto for S { } } +/// A store for sensitive data. +/// +/// Calls `Zeroize::zeroize` upon `Drop`. +#[derive(Clone)] +pub struct Protected(T); + +impl AsRef for Protected { + fn as_ref(&self) -> &T { + &self.0 + } +} + +#[cfg(feature = "std")] +impl std::fmt::Debug for Protected { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(fmt, "") + } +} + +impl From for Protected { + fn from(t: T) -> Self { + Protected(t) + } +} + +impl Zeroize for Protected { + fn zeroize(&mut self) { + self.0.zeroize() + } +} + +impl Drop for Protected { + fn drop(&mut self) { + self.zeroize() + } +} + /// An error with the interpretation of a secret. #[derive(Debug, Clone, PartialEq, Eq)] #[cfg(feature = "std")] @@ -286,13 +326,29 @@ impl + AsRef<[u8]> + Default + Derive> Ss58Codec for T { } } +/// Trait suitable for typical cryptographic PKI key public type. +pub trait Public: TypedKey + PartialEq + Eq { + /// A new instance from the given slice that should be 32 bytes long. + /// + /// NOTE: No checking goes on to ensure this is a real public key. Only use it if + /// you are certain that the array actually is a pubkey. GIGO! + fn from_slice(data: &[u8]) -> Self; + + /// Return a `Vec` filled with raw data. + #[cfg(feature = "std")] + fn to_raw_vec(&self) -> Vec; + + /// Return a slice filled with raw data. + fn as_slice(&self) -> &[u8]; +} + /// Trait suitable for typical cryptographic PKI key pair type. /// /// For now it just specifies how to create a key from a phrase and derivation path. #[cfg(feature = "std")] -pub trait Pair: Sized + 'static { - /// TThe type which is used to encode a public key. - type Public; +pub trait Pair: TypedKey + Sized + 'static { + /// The type which is used to encode a public key. + type Public: Public + Hash; /// The type used to (minimally) encode the data required to securely create /// a new key pair. @@ -300,7 +356,7 @@ pub trait Pair: Sized + 'static { /// The type used to represent a signature. Can be created from a key pair and a message /// and verified with the message and a public key. - type Signature; + type Signature: AsRef<[u8]>; /// Error returned from the `derive` function. type DeriveError; @@ -412,6 +468,31 @@ pub trait Pair: Sized + 'static { path, ) } + + /// Return a vec filled with raw data. + fn to_raw_vec(&self) -> Vec; +} + +/// An identifier for a type of cryptographic key. +/// +/// 0-1024 are reserved. +pub type KeyTypeId = u32; + +/// Constant key types. +pub mod key_types { + use super::KeyTypeId; + + /// ED25519 public key. + pub const ED25519: KeyTypeId = 10; + + /// SR25519 public key. + pub const SR25519: KeyTypeId = 20; +} + +/// A trait for something that has a key type ID. +pub trait TypedKey { + /// The type ID of this key. + const KEY_TYPE: KeyTypeId; } #[cfg(test)] @@ -429,10 +510,26 @@ mod tests { Seed(Vec), } + #[derive(PartialEq, Eq, Hash)] + struct TestPublic; + impl Public for TestPublic { + fn from_slice(_bytes: &[u8]) -> Self { + Self + } + fn as_slice(&self) -> &[u8] { + &[] + } + fn to_raw_vec(&self) -> Vec { + vec![] + } + } + impl TypedKey for TestPublic { + const KEY_TYPE: u32 = 4242; + } impl Pair for TestPair { - type Public = (); + type Public = TestPublic; type Seed = [u8; 0]; - type Signature = (); + type Signature = [u8; 0]; type DeriveError = (); fn generate() -> (Self, ::Seed) { (TestPair::Generated, []) } @@ -453,7 +550,7 @@ mod tests { Err(()) } fn from_seed(_seed: &::Seed) -> Self { TestPair::Seed(vec![]) } - fn sign(&self, _message: &[u8]) -> Self::Signature { () } + fn sign(&self, _message: &[u8]) -> Self::Signature { [] } fn verify, M: AsRef<[u8]>>( _sig: &Self::Signature, _message: M, @@ -464,7 +561,7 @@ mod tests { _message: M, _pubkey: P ) -> bool { true } - fn public(&self) -> Self::Public { () } + fn public(&self) -> Self::Public { TestPublic } fn from_standard_components>( phrase: &str, password: Option<&str>, @@ -481,6 +578,12 @@ mod tests { { Ok(TestPair::Seed(seed.to_owned())) } + fn to_raw_vec(&self) -> Vec { + vec![] + } + } + impl TypedKey for TestPair { + const KEY_TYPE: u32 = 4242; } #[test] diff --git a/core/primitives/src/ed25519.rs b/core/primitives/src/ed25519.rs index 26086816a3e5a23335e31f423101a4a22544d8d1..5d1fe884a5180efa406a07392449594e8411d582 100644 --- a/core/primitives/src/ed25519.rs +++ b/core/primitives/src/ed25519.rs @@ -32,7 +32,7 @@ use bip39::{Mnemonic, Language, MnemonicType}; use crate::crypto::{Pair as TraitPair, DeriveJunction, SecretStringError, Derive, Ss58Codec}; #[cfg(feature = "std")] use serde::{de, Serializer, Serialize, Deserializer, Deserialize}; -use crate::crypto::UncheckedFrom; +use crate::crypto::{key_types, KeyTypeId, Public as TraitPublic, TypedKey, UncheckedFrom}; /// A secret seed. It's not called a "secret key" because ring doesn't expose the secret keys /// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we @@ -282,41 +282,43 @@ impl Public { Public(data) } - /// A new instance from the given slice that should be 32 bytes long. + /// A new instance from an H256. /// /// NOTE: No checking goes on to ensure this is a real public key. Only use it if /// you are certain that the array actually is a pubkey. GIGO! - pub fn from_slice(data: &[u8]) -> Self { - let mut r = [0u8; 32]; - r.copy_from_slice(data); - Public(r) + pub fn from_h256(x: H256) -> Self { + Public(x.into()) } - /// A new instance from an H256. + /// Return a slice filled with raw data. + pub fn as_array_ref(&self) -> &[u8; 32] { + self.as_ref() + } +} + +impl TraitPublic for Public { + /// A new instance from the given slice that should be 32 bytes long. /// /// NOTE: No checking goes on to ensure this is a real public key. Only use it if /// you are certain that the array actually is a pubkey. GIGO! - pub fn from_h256(x: H256) -> Self { - Public(x.into()) + fn from_slice(data: &[u8]) -> Self { + let mut r = [0u8; 32]; + r.copy_from_slice(data); + Public(r) } /// Return a `Vec` filled with raw data. #[cfg(feature = "std")] - pub fn to_raw_vec(self) -> Vec { + fn to_raw_vec(&self) -> Vec { let r: &[u8; 32] = self.as_ref(); r.to_vec() } /// Return a slice filled with raw data. - pub fn as_slice(&self) -> &[u8] { + fn as_slice(&self) -> &[u8] { let r: &[u8; 32] = self.as_ref(); &r[..] } - - /// Return a slice filled with raw data. - pub fn as_array_ref(&self) -> &[u8; 32] { - self.as_ref() - } } #[cfg(feature = "std")] @@ -460,6 +462,11 @@ impl TraitPair for Pair { _ => false, } } + + /// Return a vec filled with raw data. + fn to_raw_vec(&self) -> Vec { + self.seed().to_vec() + } } #[cfg(feature = "std")] @@ -481,6 +488,19 @@ impl Pair { } } +impl TypedKey for Public { + const KEY_TYPE: KeyTypeId = key_types::ED25519; +} + +impl TypedKey for Signature { + const KEY_TYPE: KeyTypeId = key_types::ED25519; +} + +#[cfg(feature = "std")] +impl TypedKey for Pair { + const KEY_TYPE: KeyTypeId = key_types::ED25519; +} + #[cfg(test)] mod test { use super::*; diff --git a/core/primitives/src/lib.rs b/core/primitives/src/lib.rs index 7c0fd324fe0e1aaa25403dd6a920f2f526205d19..4fabb04ccb0383aa30ed99399639dd98bbe01d11 100644 --- a/core/primitives/src/lib.rs +++ b/core/primitives/src/lib.rs @@ -69,7 +69,7 @@ pub use self::hash::{H160, H256, H512, convert_hash}; pub use self::uint::U256; pub use changes_trie::ChangesTrieConfiguration; #[cfg(feature = "std")] -pub use crypto::{DeriveJunction, Pair}; +pub use crypto::{DeriveJunction, Pair, Public}; pub use hash_db::Hasher; // Switch back to Blake after PoC-3 is out diff --git a/core/primitives/src/offchain.rs b/core/primitives/src/offchain.rs index 7d54c9d61eb31d47d8e3bca8232544ca915203b2..2ea93423d972723a318098fc907435cc9d89a4b0 100644 --- a/core/primitives/src/offchain.rs +++ b/core/primitives/src/offchain.rs @@ -16,18 +16,57 @@ //! Offchain workers types +use crate::crypto; +use parity_codec::{Encode, Decode}; use rstd::prelude::{Vec, Box}; use rstd::convert::TryFrom; /// A type of supported crypto. -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Debug))] +#[repr(C)] +pub enum StorageKind { + /// Persistent storage is non-revertible and not fork-aware. It means that any value + /// set by the offchain worker triggered at block `N(hash1)` is persisted even + /// if that block is reverted as non-canonical and is available for the worker + /// that is re-run at block `N(hash2)`. + /// This storage can be used by offchain workers to handle forks + /// and coordinate offchain workers running on different forks. + PERSISTENT = 1, + /// Local storage is revertible and fork-aware. It means that any value + /// set by the offchain worker triggered at block `N(hash1)` is reverted + /// if that block is reverted as non-canonical and is NOT available for the worker + /// that is re-run at block `N(hash2)`. + LOCAL = 2, +} + +impl TryFrom for StorageKind { + type Error = (); + + fn try_from(kind: u32) -> Result { + match kind { + e if e == u32::from(StorageKind::PERSISTENT as u8) => Ok(StorageKind::PERSISTENT), + e if e == u32::from(StorageKind::LOCAL as u8) => Ok(StorageKind::LOCAL), + _ => Err(()), + } + } +} + +impl From for u32 { + fn from(c: StorageKind) -> Self { + c as u8 as u32 + } +} + +/// A type of supported crypto. +#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug))] #[repr(C)] pub enum CryptoKind { /// SR25519 crypto (Schnorrkel) - Sr25519 = 1, + Sr25519 = crypto::key_types::SR25519 as isize, /// ED25519 crypto (Edwards) - Ed25519 = 2, + Ed25519 = crypto::key_types::ED25519 as isize, } impl TryFrom for CryptoKind { @@ -35,23 +74,41 @@ impl TryFrom for CryptoKind { fn try_from(kind: u32) -> Result { match kind { - e if e == u32::from(CryptoKind::Sr25519 as u8) => Ok(CryptoKind::Sr25519), - e if e == u32::from(CryptoKind::Ed25519 as u8) => Ok(CryptoKind::Ed25519), - _ => Err(()) + e if e == CryptoKind::Sr25519 as isize as u32 => Ok(CryptoKind::Sr25519), + e if e == CryptoKind::Ed25519 as isize as u32 => Ok(CryptoKind::Ed25519), + _ => Err(()), } } } +impl From for u32 { + fn from(c: CryptoKind) -> Self { + c as isize as u32 + } +} + /// Opaque type for created crypto keys. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "std", derive(Debug))] pub struct CryptoKeyId(pub u16); +impl From for u32 { + fn from(c: CryptoKeyId) -> Self { + c.0 as u32 + } +} + /// Opaque type for offchain http requests. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "std", derive(Debug))] pub struct HttpRequestId(pub u16); +impl From for u32 { + fn from(c: HttpRequestId) -> Self { + c.0 as u32 + } +} + /// An error enum returned by some http methods. #[derive(Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Debug))] @@ -75,6 +132,12 @@ impl TryFrom for HttpError { } } +impl From for u32 { + fn from(c: HttpError) -> Self { + c as u8 as u32 + } +} + /// Status of the HTTP request #[derive(Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Debug))] @@ -185,31 +248,34 @@ pub trait Externalities { /// Encrypt a piece of data using given crypto key. /// - /// If `key` is `None`, it will attempt to use current authority key. + /// If `key` is `None`, it will attempt to use current authority key of `CryptoKind`. /// - /// Returns an error if `key` is not available or does not exist. - fn encrypt(&mut self, key: Option, data: &[u8]) -> Result, ()>; + /// Returns an error if `key` is not available or does not exist, + /// or the expected `CryptoKind` does not match. + fn encrypt(&mut self, key: Option, kind: CryptoKind, data: &[u8]) -> Result, ()>; /// Decrypt a piece of data using given crypto key. /// - /// If `key` is `None`, it will attempt to use current authority key. + /// If `key` is `None`, it will attempt to use current authority key of `CryptoKind`. /// - /// Returns an error if data cannot be decrypted or the `key` is not available or does not exist. - fn decrypt(&mut self, key: Option, data: &[u8]) -> Result, ()>; + /// Returns an error if data cannot be decrypted or the `key` is not available or does not exist, + /// or the expected `CryptoKind` does not match. + fn decrypt(&mut self, key: Option, kind: CryptoKind, data: &[u8]) -> Result, ()>; /// Sign a piece of data using given crypto key. /// - /// If `key` is `None`, it will attempt to use current authority key. + /// If `key` is `None`, it will attempt to use current authority key of `CryptoKind`. /// - /// Returns an error if `key` is not available or does not exist. - fn sign(&mut self, key: Option, data: &[u8]) -> Result, ()>; + /// Returns an error if `key` is not available or does not exist, + /// or the expected `CryptoKind` does not match. + fn sign(&mut self, key: Option, kind: CryptoKind, data: &[u8]) -> Result, ()>; /// Verifies that `signature` for `msg` matches given `key`. /// /// Returns an `Ok` with `true` in case it does, `false` in case it doesn't. /// Returns an error in case the key is not available or does not exist or the parameters - /// lengths are incorrect. - fn verify(&mut self, key: Option, msg: &[u8], signature: &[u8]) -> Result; + /// lengths are incorrect or `CryptoKind` does not match. + fn verify(&mut self, key: Option, kind: CryptoKind, msg: &[u8], signature: &[u8]) -> Result; /// Returns current UNIX timestamp (in millis) fn timestamp(&mut self) -> Timestamp; @@ -227,23 +293,31 @@ pub trait Externalities { /// /// Note this storage is not part of the consensus, it's only accessible by /// offchain worker tasks running on the same machine. It IS persisted between runs. - fn local_storage_set(&mut self, key: &[u8], value: &[u8]); + fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]); /// Sets a value in the local storage if it matches current value. /// /// Since multiple offchain workers may be running concurrently, to prevent /// data races use CAS to coordinate between them. /// + /// Returns `true` if the value has been set, `false` otherwise. + /// /// Note this storage is not part of the consensus, it's only accessible by /// offchain worker tasks running on the same machine. It IS persisted between runs. - fn local_storage_compare_and_set(&mut self, key: &[u8], old_value: &[u8], new_value: &[u8]); + fn local_storage_compare_and_set( + &mut self, + kind: StorageKind, + key: &[u8], + old_value: &[u8], + new_value: &[u8], + ) -> bool; /// Gets a value from the local storage. /// /// If the value does not exist in the storage `None` will be returned. /// Note this storage is not part of the consensus, it's only accessible by /// offchain worker tasks running on the same machine. It IS persisted between runs. - fn local_storage_get(&mut self, key: &[u8]) -> Option>; + fn local_storage_get(&mut self, kind: StorageKind, key: &[u8]) -> Option>; /// Initiaties a http request given HTTP verb and the URL. /// @@ -320,20 +394,20 @@ impl Externalities for Box { (&mut **self).new_crypto_key(crypto) } - fn encrypt(&mut self, key: Option, data: &[u8]) -> Result, ()> { - (&mut **self).encrypt(key, data) + fn encrypt(&mut self, key: Option, kind: CryptoKind, data: &[u8]) -> Result, ()> { + (&mut **self).encrypt(key, kind, data) } - fn decrypt(&mut self, key: Option, data: &[u8]) -> Result, ()> { - (&mut **self).decrypt(key, data) + fn decrypt(&mut self, key: Option, kind: CryptoKind, data: &[u8]) -> Result, ()> { + (&mut **self).decrypt(key, kind, data) } - fn sign(&mut self, key: Option, data: &[u8]) -> Result, ()> { - (&mut **self).sign(key, data) + fn sign(&mut self, key: Option, kind: CryptoKind, data: &[u8]) -> Result, ()> { + (&mut **self).sign(key, kind, data) } - fn verify(&mut self, key: Option, msg: &[u8], signature: &[u8]) -> Result { - (&mut **self).verify(key, msg, signature) + fn verify(&mut self, key: Option, kind: CryptoKind, msg: &[u8], signature: &[u8]) -> Result { + (&mut **self).verify(key, kind, msg, signature) } fn timestamp(&mut self) -> Timestamp { @@ -348,16 +422,22 @@ impl Externalities for Box { (&mut **self).random_seed() } - fn local_storage_set(&mut self, key: &[u8], value: &[u8]) { - (&mut **self).local_storage_set(key, value) + fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]) { + (&mut **self).local_storage_set(kind, key, value) } - fn local_storage_compare_and_set(&mut self, key: &[u8], old_value: &[u8], new_value: &[u8]) { - (&mut **self).local_storage_compare_and_set(key, old_value, new_value) + fn local_storage_compare_and_set( + &mut self, + kind: StorageKind, + key: &[u8], + old_value: &[u8], + new_value: &[u8], + ) -> bool { + (&mut **self).local_storage_compare_and_set(kind, key, old_value, new_value) } - fn local_storage_get(&mut self, key: &[u8]) -> Option> { - (&mut **self).local_storage_get(key) + fn local_storage_get(&mut self, kind: StorageKind, key: &[u8]) -> Option> { + (&mut **self).local_storage_get(kind, key) } fn http_request_start(&mut self, method: &str, uri: &str, meta: &[u8]) -> Result { diff --git a/core/primitives/src/sr25519.rs b/core/primitives/src/sr25519.rs index aa2db2dc1263cb8a3897ad51a1848b161c8e0f1b..e01d989143c6b8491680bb18c1a95a11e7540e32 100644 --- a/core/primitives/src/sr25519.rs +++ b/core/primitives/src/sr25519.rs @@ -31,13 +31,14 @@ use substrate_bip39::mini_secret_from_entropy; use bip39::{Mnemonic, Language, MnemonicType}; #[cfg(feature = "std")] use crate::crypto::{Pair as TraitPair, DeriveJunction, Infallible, SecretStringError, Derive, Ss58Codec}; -use crate::{hash::{H256, H512}, crypto::UncheckedFrom}; +use crate::crypto::{key_types, KeyTypeId, Public as TraitPublic, TypedKey, UncheckedFrom}; +use crate::hash::{H256, H512}; use parity_codec::{Encode, Decode}; #[cfg(feature = "std")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "std")] -use schnorrkel::keys::MINI_SECRET_KEY_LENGTH; +use schnorrkel::keys::{MINI_SECRET_KEY_LENGTH, SECRET_KEY_LENGTH}; // signing context #[cfg(feature = "std")] @@ -51,6 +52,17 @@ pub struct Public(pub [u8; 32]); #[cfg(feature = "std")] pub struct Pair(Keypair); +#[cfg(feature = "std")] +impl Clone for Pair { + fn clone(&self) -> Self { + Pair(schnorrkel::Keypair { + public: self.0.public.clone(), + secret: schnorrkel::SecretKey::from_bytes(&self.0.secret.to_bytes()[..]) + .expect("key is always the correct size; qed") + }) + } +} + impl AsRef for Public { fn as_ref(&self) -> &Public { &self @@ -282,39 +294,41 @@ impl Public { Public(data) } - /// A new instance from the given slice that should be 32 bytes long. + /// A new instance from an H256. /// /// NOTE: No checking goes on to ensure this is a real public key. Only use it if /// you are certain that the array actually is a pubkey. GIGO! - pub fn from_slice(data: &[u8]) -> Self { - let mut r = [0u8; 32]; - r.copy_from_slice(data); - Public(r) + pub fn from_h256(x: H256) -> Self { + Public(x.into()) } - /// A new instance from an H256. + /// Return a slice filled with raw data. + pub fn as_array_ref(&self) -> &[u8; 32] { + self.as_ref() + } +} + +impl TraitPublic for Public { + /// A new instance from the given slice that should be 32 bytes long. /// /// NOTE: No checking goes on to ensure this is a real public key. Only use it if /// you are certain that the array actually is a pubkey. GIGO! - pub fn from_h256(x: H256) -> Self { - Public(x.into()) + fn from_slice(data: &[u8]) -> Self { + let mut r = [0u8; 32]; + r.copy_from_slice(data); + Public(r) } /// Return a `Vec` filled with raw data. #[cfg(feature = "std")] - pub fn into_raw_vec(self) -> Vec { + fn to_raw_vec(&self) -> Vec { self.0.to_vec() } /// Return a slice filled with raw data. - pub fn as_slice(&self) -> &[u8] { + fn as_slice(&self) -> &[u8] { &self.0 } - - /// Return a slice filled with raw data. - pub fn as_array_ref(&self) -> &[u8; 32] { - self.as_ref() - } } #[cfg(feature = "std")] @@ -365,6 +379,7 @@ fn derive_hard_junction(secret: &SecretKey, cc: &[u8; CHAIN_CODE_LENGTH]) -> Sec secret.hard_derive_mini_secret_key(Some(ChainCode(cc.clone())), b"").0.expand() } +/// The raw secret seed, which can be used to recreate the `Pair`. #[cfg(feature = "std")] type Seed = [u8; MINI_SECRET_KEY_LENGTH]; @@ -397,14 +412,22 @@ impl TraitPair for Pair { /// /// You should never need to use this; generate(), generate_with_phrase(), from_phrase() fn from_seed_slice(seed: &[u8]) -> Result { - if seed.len() != MINI_SECRET_KEY_LENGTH { - Err(SecretStringError::InvalidSeedLength) - } else { - Ok(Pair( - MiniSecretKey::from_bytes(seed) - .map_err(|_| SecretStringError::InvalidSeed)? - .expand_to_keypair() - )) + match seed.len() { + MINI_SECRET_KEY_LENGTH => { + Ok(Pair( + MiniSecretKey::from_bytes(seed) + .map_err(|_| SecretStringError::InvalidSeed)? + .expand_to_keypair() + )) + } + SECRET_KEY_LENGTH => { + Ok(Pair( + SecretKey::from_bytes(seed) + .map_err(|_| SecretStringError::InvalidSeed)? + .to_keypair() + )) + } + _ => Err(SecretStringError::InvalidSeedLength) } } @@ -478,6 +501,11 @@ impl TraitPair for Pair { Err(_) => false, } } + + /// Return a vec filled with raw data. + fn to_raw_vec(&self) -> Vec { + self.0.secret.to_bytes().to_vec() + } } #[cfg(feature = "std")] @@ -495,6 +523,19 @@ impl Pair { } } +impl TypedKey for Public { + const KEY_TYPE: KeyTypeId = key_types::SR25519; +} + +impl TypedKey for Signature { + const KEY_TYPE: KeyTypeId = key_types::SR25519; +} + +#[cfg(feature = "std")] +impl TypedKey for Pair { + const KEY_TYPE: KeyTypeId = key_types::SR25519; +} + #[cfg(test)] mod test { use super::*; diff --git a/core/rpc-servers/Cargo.toml b/core/rpc-servers/Cargo.toml index bca094b572d5f1d6ed6f5a143f8eaa27d1168bed..64a494f65ffe74b870720c2b0feb02de6e0ff46d 100644 --- a/core/rpc-servers/Cargo.toml +++ b/core/rpc-servers/Cargo.toml @@ -5,10 +5,12 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -http = { package = "jsonrpc-http-server", version = "12.0.0" } pubsub = { package = "jsonrpc-pubsub", version = "12.0.0" } -ws = { package = "jsonrpc-ws-server", version = "12.0.0" } log = "0.4" serde = "1.0" substrate-rpc = { path = "../rpc" } sr-primitives = { path = "../sr-primitives" } + +[target.'cfg(not(target_os = "unknown"))'.dependencies] +http = { package = "jsonrpc-http-server", version = "12.0.0" } +ws = { package = "jsonrpc-ws-server", version = "12.0.0" } diff --git a/core/rpc-servers/src/lib.rs b/core/rpc-servers/src/lib.rs index adf560ce5a6375eeee780ecace7ef6c42908959a..a33f726747149414ebc8e90dd59e0f04791e332c 100644 --- a/core/rpc-servers/src/lib.rs +++ b/core/rpc-servers/src/lib.rs @@ -30,10 +30,10 @@ const MAX_PAYLOAD: usize = 15 * 1024 * 1024; /// Default maximum number of connections for WS RPC servers. const WS_MAX_CONNECTIONS: usize = 100; -type Metadata = apis::metadata::Metadata; -type RpcHandler = pubsub::PubSubHandler; -pub type HttpServer = http::Server; -pub type WsServer = ws::Server; +pub type Metadata = apis::metadata::Metadata; +pub type RpcHandler = pubsub::PubSubHandler; + +pub use self::inner::*; /// Construct rpc `IoHandler` pub fn rpc_handler( @@ -57,49 +57,78 @@ pub fn rpc_handler( io } -/// Start HTTP server listening on given address. -pub fn start_http( - addr: &std::net::SocketAddr, - cors: Option<&Vec>, - io: RpcHandler, -) -> io::Result { - http::ServerBuilder::new(io) - .threads(4) - .health_api(("/health", "system_health")) - .rest_api(if cors.is_some() { - http::RestApi::Secure - } else { - http::RestApi::Unsecure - }) - .cors(map_cors::(cors)) - .max_request_body_size(MAX_PAYLOAD) - .start_http(addr) -} +#[cfg(not(target_os = "unknown"))] +mod inner { + use super::*; + + pub type HttpServer = http::Server; + pub type WsServer = ws::Server; -/// Start WS server listening on given address. -pub fn start_ws( - addr: &std::net::SocketAddr, - max_connections: Option, - cors: Option<&Vec>, - io: RpcHandler, -) -> io::Result { - ws::ServerBuilder::with_meta_extractor(io, |context: &ws::RequestContext| Metadata::new(context.sender())) - .max_payload(MAX_PAYLOAD) - .max_connections(max_connections.unwrap_or(WS_MAX_CONNECTIONS)) - .allowed_origins(map_cors(cors)) - .start(addr) - .map_err(|err| match err { - ws::Error::Io(io) => io, - ws::Error::ConnectionClosed => io::ErrorKind::BrokenPipe.into(), - e => { - error!("{}", e); - io::ErrorKind::Other.into() - } - }) + /// Start HTTP server listening on given address. + /// + /// **Note**: Only available if `not(target_os = "unknown")`. + pub fn start_http( + addr: &std::net::SocketAddr, + cors: Option<&Vec>, + io: RpcHandler, + ) -> io::Result { + http::ServerBuilder::new(io) + .threads(4) + .health_api(("/health", "system_health")) + .allowed_hosts(hosts_filtering(cors.is_some())) + .rest_api(if cors.is_some() { + http::RestApi::Secure + } else { + http::RestApi::Unsecure + }) + .cors(map_cors::(cors)) + .max_request_body_size(MAX_PAYLOAD) + .start_http(addr) + } + + /// Start WS server listening on given address. + /// + /// **Note**: Only available if `not(target_os = "unknown")`. + pub fn start_ws( + addr: &std::net::SocketAddr, + max_connections: Option, + cors: Option<&Vec>, + io: RpcHandler, + ) -> io::Result { + ws::ServerBuilder::with_meta_extractor(io, |context: &ws::RequestContext| Metadata::new(context.sender())) + .max_payload(MAX_PAYLOAD) + .max_connections(max_connections.unwrap_or(WS_MAX_CONNECTIONS)) + .allowed_origins(map_cors(cors)) + .allowed_hosts(hosts_filtering(cors.is_some())) + .start(addr) + .map_err(|err| match err { + ws::Error::Io(io) => io, + ws::Error::ConnectionClosed => io::ErrorKind::BrokenPipe.into(), + e => { + error!("{}", e); + io::ErrorKind::Other.into() + } + }) + } + + fn map_cors From<&'a str>>( + cors: Option<&Vec> + ) -> http::DomainsValidation { + cors.map(|x| x.iter().map(AsRef::as_ref).map(Into::into).collect::>()).into() + } + + fn hosts_filtering(enable: bool) -> http::DomainsValidation { + if enable { + // NOTE The listening address is whitelisted by default. + // Setting an empty vector here enables the validation + // and allows only the listening address. + http::DomainsValidation::AllowOnly(vec![]) + } else { + http::DomainsValidation::Disabled + } + } } -fn map_cors From<&'a str>>( - cors: Option<&Vec> -) -> http::DomainsValidation { - cors.map(|x| x.iter().map(AsRef::as_ref).map(Into::into).collect::>()).into() +#[cfg(target_os = "unknown")] +mod inner { } diff --git a/core/rpc/Cargo.toml b/core/rpc/Cargo.toml index e72f62e5000ca26c80a8e42761a6f1e44e43bdd0..181cbdfd8ea5f28ab7a361161e7a6859192aba6a 100644 --- a/core/rpc/Cargo.toml +++ b/core/rpc/Cargo.toml @@ -7,13 +7,14 @@ edition = "2018" [dependencies] derive_more = "0.14.0" futures = "0.1" +futures03 = { package = "futures-preview", version = "0.3.0-alpha.17", features = ["compat"] } jsonrpc-core = "12.0.0" jsonrpc-core-client = "12.0.0" jsonrpc-pubsub = "12.0.0" jsonrpc-derive = "12.0.0" log = "0.4" parking_lot = "0.8.0" -parity-codec = "3.3" +parity-codec = "4.1.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" client = { package = "substrate-client", path = "../client" } @@ -24,7 +25,6 @@ state_machine = { package = "substrate-state-machine", path = "../state-machine" transaction_pool = { package = "substrate-transaction-pool", path = "../transaction-pool" } runtime_primitives = { package = "sr-primitives", path = "../sr-primitives" } runtime_version = { package = "sr-version", path = "../sr-version" } -tokio = "0.1.7" [dev-dependencies] assert_matches = "1.1" @@ -32,3 +32,4 @@ futures = "0.1.17" sr-io = { path = "../sr-io" } test-client = { package = "substrate-test-runtime-client", path = "../test-runtime/client" } rustc-hex = "2.0" +tokio = "0.1.17" diff --git a/core/rpc/src/author/tests.rs b/core/rpc/src/author/tests.rs index 4c6a724acd5ae35bbf4ccbfbe71e7999a7d684e6..cf320ee1442e7aff950850143d65155137c62d49 100644 --- a/core/rpc/src/author/tests.rs +++ b/core/rpc/src/author/tests.rs @@ -44,7 +44,7 @@ fn submit_transaction_should_not_cause_error() { let p = Author { client: client.clone(), pool: Arc::new(Pool::new(Default::default(), ChainApi::new(client))), - subscriptions: Subscriptions::new(runtime.executor()), + subscriptions: Subscriptions::new(Arc::new(runtime.executor())), }; let xt = uxt(AccountKeyring::Alice, 1).encode(); let h: H256 = blake2_256(&xt).into(); @@ -65,7 +65,7 @@ fn submit_rich_transaction_should_not_cause_error() { let p = Author { client: client.clone(), pool: Arc::new(Pool::new(Default::default(), ChainApi::new(client.clone()))), - subscriptions: Subscriptions::new(runtime.executor()), + subscriptions: Subscriptions::new(Arc::new(runtime.executor())), }; let xt = uxt(AccountKeyring::Alice, 0).encode(); let h: H256 = blake2_256(&xt).into(); @@ -88,7 +88,7 @@ fn should_watch_extrinsic() { let p = Author { client, pool: pool.clone(), - subscriptions: Subscriptions::new(runtime.executor()), + subscriptions: Subscriptions::new(Arc::new(runtime.executor())), }; let (subscriber, id_rx, data) = ::jsonrpc_pubsub::typed::Subscriber::new_test("test"); @@ -128,7 +128,7 @@ fn should_return_pending_extrinsics() { let p = Author { client, pool: pool.clone(), - subscriptions: Subscriptions::new(runtime.executor()), + subscriptions: Subscriptions::new(Arc::new(runtime.executor())), }; let ex = uxt(AccountKeyring::Alice, 0); AuthorApi::submit_extrinsic(&p, ex.encode().into()).unwrap(); @@ -146,7 +146,7 @@ fn should_remove_extrinsics() { let p = Author { client, pool: pool.clone(), - subscriptions: Subscriptions::new(runtime.executor()), + subscriptions: Subscriptions::new(Arc::new(runtime.executor())), }; let ex1 = uxt(AccountKeyring::Alice, 0); p.submit_extrinsic(ex1.encode().into()).unwrap(); diff --git a/core/rpc/src/chain/mod.rs b/core/rpc/src/chain/mod.rs index 3594ed48e3aaf990919131c3779c096c400cb779..d1d476c3ab43dbf3656b4eedbff4112bb71f0da6 100644 --- a/core/rpc/src/chain/mod.rs +++ b/core/rpc/src/chain/mod.rs @@ -23,6 +23,7 @@ pub mod number; mod tests; use std::sync::Arc; +use futures03::{future, StreamExt as _, TryStreamExt as _}; use client::{self, Client, BlockchainEvents}; use crate::rpc::Result as RpcResult; @@ -203,8 +204,9 @@ impl ChainApi, Block::Hash, Block::Header, Sig subscriber, || self.block_hash(None.into()), || self.client.import_notification_stream() - .filter(|notification| notification.is_new_best) - .map(|notification| notification.header), + .filter(|notification| future::ready(notification.is_new_best)) + .map(|notification| Ok::<_, ()>(notification.header)) + .compat(), ) } @@ -217,7 +219,8 @@ impl ChainApi, Block::Hash, Block::Header, Sig subscriber, || Ok(Some(self.client.info().chain.finalized_hash)), || self.client.finality_notification_stream() - .map(|notification| notification.header), + .map(|notification| Ok::<_, ()>(notification.header)) + .compat(), ) } diff --git a/core/rpc/src/chain/tests.rs b/core/rpc/src/chain/tests.rs index eed9ae836b8b5cbdb88da859cb58a54b9ae16207..e6fa4d94e5b0dfa96bfebc615eeb9aede6e40082 100644 --- a/core/rpc/src/chain/tests.rs +++ b/core/rpc/src/chain/tests.rs @@ -29,7 +29,7 @@ fn should_return_header() { let client = Chain { client: Arc::new(test_client::new()), - subscriptions: Subscriptions::new(remote), + subscriptions: Subscriptions::new(Arc::new(remote)), }; assert_matches!( @@ -67,7 +67,7 @@ fn should_return_a_block() { let api = Chain { client: Arc::new(test_client::new()), - subscriptions: Subscriptions::new(remote), + subscriptions: Subscriptions::new(Arc::new(remote)), }; let block = api.client.new_block(Default::default()).unwrap().bake().unwrap(); @@ -121,7 +121,7 @@ fn should_return_block_hash() { let client = Chain { client: Arc::new(test_client::new()), - subscriptions: Subscriptions::new(remote), + subscriptions: Subscriptions::new(Arc::new(remote)), }; assert_matches!( @@ -165,7 +165,7 @@ fn should_return_finalized_hash() { let client = Chain { client: Arc::new(test_client::new()), - subscriptions: Subscriptions::new(remote), + subscriptions: Subscriptions::new(Arc::new(remote)), }; assert_matches!( @@ -199,7 +199,7 @@ fn should_notify_about_latest_block() { { let api = Chain { client: Arc::new(test_client::new()), - subscriptions: Subscriptions::new(remote), + subscriptions: Subscriptions::new(Arc::new(remote)), }; api.subscribe_new_head(Default::default(), subscriber); @@ -230,7 +230,7 @@ fn should_notify_about_finalized_block() { { let api = Chain { client: Arc::new(test_client::new()), - subscriptions: Subscriptions::new(remote), + subscriptions: Subscriptions::new(Arc::new(remote)), }; api.subscribe_finalized_heads(Default::default(), subscriber); diff --git a/core/rpc/src/state/mod.rs b/core/rpc/src/state/mod.rs index 0b3b93885e16cf4f1dc3338f172643fcb73d2698..40ee94fdb292e6b6217e14d44bd351661c2c73ab 100644 --- a/core/rpc/src/state/mod.rs +++ b/core/rpc/src/state/mod.rs @@ -26,6 +26,7 @@ use std::{ ops::Range, sync::Arc, }; +use futures03::{future, StreamExt as _, TryStreamExt as _}; use client::{self, Client, CallExecutor, BlockchainEvents, runtime_api::Metadata}; use crate::rpc::Result as RpcResult; @@ -484,14 +485,14 @@ impl StateApi for State where self.subscriptions.add(subscriber, |sink| { let stream = stream - .map_err(|e| warn!("Error creating storage notification stream: {:?}", e)) - .map(|(block, changes)| Ok(StorageChangeSet { + .map(|(block, changes)| Ok::<_, ()>(Ok(StorageChangeSet { block, changes: changes.iter() .filter_map(|(o_sk, k, v)| if o_sk.is_none() { Some((k.clone(),v.cloned())) } else { None }).collect(), - })); + }))) + .compat(); sink .sink_map_err(|e| warn!("Error sending notifications: {:?}", e)) @@ -530,7 +531,6 @@ impl StateApi for State where let mut previous_version = version.clone(); let stream = stream - .map_err(|e| warn!("Error creating storage notification stream: {:?}", e)) .filter_map(move |_| { let info = client.info(); let version = client @@ -539,11 +539,12 @@ impl StateApi for State where .map_err(Into::into); if previous_version != version { previous_version = version.clone(); - Some(version) + future::ready(Some(Ok::<_, ()>(version))) } else { - None + future::ready(None) } - }); + }) + .compat(); sink .sink_map_err(|e| warn!("Error sending notifications: {:?}", e)) diff --git a/core/rpc/src/state/tests.rs b/core/rpc/src/state/tests.rs index f8cb19451337aae09b0c475aa67a9cb04f386791..6a8eefa10b660d2785e16740e7e064a959963e83 100644 --- a/core/rpc/src/state/tests.rs +++ b/core/rpc/src/state/tests.rs @@ -32,7 +32,7 @@ fn should_return_storage() { let core = tokio::runtime::Runtime::new().unwrap(); let client = Arc::new(test_client::new()); let genesis_hash = client.genesis_hash(); - let client = State::new(client, Subscriptions::new(core.executor())); + let client = State::new(client, Subscriptions::new(Arc::new(core.executor()))); let key = StorageKey(b":code".to_vec()); assert_eq!( @@ -57,7 +57,7 @@ fn should_return_child_storage() { .add_child_storage("test", "key", vec![42_u8]) .build()); let genesis_hash = client.genesis_hash(); - let client = State::new(client, Subscriptions::new(core.executor())); + let client = State::new(client, Subscriptions::new(Arc::new(core.executor()))); let child_key = StorageKey(well_known_keys::CHILD_STORAGE_KEY_PREFIX.iter().chain(b"test").cloned().collect()); let key = StorageKey(b"key".to_vec()); @@ -82,7 +82,7 @@ fn should_call_contract() { let core = tokio::runtime::Runtime::new().unwrap(); let client = Arc::new(test_client::new()); let genesis_hash = client.genesis_hash(); - let client = State::new(client, Subscriptions::new(core.executor())); + let client = State::new(client, Subscriptions::new(Arc::new(core.executor()))); assert_matches!( client.call("balanceOf".into(), Bytes(vec![1,2,3]), Some(genesis_hash).into()), @@ -97,7 +97,7 @@ fn should_notify_about_storage_changes() { let (subscriber, id, transport) = Subscriber::new_test("test"); { - let api = State::new(Arc::new(test_client::new()), Subscriptions::new(remote)); + let api = State::new(Arc::new(test_client::new()), Subscriptions::new(Arc::new(remote))); api.subscribe_storage(Default::default(), subscriber, None.into()); @@ -128,7 +128,7 @@ fn should_send_initial_storage_changes_and_notifications() { let (subscriber, id, transport) = Subscriber::new_test("test"); { - let api = State::new(Arc::new(test_client::new()), Subscriptions::new(remote)); + let api = State::new(Arc::new(test_client::new()), Subscriptions::new(Arc::new(remote))); let alice_balance_key = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Alice.into())); @@ -163,7 +163,7 @@ fn should_send_initial_storage_changes_and_notifications() { fn should_query_storage() { fn run_tests(client: Arc) { let core = tokio::runtime::Runtime::new().unwrap(); - let api = State::new(client.clone(), Subscriptions::new(core.executor())); + let api = State::new(client.clone(), Subscriptions::new(Arc::new(core.executor()))); let add_block = |nonce| { let mut builder = client.new_block(Default::default()).unwrap(); @@ -254,7 +254,7 @@ fn should_return_runtime_version() { let core = tokio::runtime::Runtime::new().unwrap(); let client = Arc::new(test_client::new()); - let api = State::new(client.clone(), Subscriptions::new(core.executor())); + let api = State::new(client.clone(), Subscriptions::new(Arc::new(core.executor()))); let result = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":1,\ \"specVersion\":1,\"implVersion\":1,\"apis\":[[\"0xdf6acb689907609b\",2],\ @@ -274,7 +274,7 @@ fn should_notify_on_runtime_version_initially() { { let client = Arc::new(test_client::new()); - let api = State::new(client.clone(), Subscriptions::new(core.executor())); + let api = State::new(client.clone(), Subscriptions::new(Arc::new(core.executor()))); api.subscribe_runtime_version(Default::default(), subscriber); diff --git a/core/rpc/src/subscriptions.rs b/core/rpc/src/subscriptions.rs index 500f3dac4545ccf966cf558f0dc94ccbb6f192de..77e1d958f683fed3f639f8093d048bd946984677 100644 --- a/core/rpc/src/subscriptions.rs +++ b/core/rpc/src/subscriptions.rs @@ -17,12 +17,11 @@ use std::collections::HashMap; use std::sync::{Arc, atomic::{self, AtomicUsize}}; -use log::warn; +use log::{error, warn}; use jsonrpc_pubsub::{SubscriptionId, typed::{Sink, Subscriber}}; use parking_lot::Mutex; use crate::rpc::futures::sync::oneshot; use crate::rpc::futures::{Future, future}; -use tokio::runtime::TaskExecutor; type Id = u64; @@ -50,16 +49,16 @@ impl IdProvider { /// /// Takes care of assigning unique subscription ids and /// driving the sinks into completion. -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct Subscriptions { next_id: IdProvider, active_subscriptions: Arc>>>, - executor: TaskExecutor, + executor: Arc + Send>> + Send + Sync>, } impl Subscriptions { /// Creates new `Subscriptions` object. - pub fn new(executor: TaskExecutor) -> Self { + pub fn new(executor: Arc + Send>> + Send + Sync>) -> Self { Subscriptions { next_id: Default::default(), active_subscriptions: Default::default(), @@ -86,7 +85,9 @@ impl Subscriptions { .then(|_| Ok(())); self.active_subscriptions.lock().insert(id, tx); - self.executor.spawn(future); + if self.executor.execute(Box::new(future)).is_err() { + error!("Failed to spawn RPC subscription task"); + } } } diff --git a/core/service/Cargo.toml b/core/service/Cargo.toml index 21501286d4bc9ea10595f78b95cea9e6d4d4e0ec..8be5002d2d48554da02dad1ee5e775c3ec76582e 100644 --- a/core/service/Cargo.toml +++ b/core/service/Cargo.toml @@ -7,15 +7,17 @@ edition = "2018" [dependencies] derive_more = "0.14.0" futures = "0.1.17" +futures03 = { package = "futures-preview", version = "0.3.0-alpha.17", features = ["compat"] } parking_lot = "0.8.0" lazy_static = "1.0" log = "0.4" slog = {version = "^2", features = ["nested-values"]} -tokio = "0.1.7" +tokio-executor = "0.1.7" +tokio-timer = "0.2" exit-future = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -sysinfo = "0.8.0" +sysinfo = "0.9.0" target_info = "0.1" keystore = { package = "substrate-keystore", path = "../../core/keystore" } sr-io = { path = "../../core/sr-io" } @@ -25,7 +27,7 @@ consensus_common = { package = "substrate-consensus-common", path = "../../core/ network = { package = "substrate-network", path = "../../core/network" } client = { package = "substrate-client", path = "../../core/client" } client_db = { package = "substrate-client-db", path = "../../core/client/db", features = ["kvdb-rocksdb"] } -parity-codec = "3.3" +parity-codec = "4.1.1" substrate-executor = { path = "../../core/executor" } transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" } rpc = { package = "substrate-rpc-servers", path = "../../core/rpc-servers" } diff --git a/core/service/src/chain_ops.rs b/core/service/src/chain_ops.rs index 925461ca9e75d136c3d58021fc8a2c73a089c9d9..ea671211566c1fcd4ab9b6f35f0f74f97c960b53 100644 --- a/core/service/src/chain_ops.rs +++ b/core/service/src/chain_ops.rs @@ -22,7 +22,7 @@ use log::{info, warn}; use runtime_primitives::generic::{SignedBlock, BlockId}; use runtime_primitives::traits::{SaturatedConversion, Zero, One, Block, Header, NumberFor}; -use consensus_common::import_queue::{ImportQueue, IncomingBlock, Link}; +use consensus_common::import_queue::{ImportQueue, IncomingBlock, Link, BlockImportError, BlockImportResult}; use network::message; use consensus_common::BlockOrigin; @@ -111,22 +111,30 @@ impl WaitLink { } impl Link for WaitLink { - fn block_imported(&mut self, _hash: &B::Hash, _number: NumberFor) { - self.imported_blocks += 1; + fn blocks_processed( + &mut self, + imported: usize, + count: usize, + results: Vec<(Result>, BlockImportError>, B::Hash)> + ) { + self.imported_blocks += imported as u64; + if results.iter().any(|(r, _)| r.is_err()) { + warn!("There was an error importing {} blocks", count); + } } } -/// Import blocks from a binary stream. +/// Returns a future that import blocks from a binary stream. pub fn import_blocks( config: FactoryFullConfiguration, exit: E, mut input: R -) -> error::Result<()> +) -> error::Result> where F: ServiceFactory, E: Future + Send + 'static, R: Read, { let (client, mut state) = new_client::(config)?; let select_chain = components::FullComponents::::build_select_chain(&mut state, client.clone())?; - let mut queue = components::FullComponents::::build_import_queue(&mut state, client.clone(), select_chain)?; + let (mut queue, _) = components::FullComponents::::build_import_queue(&mut state, client.clone(), select_chain)?; let (exit_send, exit_recv) = std::sync::mpsc::channel(); ::std::thread::spawn(move || { @@ -168,13 +176,17 @@ pub fn import_blocks( } block_count = b; - if b % 1000 == 0 { + if b % 1000 == 0 && b != 0 { info!("#{} blocks were added to the queue", b); } } let mut link = WaitLink::new(); - tokio::run(futures::future::poll_fn(move || { + Ok(futures::future::poll_fn(move || { + if exit_recv.try_recv().is_ok() { + return Ok(Async::Ready(())); + } + let blocks_before = link.imported_blocks; queue.poll_actions(&mut link); if link.imported_blocks / 1000 != blocks_before / 1000 { @@ -185,15 +197,12 @@ pub fn import_blocks( ); } if link.imported_blocks >= count { + info!("Imported {} blocks. Best: #{}", block_count, client.info().chain.best_number); Ok(Async::Ready(())) } else { Ok(Async::NotReady) } - })); - - info!("Imported {} blocks. Best: #{}", block_count, client.info().chain.best_number); - - Ok(()) + })) } /// Revert the chain. diff --git a/core/service/src/components.rs b/core/service/src/components.rs index 73cd2a4f96357d7c7864c2b9c7f858ffa98ea4b3..aa46542048a2a82929fdf84af31f9817316fce35 100644 --- a/core/service/src/components.rs +++ b/core/service/src/components.rs @@ -16,15 +16,14 @@ //! Substrate service components. -use std::{sync::Arc, net::SocketAddr, ops::Deref, ops::DerefMut}; +use std::{sync::Arc, ops::Deref, ops::DerefMut}; use serde::{Serialize, de::DeserializeOwned}; -use tokio::runtime::TaskExecutor; use crate::chain_spec::ChainSpec; use client_db; use client::{self, Client, runtime_api}; -use crate::{error, Service, maybe_start_server}; +use crate::{error, Service, AuthorityKeyProvider}; use consensus_common::{import_queue::ImportQueue, SelectChain}; -use network::{self, OnDemand, FinalityProofProvider}; +use network::{self, OnDemand, FinalityProofProvider, config::BoxFinalityProofRequestBuilder}; use substrate_executor::{NativeExecutor, NativeExecutionDispatch}; use transaction_pool::txpool::{self, Options as TransactionPoolOptions, Pool as TransactionPool}; use runtime_primitives::{ @@ -33,14 +32,17 @@ use runtime_primitives::{ use crate::config::Configuration; use primitives::{Blake2Hasher, H256}; use rpc::{self, apis::system::SystemInfo}; -use parking_lot::Mutex; -use futures::sync::mpsc; +use futures::{prelude::*, future::Executor, sync::mpsc}; // Type aliases. -// These exist mainly to avoid typing `::Foo` all over the code. -/// Network service type for a factory. -pub type NetworkService = - network::NetworkService<::Block, ::NetworkProtocol>; +// These exist mainly to avoid typing `::Foo` all over the code. + +/// Network service type for `Components`. +pub type NetworkService = network::NetworkService< + ComponentBlock, + <::Factory as ServiceFactory>::NetworkProtocol, + ComponentExHash +>; /// Code executor type for a factory. pub type CodeExecutor = NativeExecutor<::RuntimeDispatch>; @@ -118,6 +120,11 @@ pub type ComponentClient = Client< ::RuntimeApi, >; +/// A offchain workers storage backend type. +pub type ComponentOffchainStorage = < + ::Backend as client::backend::Backend, Blake2Hasher> +>::OffchainStorage; + /// Block type for `Components` pub type ComponentBlock = <::Factory as ServiceFactory>::Block; @@ -179,72 +186,37 @@ pub type LightComponentsSetupState = IntermediateSetupState< >; /// Something that can start the RPC service. pub trait StartRPC { - type ServersHandle: Send + Sync; - fn start_rpc( client: Arc>, system_send_back: mpsc::UnboundedSender>>, system_info: SystemInfo, - rpc_http: Option, - rpc_ws: Option, - rpc_ws_max_connections: Option, - rpc_cors: Option>, task_executor: TaskExecutor, transaction_pool: Arc>, - ) -> error::Result; + ) -> rpc::RpcHandler; } impl StartRPC for C where ComponentClient: ProvideRuntimeApi, as ProvideRuntimeApi>::Api: runtime_api::Metadata>, { - type ServersHandle = (Option, Option>); - fn start_rpc( client: Arc>, system_send_back: mpsc::UnboundedSender>>, rpc_system_info: SystemInfo, - rpc_http: Option, - rpc_ws: Option, - rpc_ws_max_connections: Option, - rpc_cors: Option>, task_executor: TaskExecutor, transaction_pool: Arc>, - ) -> error::Result { - let handler = || { - let client = client.clone(); - let subscriptions = rpc::apis::Subscriptions::new(task_executor.clone()); - let chain = rpc::apis::chain::Chain::new(client.clone(), subscriptions.clone()); - let state = rpc::apis::state::State::new(client.clone(), subscriptions.clone()); - let author = rpc::apis::author::Author::new( - client.clone(), transaction_pool.clone(), subscriptions - ); - let system = rpc::apis::system::System::new( - rpc_system_info.clone(), system_send_back.clone() - ); - rpc::rpc_handler::, ComponentExHash, _, _, _, _>( - state, - chain, - author, - system, - ) - }; - - Ok(( - maybe_start_server( - rpc_http, - |address| rpc::start_http(address, rpc_cors.as_ref(), handler()), - )?, - maybe_start_server( - rpc_ws, - |address| rpc::start_ws( - address, - rpc_ws_max_connections, - rpc_cors.as_ref(), - handler(), - ), - )?.map(Mutex::new), - )) + ) -> rpc::RpcHandler { + let subscriptions = rpc::apis::Subscriptions::new(task_executor.clone()); + let chain = rpc::apis::chain::Chain::new(client.clone(), subscriptions.clone()); + let state = rpc::apis::state::State::new(client.clone(), subscriptions.clone()); + let author = rpc::apis::author::Author::new(client, transaction_pool, subscriptions); + let system = rpc::apis::system::System::new(rpc_system_info, system_send_back); + rpc::rpc_handler::, ComponentExHash, _, _, _, _>( + state, + chain, + author, + system, + ) } } @@ -262,7 +234,7 @@ fn maintain_transaction_pool( client: &Client, transaction_pool: &TransactionPool, ) -> error::Result<()> where - Block: BlockT::Out>, + Block: BlockT::Out>, Backend: client::backend::Backend, Client: ProvideRuntimeApi, as ProvideRuntimeApi>::Api: runtime_api::TaggedTransactionQueue, @@ -299,9 +271,14 @@ impl MaintainTransactionPool for C where pub trait OffchainWorker { fn offchain_workers( number: &FactoryBlockNumber, - offchain: &offchain::OffchainWorkers, ComponentBlock>, + offchain: &offchain::OffchainWorkers< + ComponentClient, + ComponentOffchainStorage, + AuthorityKeyProvider, + ComponentBlock + >, pool: &Arc>, - ) -> error::Result<()>; + ) -> error::Result + Send>>; } impl OffchainWorker for C where @@ -310,10 +287,15 @@ impl OffchainWorker for C where { fn offchain_workers( number: &FactoryBlockNumber, - offchain: &offchain::OffchainWorkers, ComponentBlock>, + offchain: &offchain::OffchainWorkers< + ComponentClient, + ComponentOffchainStorage, + AuthorityKeyProvider, + ComponentBlock + >, pool: &Arc>, - ) -> error::Result<()> { - Ok(offchain.on_block_imported(number, pool)) + ) -> error::Result + Send>> { + Ok(Box::new(offchain.on_block_imported(number, pool))) } } @@ -321,7 +303,6 @@ impl OffchainWorker for C where pub trait ServiceTrait: Deref> + Send - + Sync + 'static + StartRPC + MaintainTransactionPool @@ -330,13 +311,15 @@ pub trait ServiceTrait: impl ServiceTrait for T where T: Deref> + Send - + Sync + 'static + StartRPC + MaintainTransactionPool + OffchainWorker {} +/// Alias for a an implementation of `futures::future::Executor`. +pub type TaskExecutor = Arc + Send>> + Send + Sync>; + /// A collection of types and methods to build a service on top of the substrate service. pub trait ServiceFactory: 'static + Sized { /// Block type. @@ -394,10 +377,10 @@ pub trait ServiceFactory: 'static + Sized { ) -> Result; /// Build full service. - fn new_full(config: FactoryFullConfiguration, executor: TaskExecutor) + fn new_full(config: FactoryFullConfiguration) -> Result; /// Build light service. - fn new_light(config: FactoryFullConfiguration, executor: TaskExecutor) + fn new_light(config: FactoryFullConfiguration) -> Result; /// ImportQueue for a full client @@ -420,7 +403,7 @@ pub trait ServiceFactory: 'static + Sized { fn build_light_import_queue( state: &mut LightComponentsSetupState, _client: Arc> - ) -> Result { + ) -> Result<(Self::LightImportQueue, BoxFinalityProofRequestBuilder), error::Error> { if let Some(name) = state.config.chain_spec.consensus_engine() { match name { _ => Err(format!("Chain Specification defines unknown consensus engine '{}'", name).into()) @@ -472,12 +455,13 @@ pub trait Components: Sized + 'static { fn build_transaction_pool(config: TransactionPoolOptions, client: Arc>) -> Result, error::Error>; - /// instance of import queue for clients + /// Build the queue that imports blocks from the network, and optionally a way for the network + /// to build requests for proofs of finality. fn build_import_queue( setup: &mut ComponentsSetupState, client: Arc>, select_chain: Option, - ) -> Result; + ) -> Result<(Self::ImportQueue, Option>>), error::Error>; /// Finality proof provider for serving network requests. fn build_finality_proof_provider( @@ -499,10 +483,9 @@ pub struct FullComponents { impl FullComponents { /// Create new `FullComponents` pub fn new( - config: FactoryFullConfiguration, - task_executor: TaskExecutor + config: FactoryFullConfiguration ) -> Result<(Self, FullComponentsSetupState), error::Error> { - let (service, state) = Service::new(config, task_executor)?; + let (service, state) = Service::new(config)?; Ok((Self { service }, state)) } } @@ -521,6 +504,15 @@ impl DerefMut for FullComponents { } } +impl Future for FullComponents { + type Item = (); + type Error = (); + + fn poll(&mut self) -> Poll { + self.service.poll() + } +} + impl Components for FullComponents { type Factory = Factory; type Executor = FullExecutor; @@ -546,7 +538,7 @@ impl Components for FullComponents { state_cache_size: config.state_cache_size, state_cache_child_ratio: config.state_cache_child_ratio.map(|v| (v, 100)), - path: config.database_path.as_str().into(), + path: config.database_path.clone(), pruning: config.pruning.clone(), }; let (client, backend) = client_db::new_client( @@ -570,10 +562,11 @@ impl Components for FullComponents { setup: &mut ComponentsSetupState, client: Arc>, select_chain: Option, - ) -> Result { + ) -> Result<(Self::ImportQueue, Option>>), error::Error> { let select_chain = select_chain .ok_or(error::Error::SelectChainRequired)?; Factory::build_full_import_queue(setup, client, select_chain) + .map(|queue| (queue, None)) } fn build_select_chain( @@ -599,9 +592,8 @@ impl LightComponents { /// Create new `LightComponents` pub fn new( config: FactoryFullConfiguration, - task_executor: TaskExecutor ) -> Result { - let (service, _state) = Service::new(config, task_executor)?; + let (service, _state) = Service::new(config)?; Ok(Self { service } ) } } @@ -614,6 +606,15 @@ impl Deref for LightComponents { } } +impl Future for LightComponents { + type Item = (); + type Error = (); + + fn poll(&mut self) -> Poll { + self.service.poll() + } +} + impl Components for LightComponents { type Factory = Factory; type Executor = LightExecutor; @@ -640,7 +641,7 @@ impl Components for LightComponents { state_cache_size: config.state_cache_size, state_cache_child_ratio: config.state_cache_child_ratio.map(|v| (v, 100)), - path: config.database_path.as_str().into(), + path: config.database_path.clone(), pruning: config.pruning.clone(), }; let db_storage = client_db::light::LightStorage::new(db_settings)?; @@ -663,8 +664,9 @@ impl Components for LightComponents { state: &mut ComponentsSetupState, client: Arc>, _select_chain: Option, - ) -> Result { + ) -> Result<(Self::ImportQueue, Option>>), error::Error> { Factory::build_light_import_queue(state, client) + .map(|(queue, builder)| (queue, Some(builder))) } fn build_finality_proof_provider( diff --git a/core/service/src/config.rs b/core/service/src/config.rs index 3a49630898d42c4eff7c815db4461c986d5b17f9..6f2f51ebfb6ea6a69bf61f899adcedb8f940585f 100644 --- a/core/service/src/config.rs +++ b/core/service/src/config.rs @@ -16,12 +16,14 @@ //! Service configuration. -use std::net::SocketAddr; -use transaction_pool; -use crate::chain_spec::ChainSpec; pub use client::ExecutionStrategies; pub use client_db::PruningMode; -pub use network::config::{NetworkConfiguration, Roles}; +pub use network::config::{ExtTransport, NetworkConfiguration, Roles}; + +use std::{path::PathBuf, net::SocketAddr}; +use transaction_pool; +use crate::chain_spec::ChainSpec; +use primitives::crypto::Protected; use runtime_primitives::BuildStorage; use serde::{Serialize, de::DeserializeOwned}; use target_info::Target; @@ -43,15 +45,15 @@ pub struct Configuration { /// Network configuration. pub network: NetworkConfiguration, /// Path to key files. - pub keystore_path: String, + pub keystore_path: Option, /// Path to the database. - pub database_path: String, + pub database_path: PathBuf, /// Cache Size for internal database in MiB pub database_cache_size: Option, /// Size of internal state cache in Bytes pub state_cache_size: usize, - /// Size in percent of cache size dedicated to child tries - pub state_cache_child_ratio: Option, + /// Size in percent of cache size dedicated to child tries + pub state_cache_child_ratio: Option, /// Pruning settings. pub pruning: PruningMode, /// Additional key seeds. @@ -74,6 +76,9 @@ pub struct Configuration { pub rpc_cors: Option>, /// Telemetry service URL. `None` if disabled. pub telemetry_endpoints: Option, + /// External WASM transport for the telemetry. If `Some`, when connection to a telemetry + /// endpoint, this transport will be tried in priority before all others. + pub telemetry_external_transport: Option, /// The default number of 64KB pages to allocate for Wasm execution pub default_heap_pages: Option, /// Should offchain workers be executed. @@ -82,8 +87,11 @@ pub struct Configuration { pub force_authoring: bool, /// Disable GRANDPA when running in validator mode pub disable_grandpa: bool, + /// Run GRANDPA voter even when no additional key seed is specified. This can for example be of interest when + /// running a sentry node in front of a validator, thus needing to forward GRANDPA gossip messages. + pub grandpa_voter: bool, /// Node keystore's password - pub password: String, + pub password: Protected, } impl Configuration { @@ -112,11 +120,13 @@ impl Configuration String { let commit_dash = if impl_commit.is_empty() { "" } else { "-" }; format!("{}{}{}-{}", impl_version, commit_dash, impl_commit, platform()) } - diff --git a/core/service/src/lib.rs b/core/service/src/lib.rs index 62c53ba5d56b3cc3d367cef5c5a3ed58e809693f..7502857da9f82902064a7b73ec3daa4c8892228e 100644 --- a/core/service/src/lib.rs +++ b/core/service/src/lib.rs @@ -28,18 +28,21 @@ pub mod error; use std::io; use std::net::SocketAddr; use std::collections::HashMap; +use std::time::Duration; use futures::sync::mpsc; use parking_lot::Mutex; -use client::BlockchainEvents; +use client::{BlockchainEvents, backend::Backend, runtime_api::BlockT}; use exit_future::Signal; use futures::prelude::*; +use futures03::stream::{StreamExt as _, TryStreamExt as _}; use keystore::Store as Keystore; -use log::{info, warn, debug}; +use network::NetworkState; +use log::{info, warn, debug, error}; use parity_codec::{Encode, Decode}; -use primitives::Pair; +use primitives::{Pair, ed25519, crypto}; use runtime_primitives::generic::BlockId; -use runtime_primitives::traits::{Header, SaturatedConversion}; +use runtime_primitives::traits::{Header, NumberFor, SaturatedConversion}; use substrate_executor::NativeExecutor; use sysinfo::{get_current_pid, ProcessExt, System, SystemExt}; use tel::{telemetry, SUBSTRATE_INFO}; @@ -50,11 +53,10 @@ pub use chain_spec::{ChainSpec, Properties}; pub use transaction_pool::txpool::{ self, Pool as TransactionPool, Options as TransactionPoolOptions, ChainApi, IntoPoolError }; -use client::runtime_api::BlockT; pub use client::FinalityNotifications; pub use components::{ServiceFactory, FullBackend, FullExecutor, LightBackend, - LightExecutor, Components, PoolApi, ComponentClient, + LightExecutor, Components, PoolApi, ComponentClient, ComponentOffchainStorage, ComponentBlock, FullClient, LightClient, FullComponents, LightComponents, ComponentsSetupState, FullComponentsSetupState, LightComponentsSetupState, CodeExecutor, NetworkService, FactoryChainSpec, FactoryBlock, @@ -65,25 +67,44 @@ use components::{StartRPC, MaintainTransactionPool, OffchainWorker}; #[doc(hidden)] pub use std::{ops::Deref, result::Result, sync::Arc}; #[doc(hidden)] -pub use network::{FinalityProofProvider, OnDemand}; +pub use network::{FinalityProofProvider, OnDemand, config::BoxFinalityProofRequestBuilder}; #[doc(hidden)] -pub use tokio::runtime::TaskExecutor; +pub use futures::future::Executor; const DEFAULT_PROTOCOL_ID: &str = "sup"; /// Substrate service. pub struct Service { client: Arc>, - select_chain: Option<::SelectChain>, - network: Option>>, + select_chain: Option, + network: Arc>, + /// Sinks to propagate network status updates. + network_status_sinks: Arc>, NetworkState + )>>>>, transaction_pool: Arc>, - keystore: Keystore, + keystore: AuthorityKeyProvider, exit: ::exit_future::Exit, signal: Option, + /// Sender for futures that must be spawned as background tasks. + to_spawn_tx: mpsc::UnboundedSender + Send>>, + /// Receiver for futures that must be spawned as background tasks. + to_spawn_rx: mpsc::UnboundedReceiver + Send>>, + /// List of futures to poll from `poll`. + /// If spawning a background task is not possible, we instead push the task into this `Vec`. + /// The elements must then be polled manually. + to_poll: Vec + Send>>, + /// Configuration of this Service + rpc_handlers: rpc::RpcHandler, _rpc: Box, _telemetry: Option, - _offchain_workers: Option, ComponentBlock>>>, _telemetry_on_connect_sinks: Arc>>>, + _offchain_workers: Option, + ComponentOffchainStorage, + AuthorityKeyProvider, + ComponentBlock> + >>, } /// Creates bare client without any networking. @@ -101,17 +122,33 @@ pub fn new_client(config: FactoryFullConfig Ok((client, state)) } +/// An handle for spawning tasks in the service. +#[derive(Clone)] +pub struct SpawnTaskHandle { + sender: mpsc::UnboundedSender + Send>>, +} + +impl Executor + Send>> for SpawnTaskHandle { + fn execute( + &self, + future: Box + Send> + ) -> Result<(), futures::future::ExecuteError + Send>>> { + if let Err(err) = self.sender.unbounded_send(future) { + let kind = futures::future::ExecuteErrorKind::Shutdown; + Err(futures::future::ExecuteError::new(kind, err.into_inner())) + } else { + Ok(()) + } + } +} + /// Stream of events for connection established to a telemetry server. pub type TelemetryOnConnectNotifications = mpsc::UnboundedReceiver<()>; /// Used to hook on telemetry connection established events. -pub struct TelemetryOnConnect<'a> { - /// Handle to a future that will resolve on exit. - pub on_exit: Box + Send + 'static>, +pub struct TelemetryOnConnect { /// Event stream. pub telemetry_connection_sinks: TelemetryOnConnectNotifications, - /// Executor to which the hook is spawned. - pub executor: &'a TaskExecutor, } impl Service { @@ -124,40 +161,60 @@ impl Service { /// Creates a new service. pub fn new( - config: FactoryFullConfiguration, - task_executor: TaskExecutor, + config: FactoryFullConfiguration ) -> Result<(Self, ComponentsSetupState), error::Error> { let (signal, exit) = ::exit_future::signal(); + // List of asynchronous tasks to spawn. We collect them, then spawn them all at once. + let (to_spawn_tx, to_spawn_rx) = + mpsc::unbounded:: + Send>>(); + // Create client let executor = NativeExecutor::new(config.default_heap_pages); - let mut keystore = Keystore::open(config.keystore_path.as_str().into())?; + let mut keystore = if let Some(keystore_path) = config.keystore_path.as_ref() { + match Keystore::open(keystore_path.clone()) { + Ok(ks) => Some(ks), + Err(err) => { + error!("Failed to initialize keystore: {}", err); + None + } + } + } else { + None + }; + + // Keep the public key for telemetry + let public_key: String; // This is meant to be for testing only // FIXME #1063 remove this - for seed in &config.keys { - keystore.generate_from_seed(seed)?; - } - // Keep the public key for telemetry - let public_key = match keystore.contents()?.get(0) { - Some(public_key) => public_key.clone(), - None => { - let key = keystore.generate(&config.password)?; - let public_key = key.public(); - info!("Generated a new keypair: {:?}", public_key); - - public_key + if let Some(keystore) = keystore.as_mut() { + for seed in &config.keys { + keystore.generate_from_seed::(seed)?; } - }; + + public_key = match keystore.contents::()?.get(0) { + Some(public_key) => public_key.to_string(), + None => { + let key: ed25519::Pair = keystore.generate(&config.password.as_ref())?; + let public_key = key.public(); + info!("Generated a new keypair: {:?}", public_key); + public_key.to_string() + } + } + } else { + public_key = format!(""); + } let (client, mut state, on_demand) = Components::build_client(config, executor)?; let select_chain = Components::build_select_chain(&mut state, client.clone())?; - let import_queue = Box::new(Components::build_import_queue( + let (import_queue, finality_proof_request_builder) = Components::build_import_queue( &mut state, client.clone(), select_chain.clone(), - )?); + )?; + let import_queue = Box::new(import_queue); let finality_proof_provider = Components::build_finality_proof_provider(client.clone())?; let chain_info = client.info().chain; @@ -188,7 +245,7 @@ impl Service { DEFAULT_PROTOCOL_ID } }.as_bytes(); - network::ProtocolId::from(protocol_id_full) + network::config::ProtocolId::from(protocol_id_full) }; let network_params = network::config::Params { @@ -196,6 +253,7 @@ impl Service { network_config: state.config.network.clone(), chain: client.clone(), finality_proof_provider, + finality_proof_request_builder, on_demand, transaction_pool: transaction_pool_adapter.clone() as _, import_queue, @@ -206,36 +264,43 @@ impl Service { let has_bootnodes = !network_params.network_config.boot_nodes.is_empty(); let network_mut = network::NetworkWorker::new(network_params)?; let network = network_mut.service().clone(); + let network_status_sinks = Arc::new(Mutex::new(Vec::new())); - task_executor.spawn(network_mut - .map_err(|_| ()) - .select(exit.clone()) - .then(|_| Ok(()))); + let keystore_authority_key = AuthorityKeyProvider { + roles: config.roles, + password: config.password.clone(), + keystore: keystore.map(Arc::new), + }; - let offchain_workers = if state.config.offchain_worker { - Some(Arc::new(offchain::OffchainWorkers::new( - client.clone(), - task_executor.clone(), - ))) - } else { - None + let offchain_storage = state.backend.offchain_storage(); + let offchain_workers = match (state.config.offchain_worker, offchain_storage) { + (true, Some(db)) => { + Some(Arc::new(offchain::OffchainWorkers::new( + client.clone(), + db, + keystore_authority_key.clone(), + state.config.password.clone(), + ))) + }, + (true, None) => { + log::warn!("Offchain workers disabled, due to lack of offchain storage support in backend."); + None + }, + _ => None, }; { // block notifications - let network = Arc::downgrade(&network); let txpool = Arc::downgrade(&transaction_pool); let wclient = Arc::downgrade(&client); let offchain = offchain_workers.as_ref().map(Arc::downgrade); + let to_spawn_tx_ = to_spawn_tx.clone(); let events = client.import_notification_stream() + .map(|v| Ok::<_, ()>(v)).compat() .for_each(move |notification| { let number = *notification.header.number(); - if let Some(network) = network.upgrade() { - network.on_block_imported(notification.hash, notification.header); - } - if let (Some(txpool), Some(client)) = (txpool.upgrade(), wclient.upgrade()) { Components::RuntimeServices::maintain_transaction_pool( &BlockId::hash(notification.hash), @@ -245,64 +310,19 @@ impl Service { } if let (Some(txpool), Some(offchain)) = (txpool.upgrade(), offchain.as_ref().and_then(|o| o.upgrade())) { - Components::RuntimeServices::offchain_workers( + let future = Components::RuntimeServices::offchain_workers( &number, &offchain, &txpool, ).map_err(|e| warn!("Offchain workers error processing new block: {:?}", e))?; + let _ = to_spawn_tx_.unbounded_send(future); } Ok(()) }) .select(exit.clone()) .then(|_| Ok(())); - task_executor.spawn(events); - } - - { - // finality notifications - let network = Arc::downgrade(&network); - - // A utility stream that drops all ready items and only returns the last one. - // This is used to only keep the last finality notification and avoid - // overloading the sync module with notifications. - struct MostRecentNotification(futures::stream::Fuse>); - - impl Stream for MostRecentNotification { - type Item = as Stream>::Item; - type Error = as Stream>::Error; - - fn poll(&mut self) -> Poll, Self::Error> { - let mut last = None; - let last = loop { - match self.0.poll()? { - Async::Ready(Some(item)) => { last = Some(item) } - Async::Ready(None) => match last { - None => return Ok(Async::Ready(None)), - Some(last) => break last, - }, - Async::NotReady => match last { - None => return Ok(Async::NotReady), - Some(last) => break last, - }, - } - }; - - Ok(Async::Ready(Some(last))) - } - } - - let events = MostRecentNotification(client.finality_notification_stream().fuse()) - .for_each(move |notification| { - if let Some(network) = network.upgrade() { - network.on_block_finalized(notification.hash, notification.header); - } - Ok(()) - }) - .select(exit.clone()) - .then(|_| Ok(())); - - task_executor.spawn(events); + let _ = to_spawn_tx.unbounded_send(Box::new(events)); } { @@ -324,24 +344,25 @@ impl Service { .select(exit.clone()) .then(|_| Ok(())); - task_executor.spawn(events); + let _ = to_spawn_tx.unbounded_send(Box::new(events)); } // Periodically notify the telemetry. let transaction_pool_ = transaction_pool.clone(); let client_ = client.clone(); - let network_ = network.clone(); let mut sys = System::new(); - let self_pid = get_current_pid(); - task_executor.spawn(network.status().for_each(move |sync_status| { + let self_pid = get_current_pid().ok(); + let (netstat_tx, netstat_rx) = mpsc::unbounded::<(NetworkStatus>, NetworkState)>(); + network_status_sinks.lock().push(netstat_tx); + let tel_task = netstat_rx.for_each(move |(net_status, network_state)| { let info = client_.info(); let best_number = info.chain.best_number.saturated_into::(); let best_hash = info.chain.best_hash; - let num_peers = sync_status.num_peers; + let num_peers = net_status.num_connected_peers; let txpool_status = transaction_pool_.status(); let finalized_number: u64 = info.chain.finalized_number.saturated_into::(); - let bandwidth_download = network_.average_download_per_sec(); - let bandwidth_upload = network_.average_upload_per_sec(); + let bandwidth_download = net_status.average_download_per_sec; + let bandwidth_upload = net_status.average_upload_per_sec; let used_state_cache_size = match info.used_state_cache_size { Some(size) => size, @@ -349,13 +370,14 @@ impl Service { }; // get cpu usage and memory usage of this process - let (cpu_usage, memory) = if sys.refresh_process(self_pid) { - let proc = sys.get_process(self_pid).expect("Above refresh_process succeeds, this should be Some(), qed"); - (proc.cpu_usage(), proc.memory()) + let (cpu_usage, memory) = if let Some(self_pid) = self_pid { + if sys.refresh_process(self_pid) { + let proc = sys.get_process(self_pid) + .expect("Above refresh_process succeeds, this should be Some(), qed"); + (proc.cpu_usage(), proc.memory()) + } else { (0.0, 0) } } else { (0.0, 0) }; - let network_state = network_.network_state(); - telemetry!( SUBSTRATE_INFO; "system.interval"; @@ -374,32 +396,39 @@ impl Service { ); Ok(()) - }).select(exit.clone()).then(|_| Ok(()))); + }).select(exit.clone()).then(|_| Ok(())); + let _ = to_spawn_tx.unbounded_send(Box::new(tel_task)); // RPC - let system_info = rpc::apis::system::SystemInfo { - chain_name: state.config.chain_spec.name().into(), - impl_name: state.config.impl_name.into(), - impl_version: state.config.impl_version.into(), - properties: state.config.chain_spec.properties(), - }; let (system_rpc_tx, system_rpc_rx) = mpsc::unbounded(); - let rpc = Components::RuntimeServices::start_rpc( + let gen_handler = || { + let system_info = rpc::apis::system::SystemInfo { + chain_name: state.config.chain_spec.name().into(), + impl_name: state.config.impl_name.into(), + impl_version: state.config.impl_version.into(), + properties: state.config.chain_spec.properties(), + }; + Components::RuntimeServices::start_rpc( + client.clone(), + system_rpc_tx.clone(), + system_info.clone(), + Arc::new(SpawnTaskHandle { sender: to_spawn_tx.clone() }), + transaction_pool.clone(), + ) + }; + let rpc_handlers = gen_handler(); + let rpc = start_rpc_servers::(&config, gen_handler)?; + + let _ = to_spawn_tx.unbounded_send(Box::new(build_network_future::( + network_mut, client.clone(), - system_rpc_tx, - system_info, - state.config.rpc_http, - state.config.rpc_ws, - state.config.rpc_ws_max_connections, - state.config.rpc_cors.clone(), - task_executor.clone(), - transaction_pool.clone(), - )?; - task_executor.spawn(build_system_rpc_handler::( - network.clone(), + network_status_sinks.clone(), system_rpc_rx, has_bootnodes - )); + ) + .map_err(|_| ()) + .select(exit.clone()) + .then(|_| Ok(())))); let telemetry_connection_sinks: Arc>>> = Default::default(); @@ -407,7 +436,6 @@ impl Service { let telemetry = state.config.telemetry_endpoints.clone().map(|endpoints| { let is_authority = state.config.roles == Roles::AUTHORITY; let network_id = network.local_peer_id().to_base58(); - let pubkey = format!("{}", public_key); let name = state.config.name.clone(); let impl_name = state.config.impl_name.to_owned(); let version = version.clone(); @@ -415,9 +443,11 @@ impl Service { let telemetry_connection_sinks_ = telemetry_connection_sinks.clone(); let telemetry = tel::init_telemetry(tel::TelemetryConfig { endpoints, - wasm_external_transport: None, + wasm_external_transport: state.config.telemetry_external_transport.take(), }); let future = telemetry.clone() + .map(|ev| Ok::<_, ()>(ev)) + .compat() .for_each(move |event| { // Safe-guard in case we add more events in the future. let tel::TelemetryEvent::Connected = event; @@ -428,7 +458,7 @@ impl Service { "version" => version.clone(), "config" => "", "chain" => chain_name.clone(), - "pubkey" => &pubkey, + "pubkey" => &public_key, "authority" => is_authority, "network_id" => network_id.clone() ); @@ -438,21 +468,26 @@ impl Service { }); Ok(()) }); - task_executor.spawn(future + let _ = to_spawn_tx.unbounded_send(Box::new(future .select(exit.clone()) - .then(|_| Ok(()))); + .then(|_| Ok(())))); telemetry }); Ok((Service { client, - network: Some(network), + network, + network_status_sinks, select_chain, transaction_pool, signal: Some(signal), - keystore, + to_spawn_tx, + to_spawn_rx, + to_poll: Vec::new(), + keystore: keystore_authority_key, exit, - _rpc: Box::new(rpc), + rpc_handlers, + _rpc: rpc, _telemetry: telemetry, _offchain_workers: offchain_workers, _telemetry_on_connect_sinks: telemetry_connection_sinks.clone(), @@ -460,25 +495,43 @@ impl Service { } /// give the authority key, if we are an authority and have a key - pub fn authority_key(&self, config: &FactoryFullConfiguration) -> Option { - if config.roles != Roles::AUTHORITY { return None } - let keystore = &self.keystore; - if let Ok(Some(Ok(key))) = keystore.contents().map(|keys| keys.get(0) - .map(|k| keystore.load(k, &config.password))) - { - Some(key) - } else { - None - } + pub fn authority_key(&self) -> Option { + use offchain::AuthorityKeyProvider; + + self.keystore.authority_key() } /// return a shared instance of Telemetry (if enabled) pub fn telemetry(&self) -> Option { self._telemetry.as_ref().map(|t| t.clone()) } -} -impl Service where Components: components::Components { + /// Spawns a task in the background that runs the future passed as parameter. + pub fn spawn_task(&self, task: impl Future + Send + 'static) { + let _ = self.to_spawn_tx.unbounded_send(Box::new(task)); + } + + /// Returns a handle for spawning tasks. + pub fn spawn_task_handle(&self) -> SpawnTaskHandle { + SpawnTaskHandle { + sender: self.to_spawn_tx.clone(), + } + } + + /// Starts an RPC query. + /// + /// The query is passed as a string and must be a JSON text similar to what an HTTP client + /// would for example send. + /// + /// Returns a `Future` that contains the optional response. + /// + /// If the request subscribes you to events, the `Sender` in the `RpcSession` object is used to + /// send back spontaneous events. + pub fn rpc_query(&self, mem: &RpcSession, request: &str) + -> impl Future, Error = ()> { + self.rpc_handlers.handle_request(request, mem.metadata.clone()) + } + /// Get shared client instance. pub fn client(&self) -> Arc> { self.client.clone() @@ -490,8 +543,15 @@ impl Service where Components: components::Components { } /// Get shared network instance. - pub fn network(&self) -> Arc> { - self.network.as_ref().expect("self.network always Some").clone() + pub fn network(&self) -> Arc> { + self.network.clone() + } + + /// Returns a receiver that periodically receives a status of the network. + pub fn network_status(&self) -> mpsc::UnboundedReceiver<(NetworkStatus>, NetworkState)> { + let (sink, stream) = mpsc::unbounded(); + self.network_status_sinks.lock().push(sink); + stream } /// Get shared transaction pool instance. @@ -499,46 +559,240 @@ impl Service where Components: components::Components { self.transaction_pool.clone() } - /// Get shared keystore. - pub fn keystore(&self) -> &Keystore { - &self.keystore - } - /// Get a handle to a future that will resolve on exit. pub fn on_exit(&self) -> ::exit_future::Exit { self.exit.clone() } } +impl Future for Service where Components: components::Components { + type Item = (); + type Error = (); + + fn poll(&mut self) -> Poll { + while let Ok(Async::Ready(Some(task_to_spawn))) = self.to_spawn_rx.poll() { + let executor = tokio_executor::DefaultExecutor::current(); + if let Err(err) = executor.execute(task_to_spawn) { + debug!( + target: "service", + "Failed to spawn background task: {:?}; falling back to manual polling", + err + ); + self.to_poll.push(err.into_future()); + } + } + + // Polling all the `to_poll` futures. + while let Some(pos) = self.to_poll.iter_mut().position(|t| t.poll().map(|t| t.is_ready()).unwrap_or(true)) { + self.to_poll.remove(pos); + } + + // The service future never ends. + Ok(Async::NotReady) + } +} + +impl Executor + Send>> + for Service where Components: components::Components +{ + fn execute( + &self, + future: Box + Send> + ) -> Result<(), futures::future::ExecuteError + Send>>> { + if let Err(err) = self.to_spawn_tx.unbounded_send(future) { + let kind = futures::future::ExecuteErrorKind::Shutdown; + Err(futures::future::ExecuteError::new(kind, err.into_inner())) + } else { + Ok(()) + } + } +} + +/// Builds a never-ending future that continuously polls the network. +/// +/// The `status_sink` contain a list of senders to send a periodic network status to. +fn build_network_future< + Components: components::Components, + S: network::specialization::NetworkSpecialization>, + H: network::ExHashT +> ( + mut network: network::NetworkWorker, S, H>, + client: Arc>, + status_sinks: Arc>, NetworkState)>>>>, + mut rpc_rx: mpsc::UnboundedReceiver>>, + should_have_peers: bool, +) -> impl Future { + // Interval at which we send status updates on the status stream. + const STATUS_INTERVAL: Duration = Duration::from_millis(5000); + let mut status_interval = tokio_timer::Interval::new_interval(STATUS_INTERVAL); + + let mut imported_blocks_stream = client.import_notification_stream().fuse() + .map(|v| Ok::<_, ()>(v)).compat(); + let mut finality_notification_stream = client.finality_notification_stream().fuse() + .map(|v| Ok::<_, ()>(v)).compat(); + + futures::future::poll_fn(move || { + // We poll `imported_blocks_stream`. + while let Ok(Async::Ready(Some(notification))) = imported_blocks_stream.poll() { + network.on_block_imported(notification.hash, notification.header); + } + + // We poll `finality_notification_stream`, but we only take the last event. + let mut last = None; + while let Ok(Async::Ready(Some(item))) = finality_notification_stream.poll() { + last = Some(item); + } + if let Some(notification) = last { + network.on_block_finalized(notification.hash, notification.header); + } + + // Poll the RPC requests and answer them. + while let Ok(Async::Ready(Some(request))) = rpc_rx.poll() { + match request { + rpc::apis::system::Request::Health(sender) => { + let _ = sender.send(rpc::apis::system::Health { + peers: network.peers_debug_info().len(), + is_syncing: network.service().is_major_syncing(), + should_have_peers, + }); + }, + rpc::apis::system::Request::Peers(sender) => { + let _ = sender.send(network.peers_debug_info().into_iter().map(|(peer_id, p)| + rpc::apis::system::PeerInfo { + peer_id: peer_id.to_base58(), + roles: format!("{:?}", p.roles), + protocol_version: p.protocol_version, + best_hash: p.best_hash, + best_number: p.best_number, + } + ).collect()); + } + rpc::apis::system::Request::NetworkState(sender) => { + let _ = sender.send(network.network_state()); + } + }; + } + + // Interval report for the external API. + while let Ok(Async::Ready(_)) = status_interval.poll() { + let status = NetworkStatus { + sync_state: network.sync_state(), + best_seen_block: network.best_seen_block(), + num_sync_peers: network.num_sync_peers(), + num_connected_peers: network.num_connected_peers(), + num_active_peers: network.num_active_peers(), + average_download_per_sec: network.average_download_per_sec(), + average_upload_per_sec: network.average_upload_per_sec(), + }; + let state = network.network_state(); + + status_sinks.lock().retain(|sink| sink.unbounded_send((status.clone(), state.clone())).is_ok()); + } + + // Main network polling. + network.poll() + .map_err(|err| { + warn!(target: "service", "Error in network: {:?}", err); + }) + }) +} + +/// Overview status of the network. +#[derive(Clone)] +pub struct NetworkStatus { + /// Current global sync state. + pub sync_state: network::SyncState, + /// Target sync block number. + pub best_seen_block: Option>, + /// Number of peers participating in syncing. + pub num_sync_peers: u32, + /// Total number of connected peers + pub num_connected_peers: usize, + /// Total number of active peers. + pub num_active_peers: usize, + /// Downloaded bytes per second averaged over the past few seconds. + pub average_download_per_sec: u64, + /// Uploaded bytes per second averaged over the past few seconds. + pub average_upload_per_sec: u64, +} impl Drop for Service where Components: components::Components { fn drop(&mut self) { debug!(target: "service", "Substrate service shutdown"); - - drop(self.network.take()); - if let Some(signal) = self.signal.take() { signal.fire(); } } } -fn maybe_start_server(address: Option, start: F) -> Result, io::Error> - where F: Fn(&SocketAddr) -> Result, -{ - Ok(match address { - Some(mut address) => Some(start(&address) - .or_else(|e| match e.kind() { - io::ErrorKind::AddrInUse | - io::ErrorKind::PermissionDenied => { - warn!("Unable to bind server to {}. Trying random port.", address); - address.set_port(0); - start(&address) - }, - _ => Err(e), - })?), - None => None, - }) +/// Starts RPC servers that run in their own thread, and returns an opaque object that keeps them alive. +#[cfg(not(target_os = "unknown"))] +fn start_rpc_servers rpc::RpcHandler>( + config: &FactoryFullConfiguration, + mut gen_handler: H +) -> Result, error::Error> { + fn maybe_start_server(address: Option, mut start: F) -> Result, io::Error> + where F: FnMut(&SocketAddr) -> Result, + { + Ok(match address { + Some(mut address) => Some(start(&address) + .or_else(|e| match e.kind() { + io::ErrorKind::AddrInUse | + io::ErrorKind::PermissionDenied => { + warn!("Unable to bind server to {}. Trying random port.", address); + address.set_port(0); + start(&address) + }, + _ => Err(e), + })?), + None => None, + }) + } + + Ok(Box::new(( + maybe_start_server( + config.rpc_http, + |address| rpc::start_http(address, config.rpc_cors.as_ref(), gen_handler()), + )?, + maybe_start_server( + config.rpc_ws, + |address| rpc::start_ws( + address, + config.rpc_ws_max_connections, + config.rpc_cors.as_ref(), + gen_handler(), + ), + )?.map(Mutex::new), + ))) +} + +/// Starts RPC servers that run in their own thread, and returns an opaque object that keeps them alive. +#[cfg(target_os = "unknown")] +fn start_rpc_servers rpc::RpcHandler>( + _: &FactoryFullConfiguration, + _: H +) -> Result, error::Error> { + Ok(Box::new(())) +} + +/// An RPC session. Used to perform in-memory RPC queries (ie. RPC queries that don't go through +/// the HTTP or WebSockets server). +pub struct RpcSession { + metadata: rpc::Metadata, +} + +impl RpcSession { + /// Creates an RPC session. + /// + /// The `sender` is stored inside the `RpcSession` and is used to communicate spontaneous JSON + /// messages. + /// + /// The `RpcSession` must be kept alive in order to receive messages on the sender. + pub fn new(sender: mpsc::Sender) -> RpcSession { + RpcSession { + metadata: rpc::Metadata::new(sender), + } + } } /// Transaction pool adapter. @@ -619,37 +873,37 @@ impl network::TransactionPool, ComponentBlock< } } -/// Builds a never-ending `Future` that answers the RPC requests coming on the receiver. -fn build_system_rpc_handler( - network: Arc>, - rx: mpsc::UnboundedReceiver>>, - should_have_peers: bool, -) -> impl Future { - rx.for_each(move |request| { - match request { - rpc::apis::system::Request::Health(sender) => { - let _ = sender.send(rpc::apis::system::Health { - peers: network.peers_debug_info().len(), - is_syncing: network.is_major_syncing(), - should_have_peers, - }); - }, - rpc::apis::system::Request::Peers(sender) => { - let _ = sender.send(network.peers_debug_info().into_iter().map(|(peer_id, p)| rpc::apis::system::PeerInfo { - peer_id: peer_id.to_base58(), - roles: format!("{:?}", p.roles), - protocol_version: p.protocol_version, - best_hash: p.best_hash, - best_number: p.best_number, - }).collect()); - } - rpc::apis::system::Request::NetworkState(sender) => { - let _ = sender.send(network.network_state()); - } +/// A provider of current authority key. +#[derive(Clone)] +pub struct AuthorityKeyProvider { + roles: Roles, + keystore: Option>, + password: crypto::Protected, +} + +impl offchain::AuthorityKeyProvider for AuthorityKeyProvider { + fn authority_key(&self) -> Option { + if self.roles != Roles::AUTHORITY { + return None + } + + let keystore = match self.keystore { + Some(ref keystore) => keystore, + None => return None }; - Ok(()) - }) + let loaded_key = keystore + .contents() + .map(|keys| keys.get(0) + .map(|k| keystore.load(k, self.password.as_ref())) + ); + + if let Ok(Some(Ok(key))) = loaded_key { + Some(key) + } else { + None + } + } } /// Constructs a service factory with the given name that implements the `ServiceFactory` trait. @@ -663,12 +917,11 @@ fn build_system_rpc_handler( /// ``` /// # use substrate_service::{ /// # construct_service_factory, Service, FullBackend, FullExecutor, LightBackend, LightExecutor, -/// # FullComponents, LightComponents, FactoryFullConfiguration, FullClient, TaskExecutor +/// # FullComponents, LightComponents, FactoryFullConfiguration, FullClient /// # }; /// # use transaction_pool::{self, txpool::{Pool as TransactionPool}}; -/// # use network::construct_simple_protocol; +/// # use network::{config::DummyFinalityProofRequestBuilder, construct_simple_protocol}; /// # use client::{self, LongestChain}; -/// # use primitives::{Pair as PairT, ed25519}; /// # use consensus_common::import_queue::{BasicQueue, Verifier}; /// # use consensus_common::{BlockOrigin, ImportBlock, well_known_cache_keys::Id as CacheKeyId}; /// # use node_runtime::{GenesisConfig, RuntimeApi}; @@ -713,18 +966,21 @@ fn build_system_rpc_handler( /// SetupState = (), /// Configuration = (), /// FullService = FullComponents -/// { |config, executor| >::new(config, executor) }, +/// { |config| >::new(config) }, /// // Setup as Consensus Authority (if the role and key are given) /// AuthoritySetup = { -/// |service: Self::FullService, executor: TaskExecutor, key: Option>| { +/// |service: Self::FullService| { /// Ok(service) /// }}, /// LightService = LightComponents -/// { |config, executor| >::new(config, executor) }, +/// { |config| >::new(config) }, /// FullImportQueue = BasicQueue -/// { |_, client, _| Ok(BasicQueue::new(Arc::new(MyVerifier), client, None, None, None)) }, +/// { |_, client, _| Ok(BasicQueue::new(Arc::new(MyVerifier), Box::new(client), None, None)) }, /// LightImportQueue = BasicQueue -/// { |_, client| Ok(BasicQueue::new(Arc::new(MyVerifier), client, None, None, None)) }, +/// { |_, client| { +/// let fprb = Box::new(DummyFinalityProofRequestBuilder::default()) as Box<_>; +/// Ok((BasicQueue::new(Arc::new(MyVerifier), Box::new(client), None, None), fprb)) +/// }}, /// SelectChain = LongestChain, Self::Block> /// { |config: &FactoryFullConfiguration, client: Arc>| { /// #[allow(deprecated)] @@ -822,7 +1078,7 @@ macro_rules! construct_service_factory { fn build_light_import_queue( state: &mut $crate::LightComponentsSetupState, client: Arc<$crate::LightClient>, - ) -> Result { + ) -> Result<(Self::LightImportQueue, $crate::BoxFinalityProofRequestBuilder<$block>), $crate::Error> { ( $( $light_import_queue_init )* ) (state, client) } @@ -833,21 +1089,18 @@ macro_rules! construct_service_factory { } fn new_light( - config: $crate::FactoryFullConfiguration, - executor: $crate::TaskExecutor + config: $crate::FactoryFullConfiguration ) -> $crate::Result { - ( $( $light_service_init )* ) (config, executor) + ( $( $light_service_init )* ) (config) } fn new_full( - config: $crate::FactoryFullConfiguration, - executor: $crate::TaskExecutor, + config: $crate::FactoryFullConfiguration ) -> Result { - ( $( $full_service_init )* ) (config, executor.clone()).and_then(|(service, state)| { - let key = (&service).authority_key(&state.config).map(Arc::new); - ($( $authority_setup )*)(service, state, executor, key) + ( $( $full_service_init )* ) (config).and_then(|(service, state)| { + ($( $authority_setup )*)(service, state) }) } } diff --git a/core/service/test/src/lib.rs b/core/service/test/src/lib.rs index d3d9677bb241028e528d78714c745860354699e3..adfee10029a021efe687d73bc8b852856bf4aa78 100644 --- a/core/service/test/src/lib.rs +++ b/core/service/test/src/lib.rs @@ -17,12 +17,12 @@ //! Service integration test utils. use std::iter; -use std::sync::Arc; +use std::sync::{Arc, Mutex, MutexGuard}; use std::net::Ipv4Addr; use std::time::Duration; use std::collections::HashMap; use log::info; -use futures::{Future, Stream}; +use futures::{Future, Stream, Poll}; use tempdir::TempDir; use tokio::{runtime::Runtime, prelude::FutureExt}; use tokio::timer::Interval; @@ -34,8 +34,8 @@ use service::{ Roles, FactoryExtrinsic, }; -use network::{multiaddr, Multiaddr, ManageNetwork}; -use network::config::{NetworkConfiguration, NodeKeyConfig, Secret, NonReservedPeerMode}; +use network::{multiaddr, Multiaddr}; +use network::config::{NetworkConfiguration, TransportConfig, NodeKeyConfig, Secret, NonReservedPeerMode}; use sr_primitives::generic::BlockId; use consensus::{ImportBlock, BlockImport}; @@ -44,14 +44,44 @@ const MAX_WAIT_TIME: Duration = Duration::from_secs(60 * 3); struct TestNet { runtime: Runtime, - authority_nodes: Vec<(u32, Arc, Multiaddr)>, - full_nodes: Vec<(u32, Arc, Multiaddr)>, - light_nodes: Vec<(u32, Arc, Multiaddr)>, + authority_nodes: Vec<(usize, SyncService, Multiaddr)>, + full_nodes: Vec<(usize, SyncService, Multiaddr)>, + light_nodes: Vec<(usize, SyncService, Multiaddr)>, chain_spec: FactoryChainSpec, base_port: u16, nodes: usize, } +/// Wraps around an `Arc>` and implements `Future`. +pub struct SyncService(Arc>); + +impl SyncService { + pub fn get(&self) -> MutexGuard { + self.0.lock().unwrap() + } +} + +impl Clone for SyncService { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + +impl From for SyncService { + fn from(service: T) -> Self { + SyncService(Arc::new(Mutex::new(service))) + } +} + +impl> Future for SyncService { + type Item = (); + type Error = (); + + fn poll(&mut self) -> Poll { + self.0.lock().unwrap().poll() + } +} + impl TestNet { pub fn run_until_all_full( &mut self, @@ -59,25 +89,31 @@ impl TestNet { light_predicate: LP, ) where - FP: Send + Sync + Fn(u32, &F::FullService) -> bool + 'static, - LP: Send + Sync + Fn(u32, &F::LightService) -> bool + 'static, + FP: Send + Fn(usize, &SyncService) -> bool + 'static, + LP: Send + Fn(usize, &SyncService) -> bool + 'static, { let full_nodes = self.full_nodes.clone(); let light_nodes = self.light_nodes.clone(); let interval = Interval::new_interval(Duration::from_millis(100)) .map_err(|_| ()) .for_each(move |_| { - let full_ready = full_nodes.iter().all(|&(ref id, ref service, _)| full_predicate(*id, service)); + let full_ready = full_nodes.iter().all(|&(ref id, ref service, _)| + full_predicate(*id, service) + ); + if !full_ready { return Ok(()); } - let light_ready = light_nodes.iter().all(|&(ref id, ref service, _)| light_predicate(*id, service)); + let light_ready = light_nodes.iter().all(|&(ref id, ref service, _)| + light_predicate(*id, service) + ); + if !light_ready { - return Ok(()); + Ok(()) + } else { + Err(()) } - - Err(()) }) .timeout(MAX_WAIT_TIME); @@ -90,7 +126,7 @@ impl TestNet { } fn node_config ( - index: u32, + index: usize, spec: &FactoryChainSpec, role: Roles, key_seed: Option, @@ -124,8 +160,10 @@ fn node_config ( non_reserved_mode: NonReservedPeerMode::Accept, client_version: "network/test/0.1".to_owned(), node_name: "unknown".to_owned(), - enable_mdns: false, - wasm_external_transport: None, + transport: TransportConfig::Normal { + enable_mdns: false, + wasm_external_transport: None, + }, }; Configuration { @@ -135,8 +173,8 @@ fn node_config ( roles: role, transaction_pool: Default::default(), network: network_config, - keystore_path: root.join("key").to_str().unwrap().into(), - database_path: root.join("db").to_str().unwrap().into(), + keystore_path: Some(root.join("key")), + database_path: root.join("db"), database_cache_size: None, state_cache_size: 16777216, state_cache_child_ratio: None, @@ -151,25 +189,37 @@ fn node_config ( rpc_ws_max_connections: None, rpc_cors: None, telemetry_endpoints: None, + telemetry_external_transport: None, default_heap_pages: None, offchain_worker: false, force_authoring: false, disable_grandpa: false, - password: "".to_string(), + grandpa_voter: false, + password: "".to_string().into(), } } -impl TestNet { - fn new(temp: &TempDir, spec: FactoryChainSpec, full: u32, light: u32, authorities: Vec, base_port: u16) -> TestNet { - let _ = ::env_logger::try_init(); - ::fdlimit::raise_fd_limit(); +impl TestNet where + F::FullService: Future, + F::LightService: Future +{ + fn new( + temp: &TempDir, + spec: FactoryChainSpec, + full: usize, + light: usize, + authorities: Vec, + base_port: u16 + ) -> TestNet { + let _ = env_logger::try_init(); + fdlimit::raise_fd_limit(); let runtime = Runtime::new().expect("Error creating tokio runtime"); let mut net = TestNet { runtime, authority_nodes: Default::default(), full_nodes: Default::default(), light_nodes: Default::default(), - chain_spec: spec.clone(), + chain_spec: spec, base_port, nodes: 0, }; @@ -177,48 +227,61 @@ impl TestNet { net } - fn insert_nodes(&mut self, temp: &TempDir, full: u32, light: u32, authorities: Vec) { + fn insert_nodes(&mut self, temp: &TempDir, full: usize, light: usize, authorities: Vec) { let mut nodes = self.nodes; let base_port = self.base_port; - let spec = self.chain_spec.clone(); + let spec = &self.chain_spec; let executor = self.runtime.executor(); self.authority_nodes.extend(authorities.iter().enumerate().map(|(index, key)| { - let node_config = node_config::(index as u32, &spec, Roles::AUTHORITY, Some(key.clone()), base_port, &temp); + let node_config = node_config::( + index, + &spec, + Roles::AUTHORITY, + Some(key.clone()), + base_port, + &temp, + ); let addr = node_config.network.listen_addresses.iter().next().unwrap().clone(); - let service = Arc::new(F::new_full(node_config, executor.clone()) - .expect("Error creating test node service")); - let addr = addr.with(multiaddr::Protocol::P2p(service.network().local_peer_id().into())); - ((index + nodes) as u32, service, addr) + let service = SyncService::from(F::new_full(node_config).expect("Error creating test node service")); + + executor.spawn(service.clone()); + let addr = addr.with(multiaddr::Protocol::P2p(service.get().network().local_peer_id().into())); + ((index + nodes), service, addr) })); nodes += authorities.len(); - self.full_nodes.extend((nodes..nodes + full as usize).map(|index| { - let node_config = node_config::(index as u32, &spec, Roles::FULL, None, base_port, &temp); + self.full_nodes.extend((nodes..nodes + full).map(|index| { + let node_config = node_config::(index, &spec, Roles::FULL, None, base_port, &temp); let addr = node_config.network.listen_addresses.iter().next().unwrap().clone(); - let service = Arc::new(F::new_full(node_config, executor.clone()) - .expect("Error creating test node service")); - let addr = addr.with(multiaddr::Protocol::P2p(service.network().local_peer_id().into())); - (index as u32, service, addr) + let service = SyncService::from(F::new_full(node_config).expect("Error creating test node service")); + + executor.spawn(service.clone()); + let addr = addr.with(multiaddr::Protocol::P2p(service.get().network().local_peer_id().into())); + (index, service, addr) })); - nodes += full as usize; + nodes += full; - self.light_nodes.extend((nodes..nodes + light as usize).map(|index| { - let node_config = node_config::(index as u32, &spec, Roles::LIGHT, None, base_port, &temp); + self.light_nodes.extend((nodes..nodes + light).map(|index| { + let node_config = node_config::(index, &spec, Roles::LIGHT, None, base_port, &temp); let addr = node_config.network.listen_addresses.iter().next().unwrap().clone(); - let service = Arc::new(F::new_light(node_config, executor.clone()) - .expect("Error creating test node service")); - let addr = addr.with(multiaddr::Protocol::P2p(service.network().local_peer_id().into())); - (index as u32, service, addr) + let service = SyncService::from(F::new_light(node_config).expect("Error creating test node service")); + + executor.spawn(service.clone()); + let addr = addr.with(multiaddr::Protocol::P2p(service.get().network().local_peer_id().into())); + (index, service, addr) })); - nodes += light as usize; + nodes += light; self.nodes = nodes; } } -pub fn connectivity(spec: FactoryChainSpec) { - const NUM_FULL_NODES: u32 = 5; - const NUM_LIGHT_NODES: u32 = 5; +pub fn connectivity(spec: FactoryChainSpec) where + F::FullService: Future, + F::LightService: Future, +{ + const NUM_FULL_NODES: usize = 5; + const NUM_LIGHT_NODES: usize = 5; { let temp = TempDir::new("substrate-connectivity-test").expect("Error creating test dir"); let runtime = { @@ -233,20 +296,20 @@ pub fn connectivity(spec: FactoryChainSpec) { info!("Checking star topology"); let first_address = network.full_nodes[0].2.clone(); for (_, service, _) in network.full_nodes.iter().skip(1) { - service.network().add_reserved_peer(first_address.to_string()).expect("Error adding reserved peer"); + service.get().network().add_reserved_peer(first_address.to_string()).expect("Error adding reserved peer"); } for (_, service, _) in network.light_nodes.iter() { - service.network().add_reserved_peer(first_address.to_string()).expect("Error adding reserved peer"); + service.get().network().add_reserved_peer(first_address.to_string()).expect("Error adding reserved peer"); } network.run_until_all_full( - |_index, service| service.network().peers_debug_info().len() == NUM_FULL_NODES as usize - 1 - + NUM_LIGHT_NODES as usize, - |_index, service| service.network().peers_debug_info().len() == NUM_FULL_NODES as usize, + |_index, service| service.get().network().num_connected() == NUM_FULL_NODES - 1 + + NUM_LIGHT_NODES, + |_index, service| service.get().network().num_connected() == NUM_FULL_NODES, ); network.runtime }; - runtime.shutdown_on_idle().wait().expect("Error shutting down runtime"); + runtime.shutdown_now().wait().expect("Error shutting down runtime"); temp.close().expect("Error removing temp dir"); } @@ -263,43 +326,40 @@ pub fn connectivity(spec: FactoryChainSpec) { ); info!("Checking linked topology"); let mut address = network.full_nodes[0].2.clone(); - let max_nodes = ::std::cmp::max(NUM_FULL_NODES, NUM_LIGHT_NODES); + let max_nodes = std::cmp::max(NUM_FULL_NODES, NUM_LIGHT_NODES); for i in 0..max_nodes { if i != 0 { - if let Some((_, service, node_id)) = network.full_nodes.get(i as usize) { - service.network().add_reserved_peer(address.to_string()).expect("Error adding reserved peer"); + if let Some((_, service, node_id)) = network.full_nodes.get(i) { + service.get().network().add_reserved_peer(address.to_string()).expect("Error adding reserved peer"); address = node_id.clone(); } } - if let Some((_, service, node_id)) = network.light_nodes.get(i as usize) { - service.network().add_reserved_peer(address.to_string()).expect("Error adding reserved peer"); + if let Some((_, service, node_id)) = network.light_nodes.get(i) { + service.get().network().add_reserved_peer(address.to_string()).expect("Error adding reserved peer"); address = node_id.clone(); } } network.run_until_all_full( - |_index, service| service.network().peers_debug_info().len() == NUM_FULL_NODES as usize - 1 - + NUM_LIGHT_NODES as usize, - |_index, service| service.network().peers_debug_info().len() == NUM_FULL_NODES as usize, + |_index, service| service.get().network().num_connected() == NUM_FULL_NODES - 1 + + NUM_LIGHT_NODES, + |_index, service| service.get().network().num_connected() == NUM_FULL_NODES, ); } temp.close().expect("Error removing temp dir"); } } -pub fn sync( - spec: FactoryChainSpec, - mut block_factory: B, - mut extrinsic_factory: E, -) -where +pub fn sync(spec: FactoryChainSpec, mut block_factory: B, mut extrinsic_factory: E) where F: ServiceFactory, - B: FnMut(&F::FullService) -> ImportBlock, - E: FnMut(&F::FullService) -> FactoryExtrinsic, + F::FullService: Future, + F::LightService: Future, + B: FnMut(&SyncService) -> ImportBlock, + E: FnMut(&SyncService) -> FactoryExtrinsic, { - const NUM_FULL_NODES: u32 = 10; - const NUM_LIGHT_NODES: u32 = 10; - const NUM_BLOCKS: u32 = 512; + const NUM_FULL_NODES: usize = 10; + const NUM_LIGHT_NODES: usize = 10; + const NUM_BLOCKS: usize = 512; let temp = TempDir::new("substrate-sync-test").expect("Error creating test dir"); let mut network = TestNet::::new( &temp, @@ -312,45 +372,50 @@ where info!("Checking block sync"); let first_address = { let first_service = &network.full_nodes[0].1; + let mut client = first_service.get().client(); for i in 0 .. NUM_BLOCKS { if i % 128 == 0 { info!("Generating #{}", i); } let import_data = block_factory(&first_service); - first_service.client().import_block(import_data, HashMap::new()).expect("Error importing test block"); + client.import_block(import_data, HashMap::new()).expect("Error importing test block"); } network.full_nodes[0].2.clone() }; + info!("Running sync"); for (_, service, _) in network.full_nodes.iter().skip(1) { - service.network().add_reserved_peer(first_address.to_string()).expect("Error adding reserved peer"); + service.get().network().add_reserved_peer(first_address.to_string()).expect("Error adding reserved peer"); } for (_, service, _) in network.light_nodes.iter() { - service.network().add_reserved_peer(first_address.to_string()).expect("Error adding reserved peer"); + service.get().network().add_reserved_peer(first_address.to_string()).expect("Error adding reserved peer"); } network.run_until_all_full( |_index, service| - service.client().info().chain.best_number == NUM_BLOCKS.into(), + service.get().client().info().chain.best_number == (NUM_BLOCKS as u32).into(), |_index, service| - service.client().info().chain.best_number == NUM_BLOCKS.into(), + service.get().client().info().chain.best_number == (NUM_BLOCKS as u32).into(), ); + info!("Checking extrinsic propagation"); let first_service = network.full_nodes[0].1.clone(); - let best_block = BlockId::number(first_service.client().info().chain.best_number); - first_service.transaction_pool().submit_one(&best_block, extrinsic_factory(&first_service)).unwrap(); + let best_block = BlockId::number(first_service.get().client().info().chain.best_number); + let extrinsic = extrinsic_factory(&first_service); + first_service.get().transaction_pool().submit_one(&best_block, extrinsic).unwrap(); network.run_until_all_full( - |_index, service| service.transaction_pool().ready().count() == 1, + |_index, service| service.get().transaction_pool().ready().count() == 1, |_index, _service| true, ); } -pub fn consensus(spec: FactoryChainSpec, authorities: Vec) - where - F: ServiceFactory, +pub fn consensus(spec: FactoryChainSpec, authorities: Vec) where + F: ServiceFactory, + F::FullService: Future, + F::LightService: Future, { - const NUM_FULL_NODES: u32 = 10; - const NUM_LIGHT_NODES: u32 = 0; - const NUM_BLOCKS: u32 = 10; // 10 * 2 sec block production time = ~20 seconds + const NUM_FULL_NODES: usize = 10; + const NUM_LIGHT_NODES: usize = 0; + const NUM_BLOCKS: usize = 10; // 10 * 2 sec block production time = ~20 seconds let temp = TempDir::new("substrate-conensus-test").expect("Error creating test dir"); let mut network = TestNet::::new( &temp, @@ -360,35 +425,37 @@ pub fn consensus(spec: FactoryChainSpec, authorities: Vec) authorities, 30600, ); + info!("Checking consensus"); let first_address = network.authority_nodes[0].2.clone(); for (_, service, _) in network.full_nodes.iter() { - service.network().add_reserved_peer(first_address.to_string()).expect("Error adding reserved peer"); + service.get().network().add_reserved_peer(first_address.to_string()).expect("Error adding reserved peer"); } for (_, service, _) in network.light_nodes.iter() { - service.network().add_reserved_peer(first_address.to_string()).expect("Error adding reserved peer"); + service.get().network().add_reserved_peer(first_address.to_string()).expect("Error adding reserved peer"); } for (_, service, _) in network.authority_nodes.iter().skip(1) { - service.network().add_reserved_peer(first_address.to_string()).expect("Error adding reserved peer"); + service.get().network().add_reserved_peer(first_address.to_string()).expect("Error adding reserved peer"); } network.run_until_all_full( |_index, service| - service.client().info().chain.finalized_number >= (NUM_BLOCKS / 2).into(), + service.get().client().info().chain.finalized_number >= (NUM_BLOCKS as u32 / 2).into(), |_index, service| - service.client().info().chain.best_number >= (NUM_BLOCKS / 2).into(), + service.get().client().info().chain.best_number >= (NUM_BLOCKS as u32 / 2).into(), ); + info!("Adding more peers"); network.insert_nodes(&temp, NUM_FULL_NODES / 2, NUM_LIGHT_NODES / 2, vec![]); for (_, service, _) in network.full_nodes.iter() { - service.network().add_reserved_peer(first_address.to_string()).expect("Error adding reserved peer"); + service.get().network().add_reserved_peer(first_address.to_string()).expect("Error adding reserved peer"); } for (_, service, _) in network.light_nodes.iter() { - service.network().add_reserved_peer(first_address.to_string()).expect("Error adding reserved peer"); + service.get().network().add_reserved_peer(first_address.to_string()).expect("Error adding reserved peer"); } network.run_until_all_full( |_index, service| - service.client().info().chain.finalized_number >= NUM_BLOCKS.into(), + service.get().client().info().chain.finalized_number >= (NUM_BLOCKS as u32).into(), |_index, service| - service.client().info().chain.best_number >= NUM_BLOCKS.into(), + service.get().client().info().chain.best_number >= (NUM_BLOCKS as u32).into(), ); } diff --git a/core/sr-api-macros/Cargo.toml b/core/sr-api-macros/Cargo.toml index 9f2145d958eee31d72bc3817ff1f2c14991ae4bb..c9a91e74914cab57a7c721b42b94a6530cd337f2 100644 --- a/core/sr-api-macros/Cargo.toml +++ b/core/sr-api-macros/Cargo.toml @@ -23,7 +23,7 @@ sr-version = { path = "../sr-version" } substrate-primitives = { path = "../primitives" } criterion = "0.2" consensus_common = { package = "substrate-consensus-common", path = "../consensus/common" } -codec = { package = "parity-codec", version = "3.5.1" } +codec = { package = "parity-codec", version = "4.1.1" } trybuild = "1.0" [[bench]] diff --git a/core/sr-api-macros/tests/trybuild.rs b/core/sr-api-macros/tests/trybuild.rs index e04c67737a486835e7818aa98bfaea46d6b975c6..302dd7c0878e3dfb6c9b364c2004ee6f8fed2e80 100644 --- a/core/sr-api-macros/tests/trybuild.rs +++ b/core/sr-api-macros/tests/trybuild.rs @@ -1,5 +1,10 @@ +use std::env; + #[test] fn ui() { + // As trybuild is using `cargo check`, we don't need the real WASM binaries. + env::set_var("BUILD_DUMMY_WASM_BINARY", "1"); + let t = trybuild::TestCases::new(); t.compile_fail("tests/ui/*.rs"); } diff --git a/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.stderr b/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.stderr index 6d5d484efe0954ff752b865ec78788b63a2c5f6c..15434a52ba8b78ae6876b17e34f72ff9c7e85779 100644 --- a/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.stderr +++ b/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.stderr @@ -10,4 +10,14 @@ error[E0053]: method `test` has an incompatible type for trait = note: expected type `fn(u64)` found type `fn(std::string::String)` -For more information about this error, try `rustc --explain E0053`. +error[E0308]: mismatched types + --> $DIR/impl_incorrect_method_signature.rs:20:11 + | +20 | fn test(data: String) {} + | ^^^^ expected u64, found struct `std::string::String` + | + = note: expected type `u64` + found type `std::string::String` + +Some errors have detailed explanations: E0053, E0308. +For more information about an error, try `rustc --explain E0053`. diff --git a/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.stderr b/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.stderr index 12ec399972efa763784b24e5243368cd10ae6641..9bfc04c8db046ecba4f42d2140143a7ade6b3886 100644 --- a/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.stderr +++ b/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.stderr @@ -10,4 +10,20 @@ error[E0053]: method `test` has an incompatible type for trait = note: expected type `fn(u64)` found type `fn(&u64)` -For more information about this error, try `rustc --explain E0053`. +error[E0308]: mismatched types + --> $DIR/type_reference_in_impl_runtime_apis_call.rs:18:1 + | +18 | / impl_runtime_apis! { +19 | | impl self::Api for Runtime { +20 | | fn test(data: &u64) { +21 | | unimplemented!() +22 | | } +23 | | } +24 | | } + | |_^ expected u64, found &u64 + | + = note: expected type `u64` + found type `&u64` + +Some errors have detailed explanations: E0053, E0308. +For more information about an error, try `rustc --explain E0053`. diff --git a/core/sr-io/Cargo.toml b/core/sr-io/Cargo.toml index 0c97ba8050d2d8f9990ee540f40dfca4ceef7da9..0172d3ac75783509e8e3b41038b974a04bbd4e88 100644 --- a/core/sr-io/Cargo.toml +++ b/core/sr-io/Cargo.toml @@ -11,8 +11,8 @@ rustc_version = "0.2" [dependencies] rstd = { package = "sr-std", path = "../sr-std", default-features = false } primitives = { package = "substrate-primitives", path = "../primitives", default-features = false } -codec = { package = "parity-codec", version = "3.5.1", default-features = false } -hash-db = { version = "0.12", default-features = false } +codec = { package = "parity-codec", version = "4.1.1", default-features = false } +hash-db = { version = "0.14.0", default-features = false } libsecp256k1 = { version = "0.2.1", optional = true } tiny-keccak = { version = "1.4.2", optional = true } environmental = { version = "1.0.1", optional = true } diff --git a/core/sr-io/src/lib.rs b/core/sr-io/src/lib.rs index cd9b43798b3d1d7f59ea13ed2e1464ef949fb0de..f340f0a99b008ec880d525b4004078cea68c44a3 100644 --- a/core/sr-io/src/lib.rs +++ b/core/sr-io/src/lib.rs @@ -33,7 +33,12 @@ use rstd::vec::Vec; pub use codec; pub use primitives::Blake2Hasher; -use primitives::offchain::{Timestamp, HttpRequestId, HttpRequestStatus, HttpError, CryptoKind, CryptoKeyId}; +use primitives::offchain::{ + Timestamp, + HttpRequestId, HttpRequestStatus, HttpError, + CryptoKind, CryptoKeyId, + StorageKind, +}; /// Error verifying ECDSA signature pub enum EcdsaVerifyError { @@ -244,28 +249,33 @@ export_api! { /// If `key` is `None`, it will attempt to use current authority key. /// /// Returns an error if `key` is not available or does not exist. - fn encrypt(key: Option, data: &[u8]) -> Result, ()>; + fn encrypt(key: Option, kind: CryptoKind, data: &[u8]) -> Result, ()>; /// Decrypt a piece of data using given crypto key. /// /// If `key` is `None`, it will attempt to use current authority key. /// /// Returns an error if data cannot be decrypted or the `key` is not available or does not exist. - fn decrypt(key: Option, data: &[u8]) -> Result, ()>; + fn decrypt(key: Option, kind: CryptoKind, data: &[u8]) -> Result, ()>; /// Sign a piece of data using given crypto key. /// /// If `key` is `None`, it will attempt to use current authority key. /// /// Returns an error if `key` is not available or does not exist. - fn sign(key: Option, data: &[u8]) -> Result, ()>; + fn sign(key: Option, kind: CryptoKind, data: &[u8]) -> Result, ()>; /// Verifies that `signature` for `msg` matches given `key`. /// /// Returns an `Ok` with `true` in case it does, `false` in case it doesn't. /// Returns an error in case the key is not available or does not exist or the parameters /// lengths are incorrect. - fn verify(key: Option, msg: &[u8], signature: &[u8]) -> Result; + fn verify( + key: Option, + kind: CryptoKind, + msg: &[u8], + signature: &[u8] + ) -> Result; /// Returns current UNIX timestamp (in millis) fn timestamp() -> Timestamp; @@ -283,23 +293,25 @@ export_api! { /// /// Note this storage is not part of the consensus, it's only accessible by /// offchain worker tasks running on the same machine. It IS persisted between runs. - fn local_storage_set(key: &[u8], value: &[u8]); + fn local_storage_set(kind: StorageKind, key: &[u8], value: &[u8]); /// Sets a value in the local storage if it matches current value. /// /// Since multiple offchain workers may be running concurrently, to prevent /// data races use CAS to coordinate between them. /// + /// Returns `true` if the value has been set, `false` otherwise. + /// /// Note this storage is not part of the consensus, it's only accessible by /// offchain worker tasks running on the same machine. It IS persisted between runs. - fn local_storage_compare_and_set(key: &[u8], old_value: &[u8], new_value: &[u8]); + fn local_storage_compare_and_set(kind: StorageKind, key: &[u8], old_value: &[u8], new_value: &[u8]) -> bool; /// Gets a value from the local storage. /// /// If the value does not exist in the storage `None` will be returned. /// Note this storage is not part of the consensus, it's only accessible by /// offchain worker tasks running on the same machine. It IS persisted between runs. - fn local_storage_get(key: &[u8]) -> Option>; + fn local_storage_get(kind: StorageKind, key: &[u8]) -> Option>; /// Initiaties a http request given HTTP verb and the URL. /// @@ -382,7 +394,10 @@ mod imp { } #[cfg(feature = "std")] -pub use self::imp::{StorageOverlay, ChildrenStorageOverlay, with_storage, with_externalities}; +pub use self::imp::{ + StorageOverlay, ChildrenStorageOverlay, with_storage, with_storage_and_children, + with_externalities +}; #[cfg(not(feature = "std"))] pub use self::imp::ext::*; diff --git a/core/sr-io/src/offchain/http.rs b/core/sr-io/src/offchain/http.rs index 0708f837179ed3072001e5308050dd318c9fe0ad..6685dd023f469e607b59cfcf7509b629c58bde94 100644 --- a/core/sr-io/src/offchain/http.rs +++ b/core/sr-io/src/offchain/http.rs @@ -486,9 +486,8 @@ mod tests { #[test] fn should_send_a_basic_request_and_get_response() { - let offchain = testing::TestOffchainExt::default(); + let (offchain, state) = testing::TestOffchainExt::new(); let mut t = TestExternalities::default(); - let state = offchain.0.clone(); t.set_offchain_externalities(offchain); with_externalities(&mut t, || { @@ -528,9 +527,8 @@ mod tests { #[test] fn should_send_a_post_request() { - let offchain = testing::TestOffchainExt::default(); + let (offchain, state) = testing::TestOffchainExt::new(); let mut t = TestExternalities::default(); - let state = offchain.0.clone(); t.set_offchain_externalities(offchain); with_externalities(&mut t, || { diff --git a/core/sr-io/with_std.rs b/core/sr-io/with_std.rs index 34bfc22b9db1544571739135ca955517ae2350d1..9475aa07151bf367f550031a1b77f8057b0125be 100644 --- a/core/sr-io/with_std.rs +++ b/core/sr-io/with_std.rs @@ -275,27 +275,44 @@ impl OffchainApi for () { }, "new_crypto_key can be called only in the offchain worker context") } - fn encrypt(key: Option, data: &[u8]) -> Result, ()> { + fn encrypt( + key: Option, + kind: offchain::CryptoKind, + data: &[u8], + ) -> Result, ()> { with_offchain(|ext| { - ext.encrypt(key, data) + ext.encrypt(key, kind, data) }, "encrypt can be called only in the offchain worker context") } - fn decrypt(key: Option, data: &[u8]) -> Result, ()> { + fn decrypt( + key: Option, + kind: offchain::CryptoKind, + data: &[u8], + ) -> Result, ()> { with_offchain(|ext| { - ext.decrypt(key, data) + ext.decrypt(key, kind, data) }, "decrypt can be called only in the offchain worker context") } - fn sign(key: Option, data: &[u8]) -> Result, ()> { + fn sign( + key: Option, + kind: offchain::CryptoKind, + data: &[u8], + ) -> Result, ()> { with_offchain(|ext| { - ext.sign(key, data) + ext.sign(key, kind, data) }, "sign can be called only in the offchain worker context") } - fn verify(key: Option, msg: &[u8], signature: &[u8]) -> Result { + fn verify( + key: Option, + kind: offchain::CryptoKind, + msg: &[u8], + signature: &[u8], + ) -> Result { with_offchain(|ext| { - ext.verify(key, msg, signature) + ext.verify(key, kind, msg, signature) }, "verify can be called only in the offchain worker context") } @@ -305,7 +322,7 @@ impl OffchainApi for () { }, "timestamp can be called only in the offchain worker context") } - fn sleep_until(deadline: Timestamp) { + fn sleep_until(deadline: offchain::Timestamp) { with_offchain(|ext| { ext.sleep_until(deadline) }, "sleep_until can be called only in the offchain worker context") @@ -317,21 +334,26 @@ impl OffchainApi for () { }, "random_seed can be called only in the offchain worker context") } - fn local_storage_set(key: &[u8], value: &[u8]) { + fn local_storage_set(kind: offchain::StorageKind, key: &[u8], value: &[u8]) { with_offchain(|ext| { - ext.local_storage_set(key, value) + ext.local_storage_set(kind, key, value) }, "local_storage_set can be called only in the offchain worker context") } - fn local_storage_compare_and_set(key: &[u8], old_value: &[u8], new_value: &[u8]) { + fn local_storage_compare_and_set( + kind: offchain::StorageKind, + key: &[u8], + old_value: &[u8], + new_value: &[u8], + ) -> bool { with_offchain(|ext| { - ext.local_storage_compare_and_set(key, old_value, new_value) + ext.local_storage_compare_and_set(kind, key, old_value, new_value) }, "local_storage_compare_and_set can be called only in the offchain worker context") } - fn local_storage_get(key: &[u8]) -> Option> { + fn local_storage_get(kind: offchain::StorageKind, key: &[u8]) -> Option> { with_offchain(|ext| { - ext.local_storage_get(key) + ext.local_storage_get(kind, key) }, "local_storage_get can be called only in the offchain worker context") } @@ -413,9 +435,32 @@ pub type ChildrenStorageOverlay = HashMap, StorageOverlay>; pub fn with_storage R>(storage: &mut StorageOverlay, f: F) -> R { let mut alt_storage = Default::default(); rstd::mem::swap(&mut alt_storage, storage); - let mut ext: BasicExternalities = alt_storage.into(); + let mut ext = BasicExternalities::new(alt_storage); let r = ext::using(&mut ext, f); - *storage = ext.into(); + *storage = ext.into_storages().0; + r +} + +/// Execute the given closure with global functions available whose functionality routes into +/// externalities that draw from and populate `storage` and `children_storage`. +/// Forwards the value that the closure returns. +pub fn with_storage_and_children R>( + storage: &mut StorageOverlay, + children_storage: &mut ChildrenStorageOverlay, + f: F +) -> R { + let mut alt_storage = Default::default(); + let mut alt_children_storage = Default::default(); + rstd::mem::swap(&mut alt_storage, storage); + rstd::mem::swap(&mut alt_children_storage, children_storage); + + let mut ext = BasicExternalities::new_with_children(alt_storage, alt_children_storage); + let r = ext::using(&mut ext, f); + + let storage_tuple = ext.into_storages(); + *storage = storage_tuple.0; + *children_storage = storage_tuple.1; + r } diff --git a/core/sr-io/without_std.rs b/core/sr-io/without_std.rs index b1dc10d1b88eb4d0cf92c51197b7f44c402eb402..5565f9ab3802c4af18665d5c93183fddd5f380c2 100644 --- a/core/sr-io/without_std.rs +++ b/core/sr-io/without_std.rs @@ -395,18 +395,24 @@ pub mod ext { /// Encrypt a piece of data using given crypto key. /// - /// If `key` is `0`, it will attempt to use current authority key. + /// If `key` is `0`, it will attempt to use current authority key of given `kind`. /// /// # Returns /// /// - `0` in case the key is invalid, `msg_len` is set to `u32::max_value` /// - Otherwise, pointer to the encrypted message in memory, /// `msg_len` contains the length of the message. - fn ext_encrypt(key: u32, data: *const u8, data_len: u32, msg_len: *mut u32) -> *mut u8; + fn ext_encrypt( + key: u32, + kind: u32, + data: *const u8, + data_len: u32, + msg_len: *mut u32 + ) -> *mut u8; /// Decrypt a piece of data using given crypto key. /// - /// If `key `is `0`, it will attempt to use current authority key. + /// If `key` is `0`, it will attempt to use current authority key of given `kind`. /// /// # Returns /// @@ -414,11 +420,17 @@ pub mod ext { /// `msg_len` is set to `u32::max_value` /// - Otherwise, pointer to the decrypted message in memory, /// `msg_len` contains the length of the message. - fn ext_decrypt(key: u32, data: *const u8, data_len: u32, msg_len: *mut u32) -> *mut u8; + fn ext_decrypt( + key: u32, + kind: u32, + data: *const u8, + data_len: u32, + msg_len: *mut u32 + ) -> *mut u8; /// Sign a piece of data using given crypto key. /// - /// If `key` is `0`, it will attempt to use current authority key. + /// If `key` is `0`, it will attempt to use current authority key of given `kind`. /// /// # Returns /// @@ -426,11 +438,17 @@ pub mod ext { /// `sig_data_len` is set to `u32::max_value` /// - Otherwise, pointer to the signature in memory, /// `sig_data_len` contains the length of the signature. - fn ext_sign(key: u32, data: *const u8, data_len: u32, sig_data_len: *mut u32) -> *mut u8; + fn ext_sign( + key: u32, + kind: u32, + data: *const u8, + data_len: u32, + sig_data_len: *mut u32 + ) -> *mut u8; /// Verifies that `signature` for `msg` matches given `key`. /// - /// If `key` is `0`, it will attempt to use current authority key. + /// If `key` is `0`, it will attempt to use current authority key of given `kind`. /// /// # Returns /// - `0` in case the signature is correct @@ -438,6 +456,7 @@ pub mod ext { /// - `u32::max_value` if the key is invalid. fn ext_verify( key: u32, + kind: u32, msg: *const u8, msg_len: u32, signature: *const u8, @@ -459,17 +478,22 @@ pub mod ext { fn ext_random_seed(data: *mut u8); /// Write a value to local storage. - fn ext_local_storage_set(key: *const u8, key_len: u32, value: *const u8, value_len: u32); + fn ext_local_storage_set(kind: u32, key: *const u8, key_len: u32, value: *const u8, value_len: u32); /// Write a value to local storage in atomic fashion. + /// + /// # Returns + /// - `0` in case the value has been set + /// - `1` if the `old_value` didn't match fn ext_local_storage_compare_and_set( + kind: u32, key: *const u8, key_len: u32, old_value: *const u8, old_value_len: u32, new_value: *const u8, new_value_len: u32 - ); + ) -> u32; /// Read a value from local storage. /// @@ -478,7 +502,7 @@ pub mod ext { /// /// - 0 if the value has not been found, the `value_len` is set to `u32::max_value`. /// - Otherwise, pointer to the value in memory. `value_len` contains the length of the value. - fn ext_local_storage_get(key: *const u8, key_len: u32, value_len: *mut u32) -> *mut u8; + fn ext_local_storage_get(kind: u32, key: *const u8, key_len: u32, value_len: *mut u32) -> *mut u8; /// Initiaties a http request. /// @@ -865,7 +889,7 @@ impl OffchainApi for () { } fn new_crypto_key(crypto: offchain::CryptoKind) -> Result { - let crypto = crypto as u8 as u32; + let crypto = crypto.into(); let ret = unsafe { ext_new_crypto_key.get()(crypto) }; @@ -877,41 +901,63 @@ impl OffchainApi for () { } } - fn encrypt(key: Option, data: &[u8]) -> Result, ()> { - let key = key.map(|x| x.0 as u32).unwrap_or(0); + fn encrypt( + key: Option, + kind: offchain::CryptoKind, + data: &[u8], + ) -> Result, ()> { + let key = key.map(Into::into).unwrap_or(0); + let kind = kind.into(); let mut len = 0_u32; unsafe { - let ptr = ext_encrypt.get()(key, data.as_ptr(), data.len() as u32, &mut len); + let ptr = ext_encrypt.get()(key, kind, data.as_ptr(), data.len() as u32, &mut len); from_raw_parts(ptr, len).ok_or(()) } } - fn decrypt(key: Option, data: &[u8]) -> Result, ()> { - let key = key.map(|x| x.0 as u32).unwrap_or(0); + fn decrypt( + key: Option, + kind: offchain::CryptoKind, + data: &[u8], + ) -> Result, ()> { + let key = key.map(Into::into).unwrap_or(0); + let kind = kind.into(); let mut len = 0_u32; unsafe { - let ptr = ext_decrypt.get()(key, data.as_ptr(), data.len() as u32, &mut len); + let ptr = ext_decrypt.get()(key, kind, data.as_ptr(), data.len() as u32, &mut len); from_raw_parts(ptr, len).ok_or(()) } } - fn sign(key: Option, data: &[u8]) -> Result, ()> { - let key = key.map(|x| x.0 as u32).unwrap_or(0); + fn sign( + key: Option, + kind: offchain::CryptoKind, + data: &[u8], + ) -> Result, ()> { + let key = key.map(Into::into).unwrap_or(0); + let kind = kind.into(); let mut len = 0_u32; unsafe { - let ptr = ext_sign.get()(key, data.as_ptr(), data.len() as u32, &mut len); + let ptr = ext_sign.get()(key, kind, data.as_ptr(), data.len() as u32, &mut len); from_raw_parts(ptr, len).ok_or(()) } } - fn verify(key: Option, msg: &[u8], signature: &[u8]) -> Result { - let key = key.map(|x| x.0 as u32).unwrap_or(0); + fn verify( + key: Option, + kind: offchain::CryptoKind, + msg: &[u8], + signature: &[u8], + ) -> Result { + let key = key.map(Into::into).unwrap_or(0); + let kind = kind.into(); let val = unsafe { ext_verify.get()( key, + kind, msg.as_ptr(), msg.len() as u32, signature.as_ptr(), @@ -932,7 +978,7 @@ impl OffchainApi for () { }) } - fn sleep_until(deadline: Timestamp) { + fn sleep_until(deadline: offchain::Timestamp) { unsafe { ext_sleep_until.get()(deadline.unix_millis()) } @@ -946,9 +992,10 @@ impl OffchainApi for () { result } - fn local_storage_set(key: &[u8], value: &[u8]) { + fn local_storage_set(kind: offchain::StorageKind, key: &[u8], value: &[u8]) { unsafe { ext_local_storage_set.get()( + kind.into(), key.as_ptr(), key.len() as u32, value.as_ptr(), @@ -957,23 +1004,25 @@ impl OffchainApi for () { } } - fn local_storage_compare_and_set(key: &[u8], old_value: &[u8], new_value: &[u8]) { + fn local_storage_compare_and_set(kind: offchain::StorageKind, key: &[u8], old_value: &[u8], new_value: &[u8]) -> bool { unsafe { ext_local_storage_compare_and_set.get()( + kind.into(), key.as_ptr(), key.len() as u32, old_value.as_ptr(), old_value.len() as u32, new_value.as_ptr(), new_value.len() as u32, - ) + ) == 0 } } - fn local_storage_get(key: &[u8]) -> Option> { + fn local_storage_get(kind: offchain::StorageKind, key: &[u8]) -> Option> { let mut len = 0u32; unsafe { let ptr = ext_local_storage_get.get()( + kind.into(), key.as_ptr(), key.len() as u32, &mut len, @@ -1011,7 +1060,7 @@ impl OffchainApi for () { let result = unsafe { ext_http_request_add_header.get()( - request_id.0 as u32, + request_id.into(), name.as_ptr(), name.len() as u32, value.as_ptr(), @@ -1033,7 +1082,7 @@ impl OffchainApi for () { ) -> Result<(), offchain::HttpError> { let res = unsafe { ext_http_request_write_body.get()( - request_id.0 as u32, + request_id.into(), chunk.as_ptr(), chunk.len() as u32, deadline.map_or(0, |x| x.unix_millis()), @@ -1076,7 +1125,7 @@ impl OffchainApi for () { let mut len = 0u32; let raw_result = unsafe { let ptr = ext_http_response_headers.get()( - request_id.0 as u32, + request_id.into(), &mut len, ); @@ -1093,7 +1142,7 @@ impl OffchainApi for () { ) -> Result { let res = unsafe { ext_http_response_read_body.get()( - request_id.0 as u32, + request_id.into(), buffer.as_mut_ptr(), buffer.len() as u32, deadline.map_or(0, |x| x.unix_millis()), diff --git a/core/sr-primitives/Cargo.toml b/core/sr-primitives/Cargo.toml index b549b4c71e0a69d9ed570d61dec6bb47b770e89b..a5399eb5f73ba9d3229c39bcd3875d8db756b251 100644 --- a/core/sr-primitives/Cargo.toml +++ b/core/sr-primitives/Cargo.toml @@ -8,15 +8,16 @@ edition = "2018" num-traits = { version = "0.2", default-features = false } integer-sqrt = { version = "0.1.2" } serde = { version = "1.0", optional = true, features = ["derive"] } -codec = { package = "parity-codec", version = "3.5.1", default-features = false, features = ["derive"] } +codec = { package = "parity-codec", version = "4.1.1", default-features = false, features = ["derive"] } substrate-primitives = { path = "../primitives", default-features = false } rstd = { package = "sr-std", path = "../sr-std", default-features = false } runtime_io = { package = "sr-io", path = "../sr-io", default-features = false } log = { version = "0.4", optional = true } +paste = { version = "0.1"} [dev-dependencies] serde_json = "1.0" -primitive-types = "0.2" +primitive-types = "0.4" [features] default = ["std"] diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index 1ef8bc227578cd572281d6616f726700b6eb71a6..607fdff376d1b236f05c56fb7788df9b69c5be73 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -28,6 +28,9 @@ pub use serde; #[doc(hidden)] pub use rstd; +#[doc(hidden)] +pub use paste; + #[cfg(feature = "std")] pub use runtime_io::{StorageOverlay, ChildrenStorageOverlay}; @@ -48,6 +51,9 @@ pub mod transaction_validity; /// Re-export these since they're only "kind of" generic. pub use generic::{DigestItem, Digest}; +/// Re-export this since it's part of the API of this crate. +pub use substrate_primitives::crypto::{key_types, KeyTypeId}; + /// A message indicating an invalid signature in extrinsic. pub const BAD_SIGNATURE: &str = "bad signature in extrinsic"; @@ -66,6 +72,14 @@ pub type Justification = Vec; use traits::{Verify, Lazy}; +/// A module identifier. These are per module and should be stored in a registry somewhere. +#[derive(Clone, Copy, Eq, PartialEq, Encode, Decode)] +pub struct ModuleId(pub [u8; 8]); + +impl traits::TypeId for ModuleId { + const TYPE_ID: [u8; 4] = *b"modl"; +} + /// A String that is a `&'static str` on `no_std` and a `Cow<'static, str>` on `std`. #[cfg(feature = "std")] pub type RuntimeString = ::std::borrow::Cow<'static, str>; @@ -101,7 +115,22 @@ pub trait BuildStorage: Sized { Ok((storage, child_storage)) } /// Assimilate the storage for this module into pre-existing overlays. - fn assimilate_storage(self, storage: &mut StorageOverlay, child_storage: &mut ChildrenStorageOverlay) -> Result<(), String>; + fn assimilate_storage( + self, + storage: &mut StorageOverlay, + child_storage: &mut ChildrenStorageOverlay + ) -> Result<(), String>; +} + +/// Something that can build the genesis storage of a module. +#[cfg(feature = "std")] +pub trait BuildModuleGenesisStorage: Sized { + /// Create the module genesis storage into the given `storage` and `child_storage`. + fn build_module_genesis_storage( + self, + storage: &mut StorageOverlay, + child_storage: &mut ChildrenStorageOverlay + ) -> Result<(), String>; } #[cfg(feature = "std")] @@ -162,6 +191,21 @@ impl Permill { /// Converts a fraction into `Permill`. #[cfg(feature = "std")] pub fn from_fraction(x: f64) -> Self { Self((x * 1_000_000.0) as u32) } + + /// Approximate the fraction `p/q` into a per million fraction + pub fn from_rational_approximation(p: N, q: N) -> Self + where N: traits::SimpleArithmetic + Clone + { + let p = p.min(q.clone()); + let factor = (q.clone() / 1_000_000u32.into()).max(1u32.into()); + + // Conversion can't overflow as p < q so ( p / (q/million)) < million + let p_reduce: u32 = (p / factor.clone()).try_into().unwrap_or_else(|_| panic!()); + let q_reduce: u32 = (q / factor.clone()).try_into().unwrap_or_else(|_| panic!()); + let part = p_reduce as u64 * 1_000_000u64 / q_reduce as u64; + + Permill(part as u32) + } } impl ops::Mul for Permill @@ -254,6 +298,21 @@ impl Perbill { #[cfg(feature = "std")] /// Construct new instance whose value is equal to `x` (between 0 and 1). pub fn from_fraction(x: f64) -> Self { Self((x.max(0.0).min(1.0) * 1_000_000_000.0) as u32) } + + /// Approximate the fraction `p/q` into a per billion fraction + pub fn from_rational_approximation(p: N, q: N) -> Self + where N: traits::SimpleArithmetic + Clone + { + let p = p.min(q.clone()); + let factor = (q.clone() / 1_000_000_000u32.into()).max(1u32.into()); + + // Conversion can't overflow as p < q so ( p / (q/billion)) < billion + let p_reduce: u32 = (p / factor.clone()).try_into().unwrap_or_else(|_| panic!()); + let q_reduce: u32 = (q / factor.clone()).try_into().unwrap_or_else(|_| panic!()); + let part = p_reduce as u64 * 1_000_000_000u64 / q_reduce as u64; + + Perbill(part as u32) + } } impl ops::Mul for Perbill @@ -318,8 +377,7 @@ impl From> for Perbill { } } -/// PerU128 is parts-per-u128-max-value. It stores a value between 0 and 1 in fixed point and -/// provides a means to multiply some other value by that. +/// PerU128 is parts-per-u128-max-value. It stores a value between 0 and 1 in fixed point. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq)] pub struct PerU128(u128); @@ -556,26 +614,32 @@ pub fn verify_encoded_lazy(sig: &V, item: &T, signe /// Helper macro for `impl_outer_config` #[macro_export] macro_rules! __impl_outer_config_types { + // Generic + Instance ( - $concrete:ident $config:ident $snake:ident < $ignore:ident, $instance:path > $( $rest:tt )* + $concrete:ident $config:ident $snake:ident { $instance:ident } < $ignore:ident >; + $( $rest:tt )* ) => { #[cfg(any(feature = "std", test))] - pub type $config = $snake::GenesisConfig<$concrete, $instance>; - $crate::__impl_outer_config_types! {$concrete $($rest)*} + pub type $config = $snake::GenesisConfig<$concrete, $snake::$instance>; + $crate::__impl_outer_config_types! { $concrete $( $rest )* } }; + // Generic ( - $concrete:ident $config:ident $snake:ident < $ignore:ident > $( $rest:tt )* + $concrete:ident $config:ident $snake:ident < $ignore:ident >; + $( $rest:tt )* ) => { #[cfg(any(feature = "std", test))] pub type $config = $snake::GenesisConfig<$concrete>; - $crate::__impl_outer_config_types! {$concrete $($rest)*} + $crate::__impl_outer_config_types! { $concrete $( $rest )* } }; + // No Generic and maybe Instance ( - $concrete:ident $config:ident $snake:ident $( $rest:tt )* + $concrete:ident $config:ident $snake:ident $( { $instance:ident } )?; + $( $rest:tt )* ) => { #[cfg(any(feature = "std", test))] pub type $config = $snake::GenesisConfig; - __impl_outer_config_types! {$concrete $($rest)*} + $crate::__impl_outer_config_types! { $concrete $( $rest )* } }; ($concrete:ident) => () } @@ -590,30 +654,76 @@ macro_rules! __impl_outer_config_types { macro_rules! impl_outer_config { ( pub struct $main:ident for $concrete:ident { - $( $config:ident => $snake:ident $( < $generic:ident $(, $instance:path)? > )*, )* + $( $config:ident => + $snake:ident $( $instance:ident )? $( <$generic:ident> )*, )* } ) => { - $crate::__impl_outer_config_types! { $concrete $( $config $snake $( < $generic $(, $instance)? > )* )* } - #[cfg(any(feature = "std", test))] - #[derive($crate::serde::Serialize, $crate::serde::Deserialize)] - #[serde(rename_all = "camelCase")] - #[serde(deny_unknown_fields)] - pub struct $main { - $( - pub $snake: Option<$config>, - )* + $crate::__impl_outer_config_types! { + $concrete $( $config $snake $( { $instance } )? $( <$generic> )*; )* } - #[cfg(any(feature = "std", test))] - impl $crate::BuildStorage for $main { - fn assimilate_storage(self, top: &mut $crate::StorageOverlay, children: &mut $crate::ChildrenStorageOverlay) -> ::std::result::Result<(), String> { + + $crate::paste::item! { + #[cfg(any(feature = "std", test))] + #[derive($crate::serde::Serialize, $crate::serde::Deserialize)] + #[serde(rename_all = "camelCase")] + #[serde(deny_unknown_fields)] + pub struct $main { $( - if let Some(extra) = self.$snake { - extra.assimilate_storage(top, children)?; - } + pub [< $snake $(_ $instance )? >]: Option<$config>, )* - Ok(()) + } + #[cfg(any(feature = "std", test))] + impl $crate::BuildStorage for $main { + fn assimilate_storage( + self, + top: &mut $crate::StorageOverlay, + children: &mut $crate::ChildrenStorageOverlay + ) -> std::result::Result<(), String> { + $( + if let Some(extra) = self.[< $snake $(_ $instance )? >] { + $crate::impl_outer_config! { + @CALL_FN + $concrete; + $snake; + $( $instance )?; + extra; + top; + children; + } + } + )* + Ok(()) + } } } + }; + (@CALL_FN + $runtime:ident; + $module:ident; + $instance:ident; + $extra:ident; + $top:ident; + $children:ident; + ) => { + $crate::BuildModuleGenesisStorage::<$runtime, $module::$instance>::build_module_genesis_storage( + $extra, + $top, + $children, + )?; + }; + (@CALL_FN + $runtime:ident; + $module:ident; + ; + $extra:ident; + $top:ident; + $children:ident; + ) => { + $crate::BuildModuleGenesisStorage::<$runtime, $module::__InherentHiddenInstance>::build_module_genesis_storage( + $extra, + $top, + $children, + )?; } } @@ -646,9 +756,9 @@ impl traits::Extrinsic for OpaqueExtrinsic { mod tests { use crate::codec::{Encode, Decode}; - macro_rules! per_thing_mul_upper_test { + macro_rules! per_thing_upper_test { ($num_type:tt, $per:tt) => { - // all sort of from_percent + // multiplication from all sort of from_percent assert_eq!($per::from_percent(100) * $num_type::max_value(), $num_type::max_value()); assert_eq!( $per::from_percent(99) * $num_type::max_value(), @@ -658,9 +768,23 @@ mod tests { assert_eq!($per::from_percent(1) * $num_type::max_value(), $num_type::max_value() / 100); assert_eq!($per::from_percent(0) * $num_type::max_value(), 0); - // bounds + // multiplication with bounds assert_eq!($per::one() * $num_type::max_value(), $num_type::max_value()); assert_eq!($per::zero() * $num_type::max_value(), 0); + + // from_rational_approximation + assert_eq!( + $per::from_rational_approximation(u128::max_value() - 1, u128::max_value()), + $per::one(), + ); + assert_eq!( + $per::from_rational_approximation(u128::max_value()/3, u128::max_value()), + $per::from_parts($per::one().0/3), + ); + assert_eq!( + $per::from_rational_approximation(1, u128::max_value()), + $per::zero(), + ); } } @@ -714,13 +838,14 @@ mod tests { use super::{Perbill, Permill}; use primitive_types::U256; - per_thing_mul_upper_test!(u32, Perbill); - per_thing_mul_upper_test!(u64, Perbill); - per_thing_mul_upper_test!(u128, Perbill); + per_thing_upper_test!(u32, Perbill); + per_thing_upper_test!(u64, Perbill); + per_thing_upper_test!(u128, Perbill); + + per_thing_upper_test!(u32, Permill); + per_thing_upper_test!(u64, Permill); + per_thing_upper_test!(u128, Permill); - per_thing_mul_upper_test!(u32, Permill); - per_thing_mul_upper_test!(u64, Permill); - per_thing_mul_upper_test!(u128, Permill); } #[test] diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index 35f3ec476f6d5b78b18c9c84f27fdefea75653fc..f8df25ec596b0de1f1287f4c47de0931e5d00885 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -19,8 +19,8 @@ use serde::{Serialize, Serializer, Deserialize, de::Error as DeError, Deserializer}; use std::{fmt::Debug, ops::Deref, fmt}; use crate::codec::{Codec, Encode, Decode}; -use crate::traits::{self, Checkable, Applyable, BlakeTwo256, OpaqueKeys}; -use crate::generic; +use crate::traits::{self, Checkable, Applyable, BlakeTwo256, OpaqueKeys, TypedKey}; +use crate::{generic, KeyTypeId}; use crate::weights::{Weighable, Weight}; pub use substrate_primitives::H256; use substrate_primitives::U256; @@ -37,12 +37,28 @@ impl Into for UintAuthorityId { } } +/// The key-type of the `UintAuthorityId` +pub const UINT_DUMMY_KEY: KeyTypeId = 0xdeadbeef; + +impl TypedKey for UintAuthorityId { + const KEY_TYPE: KeyTypeId = UINT_DUMMY_KEY; +} + impl OpaqueKeys for UintAuthorityId { - fn count() -> usize { 1 } + type KeyTypeIds = std::iter::Cloned>; + + fn key_ids() -> Self::KeyTypeIds { [UINT_DUMMY_KEY].iter().cloned() } // Unsafe, i know, but it's test code and it's just there because it's really convenient to // keep `UintAuthorityId` as a u64 under the hood. - fn get_raw(&self, _: usize) -> &[u8] { unsafe { &std::mem::transmute::<_, &[u8; 8]>(&self.0)[..] } } - fn get(&self, _: usize) -> Option { self.0.using_encoded(|mut x| T::decode(&mut x)) } + fn get_raw(&self, _: KeyTypeId) -> &[u8] { + unsafe { + std::slice::from_raw_parts( + &self.0 as *const _ as *const u8, + std::mem::size_of::(), + ) + } + } + fn get(&self, _: KeyTypeId) -> Option { self.0.using_encoded(|mut x| T::decode(&mut x)) } } /// Digest item diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index b2bb7ab80511d659f6d179e37fdf89c5acb69841..a6d94babbe577e8a191f1490d594f14e24df05b2 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -25,6 +25,7 @@ use substrate_primitives::{self, Hasher, Blake2Hasher}; use crate::codec::{Codec, Encode, Decode, HasCompact}; use crate::transaction_validity::TransactionValidity; use crate::generic::{Digest, DigestItem}; +pub use substrate_primitives::crypto::TypedKey; pub use integer_sqrt::IntegerSquareRoot; pub use num_traits::{ Zero, One, Bounded, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, @@ -162,6 +163,13 @@ impl Convert for Identity { fn convert(a: T) -> T { a } } +/// A structure that performs standard conversion using the standard Rust conversion traits. +pub struct ConvertInto; + +impl> Convert for ConvertInto { + fn convert(a: A) -> B { a.into() } +} + /// A meta trait for arithmetic. /// /// Arithmetic types do all the usual stuff you'd expect numbers to do. They are guaranteed to @@ -594,6 +602,21 @@ pub trait MaybeHash {} #[cfg(not(feature = "std"))] impl MaybeHash for T {} +/// A type that provides a randomness beacon. +pub trait RandomnessBeacon { + /// Returns 32 bytes of random data. The output will change eventually, but + /// is not guaranteed to be different between any two calls. + /// + /// # Security + /// + /// This MUST NOT be used for gambling, as it can be influenced by a + /// malicious validator in the short term. It MAY be used in many + /// cryptographic protocols, however, so long as one remembers that this + /// (like everything else on-chain) is public. For example, it can be + /// used where a number is needed that cannot have been chosen by an + /// adversary, for purposes such as public-coin zero-knowledge proofs. + fn random() -> [u8; 32]; +} /// A type that can be used in runtime structures. pub trait Member: Send + Sync + Sized + MaybeDebug + Eq + PartialEq + Clone + 'static {} @@ -820,16 +843,140 @@ pub trait ValidateUnsigned { /// Opaque datatype that may be destructured into a series of raw byte slices (which represent /// individual keys). pub trait OpaqueKeys: Clone { - /// Return the number of encoded keys. - fn count() -> usize { 0 } - /// Get the raw bytes of key with index `i`. - fn get_raw(&self, i: usize) -> &[u8]; + /// An iterator over the type IDs of keys that this holds. + type KeyTypeIds: IntoIterator; + + /// Return an iterator over the key-type IDs supported by this set. + fn key_ids() -> Self::KeyTypeIds; + /// Get the raw bytes of key with key-type ID `i`. + fn get_raw(&self, i: super::KeyTypeId) -> &[u8]; /// Get the decoded key with index `i`. - fn get(&self, i: usize) -> Option { T::decode(&mut self.get_raw(i)) } + fn get(&self, i: super::KeyTypeId) -> Option { T::decode(&mut self.get_raw(i)) } /// Verify a proof of ownership for the keys. fn ownership_proof_is_valid(&self, _proof: &[u8]) -> bool { true } } +struct TrailingZeroInput<'a>(&'a [u8]); +impl<'a> codec::Input for TrailingZeroInput<'a> { + fn read(&mut self, into: &mut [u8]) -> usize { + let len = into.len().min(self.0.len()); + into[..len].copy_from_slice(&self.0[..len]); + for i in &mut into[len..] { + *i = 0; + } + self.0 = &self.0[len..]; + into.len() + } +} + +/// This type can be converted into and possibly from an AccountId (which itself is generic). +pub trait AccountIdConversion: Sized { + /// Convert into an account ID. This is infallible. + fn into_account(&self) -> AccountId { self.into_sub_account(&()) } + + /// Try to convert an account ID into this type. Might not succeed. + fn try_from_account(a: &AccountId) -> Option { + Self::try_from_sub_account::<()>(a).map(|x| x.0) + } + + /// Convert this value amalgamated with the a secondary "sub" value into an account ID. This is + /// infallible. + /// + /// NOTE: The account IDs from this and from `into_account` are *not* guaranteed to be distinct + /// for any given value of `self`, nor are different invocations to this with different types + /// `T`. For example, the following will all encode to the same account ID value: + /// - `self.into_sub_account(0u32)` + /// - `self.into_sub_account(vec![0u8; 0])` + /// - `self.into_account()` + fn into_sub_account(&self, sub: S) -> AccountId; + + /// Try to convert an account ID into this type. Might not succeed. + fn try_from_sub_account(x: &AccountId) -> Option<(Self, S)>; +} + +/// Provide a simple 4 byte identifier for a type. +pub trait TypeId { + /// Simple 4 byte identifier. + const TYPE_ID: [u8; 4]; +} + +/// Format is TYPE_ID ++ encode(parachain ID) ++ 00.... where 00... is indefinite trailing zeroes to +/// fill AccountId. +impl AccountIdConversion for Id { + fn into_sub_account(&self, sub: S) -> T { + (Id::TYPE_ID, self, sub).using_encoded(|b| + T::decode(&mut TrailingZeroInput(b)) + ).unwrap_or_default() + } + + fn try_from_sub_account(x: &T) -> Option<(Self, S)> { + x.using_encoded(|d| { + if &d[0..4] != Id::TYPE_ID { return None } + let mut cursor = &d[4..]; + let result = Decode::decode(&mut cursor)?; + if cursor.iter().all(|x| *x == 0) { + Some(result) + } else { + None + } + }) + } +} + +#[cfg(test)] +mod tests { + use super::AccountIdConversion; + use crate::codec::{Encode, Decode}; + + #[derive(Encode, Decode, Default, PartialEq, Debug)] + struct U32Value(u32); + impl super::TypeId for U32Value { + const TYPE_ID: [u8; 4] = [0x0d, 0xf0, 0xfe, 0xca]; + } + // cafef00d + + #[derive(Encode, Decode, Default, PartialEq, Debug)] + struct U16Value(u16); + impl super::TypeId for U16Value { + const TYPE_ID: [u8; 4] = [0xfe, 0xca, 0x0d, 0xf0]; + } + // f00dcafe + + type AccountId = u64; + + #[test] + fn into_account_should_work() { + let r: AccountId = U32Value::into_account(&U32Value(0xdeadbeef)); + assert_eq!(r, 0x_deadbeef_cafef00d); + } + + #[test] + fn try_from_account_should_work() { + let r = U32Value::try_from_account(&0x_deadbeef_cafef00d_u64); + assert_eq!(r.unwrap(), U32Value(0xdeadbeef)); + } + + #[test] + fn into_account_with_fill_should_work() { + let r: AccountId = U16Value::into_account(&U16Value(0xc0da)); + assert_eq!(r, 0x_0000_c0da_f00dcafe); + } + + #[test] + fn try_from_account_with_fill_should_work() { + let r = U16Value::try_from_account(&0x0000_c0da_f00dcafe_u64); + assert_eq!(r.unwrap(), U16Value(0xc0da)); + } + + #[test] + fn bad_try_from_account_should_fail() { + let r = U16Value::try_from_account(&0x0000_c0de_baadcafe_u64); + assert!(r.is_none()); + let r = U16Value::try_from_account(&0x0100_c0da_f00dcafe_u64); + assert!(r.is_none()); + } +} + /// Calls a given macro a number of times with a set of fixed params and an incrementing numeral. /// e.g. /// ```nocompile @@ -850,41 +997,62 @@ macro_rules! count { }; } -#[macro_export] -/// Just implement `OpaqueKeys` for a given tuple-struct. +/// Implement `OpaqueKeys` for a described struct. /// Would be much nicer for this to be converted to `derive` code. +/// +/// Every field type must be equivalent implement `as_ref()`, which is expected +/// to hold the standard SCALE-encoded form of that key. This is typically +/// just the bytes of the key. +/// +/// ```rust +/// use sr_primitives::{impl_opaque_keys, key_types, KeyTypeId}; +/// +/// impl_opaque_keys! { +/// pub struct Keys { +/// #[id(key_types::ED25519)] +/// pub ed25519: [u8; 32], +/// #[id(key_types::SR25519)] +/// pub sr25519: [u8; 32], +/// } +/// } +/// ``` +#[macro_export] macro_rules! impl_opaque_keys { ( - pub struct $name:ident ( $( $t:ty ),* $(,)* ); - ) => { - impl_opaque_keys! { - pub struct $name ( $( $t ,)* ); - impl OpaqueKeys for _ {} - } - }; - ( - pub struct $name:ident ( $( $t:ty ),* $(,)* ); - impl OpaqueKeys for _ { - $($rest:tt)* + pub struct $name:ident { + $( + #[id($key_id:expr)] + pub $field:ident: $type:ty, + )* } ) => { #[derive(Default, Clone, PartialEq, Eq, $crate::codec::Encode, $crate::codec::Decode)] #[cfg_attr(feature = "std", derive(Debug, $crate::serde::Serialize, $crate::serde::Deserialize))] - pub struct $name($( pub $t ,)*); + pub struct $name { + $( + pub $field: $type, + )* + } + impl $crate::traits::OpaqueKeys for $name { - fn count() -> usize { - let mut c = 0; - $( let _: $t; c += 1; )* - c + type KeyTypeIds = $crate::rstd::iter::Cloned< + $crate::rstd::slice::Iter<'static, $crate::KeyTypeId> + >; + + fn key_ids() -> Self::KeyTypeIds { + [ + $($key_id),* + ].iter().cloned() } - fn get_raw(&self, i: usize) -> &[u8] { - $crate::count!(impl_opaque_keys (!! self i) $($t),*); - &[] + + fn get_raw(&self, i: $crate::KeyTypeId) -> &[u8] { + match i { + $( + i if i == $key_id => self.$field.as_ref(), + )* + _ => &[], + } } - $($rest)* } }; - ( !! $self:ident $param_i:ident $i:tt) => { - if $param_i == $i { return $self.$i.as_ref() } - } } diff --git a/core/sr-sandbox/Cargo.toml b/core/sr-sandbox/Cargo.toml index f8d98253ad7143e083a4dc039d5da81f2a1f7224..748bc543623e3d0bad0f46392cc97baeee0961f4 100755 --- a/core/sr-sandbox/Cargo.toml +++ b/core/sr-sandbox/Cargo.toml @@ -12,7 +12,7 @@ rustc_version = "0.2" wasmi = { version = "0.4.3", optional = true } primitives = { package = "substrate-primitives", path = "../primitives", default-features = false } rstd = { package = "sr-std", path = "../sr-std", default-features = false } -codec = { package = "parity-codec", version = "3.2", default-features = false } +codec = { package = "parity-codec", version = "4.1.1", default-features = false } [dev-dependencies] wabt = "~0.7.4" diff --git a/core/sr-sandbox/src/lib.rs b/core/sr-sandbox/src/lib.rs index 1e8b2b3f1df5e63f76012f7e642f8dd04422aabf..9cb39236b0e265eb6bfc4b58706aad3e74194547 100755 --- a/core/sr-sandbox/src/lib.rs +++ b/core/sr-sandbox/src/lib.rs @@ -96,7 +96,7 @@ impl Memory { /// /// The memory allocated with initial number of pages specified by `initial`. /// Minimal possible value for `initial` is 0 and maximum possible is `65536`. - /// (Since maximum addressible memory is 232 = 4GiB = 65536 * 64KiB). + /// (Since maximum addressable memory is 232 = 4GiB = 65536 * 64KiB). /// /// It is possible to limit maximum number of pages this memory instance can have by specifying /// `maximum`. If not specified, this memory instance would be able to allocate up to 4GiB. @@ -168,7 +168,6 @@ impl EnvironmentDefinitionBuilder { /// This instance can be used for invoking exported functions. pub struct Instance { inner: imp::Instance, - } impl Instance { diff --git a/core/sr-sandbox/without_std.rs b/core/sr-sandbox/without_std.rs index 894ba43eb0ccc39795ef89590835591fcfd4d50d..9fb255a5230f6cb076c769b7ff9ca2e20beae9e5 100755 --- a/core/sr-sandbox/without_std.rs +++ b/core/sr-sandbox/without_std.rs @@ -33,7 +33,7 @@ mod ffi { /// # Safety /// /// This function should be only called with a `HostFuncIndex` that was previously registered - /// in the environment defintion. Typically this should only + /// in the environment definition. Typically this should only /// be called with an argument received in `dispatch_thunk`. pub unsafe fn coerce_host_index_to_func(idx: HostFuncIndex) -> HostFuncType { // We need to ensure that sizes of a callable function pointer and host function index is diff --git a/core/sr-std/src/lib.rs b/core/sr-std/src/lib.rs index b9874bcc2018d5e680fdf51025ffaa77165700ac..24c137c285f41096e94b71a43eaa967fc7f16cc9 100644 --- a/core/sr-std/src/lib.rs +++ b/core/sr-std/src/lib.rs @@ -30,6 +30,32 @@ macro_rules! map { ) } +/// Feature gate some code that should only be run when `std` feature is enabled. +/// +/// # Example +/// +/// ``` +/// use sr_std::if_std; +/// +/// if_std! { +/// // This code is only being compiled and executed when the `std` feature is enabled. +/// println!("Hello native world"); +/// } +/// ``` +#[cfg(feature = "std")] +#[macro_export] +macro_rules! if_std { + ( $( $code:tt )* ) => { + $( $code )* + } +} + +#[cfg(not(feature = "std"))] +#[macro_export] +macro_rules! if_std { + ( $( $code:tt )* ) => {} +} + #[cfg(feature = "std")] include!("../with_std.rs"); diff --git a/core/sr-std/with_std.rs b/core/sr-std/with_std.rs index 5824e26241675e80336a96bf7570f128b909ed88..0d5ee04ed51ab9e5dee332b8a1c6447890eb31d3 100644 --- a/core/sr-std/with_std.rs +++ b/core/sr-std/with_std.rs @@ -38,4 +38,5 @@ pub use std::vec; pub mod collections { pub use std::collections::btree_map; pub use std::collections::btree_set; + pub use std::collections::vec_deque; } diff --git a/core/sr-std/without_std.rs b/core/sr-std/without_std.rs index db81372c2f0708e6f8e86ea171860f06efd2b539..327e271049d586f7f35b6292ca52a5352634d703 100755 --- a/core/sr-std/without_std.rs +++ b/core/sr-std/without_std.rs @@ -68,10 +68,11 @@ pub use core::slice; // Allow intepreting vectors of bytes as strings, but not constructing them. pub use core::str; // We are trying to avoid certain things here, such as `core::string` -// (if you need `String` you most probably doing something wrong, since +// (if you need `String` you are probably doing something wrong, since // runtime doesn't require anything human readable). pub mod collections { pub use alloc::collections::btree_map; pub use alloc::collections::btree_set; + pub use alloc::collections::vec_deque; } diff --git a/core/sr-version/Cargo.toml b/core/sr-version/Cargo.toml index b4810b8457d81271d44264f1cae48172b277d12c..fb9b0a468875c382321cc1eab635e901f8aae774 100644 --- a/core/sr-version/Cargo.toml +++ b/core/sr-version/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] impl-serde = { version = "0.1", optional = true } serde = { version = "1.0", optional = true, features = ["derive"] } -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } rstd = { package = "sr-std", path = "../sr-std", default-features = false } runtime_primitives = { package = "sr-primitives", path = "../sr-primitives", default-features = false } diff --git a/core/state-db/Cargo.toml b/core/state-db/Cargo.toml index 8c02dbc450fb82989e45f864ca710611d30ed0d5..a8dad1e84e0393c274f7ea8a0095399d579e7d21 100644 --- a/core/state-db/Cargo.toml +++ b/core/state-db/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" parking_lot = "0.8.0" log = "0.4" primitives = { package = "substrate-primitives", path = "../../core/primitives" } -parity-codec = { version = "3.3", features = ["derive"] } +parity-codec = { version = "4.1.1", features = ["derive"] } [dev-dependencies] env_logger = "0.6" diff --git a/core/state-machine/Cargo.toml b/core/state-machine/Cargo.toml index b1cb98ae808875bd8a9d28fc6a38063979c361f3..bcb471d5306db5c76a9228606de83c590d72085c 100644 --- a/core/state-machine/Cargo.toml +++ b/core/state-machine/Cargo.toml @@ -8,13 +8,13 @@ edition = "2018" [dependencies] log = "0.4" parking_lot = "0.8.0" -hash-db = "0.12" -trie-db = "0.12" -trie-root = "0.12" +hash-db = "0.14.0" +trie-db = "0.14.0" +trie-root = "0.14.0" trie = { package = "substrate-trie", path = "../trie" } primitives = { package = "substrate-primitives", path = "../primitives" } panic-handler = { package = "substrate-panic-handler", path = "../panic-handler" } -parity-codec = "3.3" +parity-codec = "4.1.1" num-traits = "0.2" [dev-dependencies] diff --git a/core/state-machine/src/basic.rs b/core/state-machine/src/basic.rs index e9939711f1e47e9d86c5f751ab4ee2389046113c..e922db260cf02bb1344b8c0c786b29efd32173f9 100644 --- a/core/state-machine/src/basic.rs +++ b/core/state-machine/src/basic.rs @@ -18,67 +18,64 @@ use std::collections::HashMap; use std::iter::FromIterator; +use crate::backend::{Backend, InMemory}; use hash_db::Hasher; use trie::trie_root; use primitives::offchain; -use primitives::storage::well_known_keys::{CHANGES_TRIE_CONFIG, CODE, HEAP_PAGES}; +use primitives::storage::well_known_keys::{HEAP_PAGES, is_child_storage_key}; use parity_codec::Encode; -use super::{ChildStorageKey, Externalities, OverlayedChanges}; +use super::{ChildStorageKey, Externalities}; use log::warn; /// Simple HashMap-based Externalities impl. +#[derive(Debug)] pub struct BasicExternalities { - inner: HashMap, Vec>, - changes: OverlayedChanges, - code: Option>, + top: HashMap, Vec>, + children: HashMap, HashMap, Vec>>, } impl BasicExternalities { /// Create a new instance of `BasicExternalities` - pub fn new(inner: HashMap, Vec>) -> Self { - Self::new_with_code(&[], inner) + pub fn new(top: HashMap, Vec>) -> Self { + Self::new_with_children(top, Default::default()) } - /// Create a new instance of `BasicExternalities` - pub fn new_with_code(code: &[u8], mut inner: HashMap, Vec>) -> Self { - let mut overlay = OverlayedChanges::default(); - super::set_changes_trie_config( - &mut overlay, - inner.get(&CHANGES_TRIE_CONFIG.to_vec()).cloned(), - false, - ).expect("changes trie configuration is correct in test env; qed"); - - inner.insert(HEAP_PAGES.to_vec(), 8u64.encode()); - + /// Create a new instance of `BasicExternalities` with children + pub fn new_with_children( + mut top: HashMap, Vec>, + children: HashMap, HashMap, Vec>>, + ) -> Self { + top.insert(HEAP_PAGES.to_vec(), 8u64.encode()); BasicExternalities { - inner, - changes: overlay, - code: Some(code.to_vec()), + top, + children, } } /// Insert key/value pub fn insert(&mut self, k: Vec, v: Vec) -> Option> { - self.inner.insert(k, v) + self.top.insert(k, v) } -} -impl ::std::fmt::Debug for BasicExternalities { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "{:?}", self.inner) + /// Consume self and returns inner storages + pub fn into_storages(self) -> ( + HashMap, Vec>, + HashMap, HashMap, Vec>>, + ) { + (self.top, self.children) } } impl PartialEq for BasicExternalities { fn eq(&self, other: &BasicExternalities) -> bool { - self.inner.eq(&other.inner) + self.top.eq(&other.top) && self.children.eq(&other.children) } } impl FromIterator<(Vec, Vec)> for BasicExternalities { fn from_iter, Vec)>>(iter: I) -> Self { - let mut t = Self::new(Default::default()); - t.inner.extend(iter); + let mut t = Self::default(); + t.top.extend(iter); t } } @@ -87,69 +84,84 @@ impl Default for BasicExternalities { fn default() -> Self { Self::new(Default::default()) } } -impl From for HashMap, Vec> { - fn from(tex: BasicExternalities) -> Self { - tex.inner.into() - } -} - -impl From< HashMap, Vec> > for BasicExternalities { +impl From, Vec>> for BasicExternalities { fn from(hashmap: HashMap, Vec>) -> Self { BasicExternalities { - inner: hashmap, - changes: Default::default(), - code: None, + top: hashmap, + children: Default::default(), } } } impl Externalities for BasicExternalities where H::Out: Ord { fn storage(&self, key: &[u8]) -> Option> { - match key { - CODE => self.code.clone(), - _ => self.inner.get(key).cloned(), - } + self.top.get(key).cloned() } fn original_storage(&self, key: &[u8]) -> Option> { Externalities::::storage(self, key) } - fn child_storage(&self, _storage_key: ChildStorageKey, _key: &[u8]) -> Option> { - None + fn child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option> { + self.children.get(storage_key.as_ref()).and_then(|child| child.get(key)).cloned() } fn place_storage(&mut self, key: Vec, maybe_value: Option>) { - self.changes.set_storage(key.clone(), maybe_value.clone()); - match key.as_ref() { - CODE => self.code = maybe_value, - _ => { - match maybe_value { - Some(value) => { self.inner.insert(key, value); } - None => { self.inner.remove(&key); } - } - } + if is_child_storage_key(&key) { + warn!(target: "trie", "Refuse to set child storage key via main storage"); + return; + } + + match maybe_value { + Some(value) => { self.top.insert(key, value); } + None => { self.top.remove(&key); } } } - fn place_child_storage(&mut self, _storage_key: ChildStorageKey, _key: Vec, _value: Option>) { + fn place_child_storage( + &mut self, + storage_key: ChildStorageKey, + key: Vec, + value: Option> + ) { + let child_map = self.children.entry(storage_key.into_owned()).or_default(); + if let Some(value) = value { + child_map.insert(key, value); + } else { + child_map.remove(&key); + } } - fn kill_child_storage(&mut self, _storage_key: ChildStorageKey) { } + fn kill_child_storage(&mut self, storage_key: ChildStorageKey) { + self.children.remove(storage_key.as_ref()); + } fn clear_prefix(&mut self, prefix: &[u8]) { - self.changes.clear_prefix(prefix); - self.inner.retain(|key, _| !key.starts_with(prefix)); + if is_child_storage_key(prefix) { + warn!( + target: "trie", + "Refuse to clear prefix that is part of child storage key via main storage" + ); + return; + } + + self.top.retain(|key, _| !key.starts_with(prefix)); } fn chain_id(&self) -> u64 { 42 } fn storage_root(&mut self) -> H::Out { - trie_root::(self.inner.clone()) + trie_root::(self.top.clone()) } - fn child_storage_root(&mut self, _storage_key: ChildStorageKey) -> Vec { - vec![42] + fn child_storage_root(&mut self, storage_key: ChildStorageKey) -> Vec { + if let Some(child) = self.children.get(storage_key.as_ref()) { + let delta = child.clone().into_iter().map(|(k, v)| (k, Some(v))); + + InMemory::::default().child_storage_root(storage_key.as_ref(), delta).0 + } else { + vec![] + } } fn storage_changes_root(&mut self, _parent: H::Out) -> Result, ()> { @@ -165,7 +177,8 @@ impl Externalities for BasicExternalities where H::Out: Ord { #[cfg(test)] mod tests { use super::*; - use primitives::{Blake2Hasher, H256}; + use primitives::{Blake2Hasher, H256, map}; + use primitives::storage::well_known_keys::CODE; use hex_literal::hex; #[test] @@ -189,4 +202,33 @@ mod tests { assert_eq!(&ext.storage(CODE).unwrap(), &code); } + + #[test] + fn children_works() { + let child_storage = b":child_storage:default:test".to_vec(); + + let mut ext = BasicExternalities::new_with_children( + Default::default(), + map![ + child_storage.clone() => map![ + b"doe".to_vec() => b"reindeer".to_vec() + ] + ] + ); + + let ext = &mut ext as &mut dyn Externalities; + + let child = || ChildStorageKey::from_vec(child_storage.clone()).unwrap(); + + assert_eq!(ext.child_storage(child(), b"doe"), Some(b"reindeer".to_vec())); + + ext.set_child_storage(child(), b"dog".to_vec(), b"puppy".to_vec()); + assert_eq!(ext.child_storage(child(), b"dog"), Some(b"puppy".to_vec())); + + ext.clear_child_storage(child(), b"dog"); + assert_eq!(ext.child_storage(child(), b"dog"), None); + + ext.kill_child_storage(child()); + assert_eq!(ext.child_storage(child(), b"doe"), None); + } } diff --git a/core/state-machine/src/changes_trie/build.rs b/core/state-machine/src/changes_trie/build.rs index 487fde2e3528c434c23303126a22ab1aca1a06a0..d32d28906fb48eb0f37345df3c32877800b1d66e 100644 --- a/core/state-machine/src/changes_trie/build.rs +++ b/core/state-machine/src/changes_trie/build.rs @@ -16,7 +16,8 @@ //! Structures and functions required to build changes trie for given block. -use std::collections::{BTreeMap, BTreeSet}; +use std::collections::BTreeMap; +use std::collections::btree_map::Entry; use parity_codec::Decode; use hash_db::Hasher; use num_traits::One; @@ -29,77 +30,91 @@ use crate::changes_trie::{AnchorBlockId, Configuration, Storage, BlockNumber}; /// Prepare input pairs for building a changes trie of given block. /// -/// Returns Err if storage error has occured OR if storage haven't returned +/// Returns Err if storage error has occurred OR if storage haven't returned /// required data. -/// Returns Ok(None) data required to prepare input pairs is not collected -/// or storage is not provided. pub fn prepare_input<'a, B, S, H, Number>( - backend: &B, + backend: &'a B, storage: &'a S, config: &'a Configuration, - changes: &OverlayedChanges, + changes: &'a OverlayedChanges, parent: &'a AnchorBlockId, -) -> Result>>, String> +) -> Result> + 'a, String> where B: Backend, S: Storage, - H: Hasher, + H: Hasher + 'a, Number: BlockNumber, { - let mut input = Vec::new(); - input.extend(prepare_extrinsics_input( + let number = parent.number.clone() + One::one(); + let extrinsics_input = prepare_extrinsics_input( backend, - parent.number.clone() + 1.into(), - changes)?); - input.extend(prepare_digest_input::<_, H, Number>( + &number, + changes)?; + let digest_input = prepare_digest_input::<_, H, Number>( parent, config, - storage)?); - - Ok(Some(input)) + number, + storage)?; + Ok(extrinsics_input.chain(digest_input)) } /// Prepare ExtrinsicIndex input pairs. -fn prepare_extrinsics_input( - backend: &B, - block: Number, - changes: &OverlayedChanges, -) -> Result>, String> +fn prepare_extrinsics_input<'a, B, H, Number>( + backend: &'a B, + block: &Number, + changes: &'a OverlayedChanges, +) -> Result> + 'a, String> where B: Backend, H: Hasher, Number: BlockNumber, { - let mut extrinsic_map = BTreeMap::, BTreeSet>::new(); - for (key, val) in changes.prospective.top.iter().chain(changes.committed.top.iter()) { - let extrinsics = match val.extrinsics { - Some(ref extrinsics) => extrinsics, - None => continue, - }; + changes.committed.top.iter() + .chain(changes.prospective.top.iter()) + .filter(|( _, v)| v.extrinsics.is_some()) + .try_fold(BTreeMap::new(), |mut map: BTreeMap<&[u8], (ExtrinsicIndex, Vec)>, (k, v)| { + match map.entry(k) { + Entry::Vacant(entry) => { + // ignore temporary values (values that have null value at the end of operation + // AND are not in storage at the beginning of operation + if !changes.storage(k).map(|v| v.is_some()).unwrap_or_default() { + if !backend.exists_storage(k).map_err(|e| format!("{}", e))? { + return Ok(map); + } + } - // ignore values that have null value at the end of operation AND are not in storage - // at the beginning of operation - if !changes.storage(key).map(|v| v.is_some()).unwrap_or_default() { - if !backend.exists_storage(key).map_err(|e| format!("{}", e))? { - continue; + let extrinsics = v.extrinsics.as_ref() + .expect("filtered by filter() call above; qed") + .iter().cloned().collect(); + entry.insert((ExtrinsicIndex { + block: block.clone(), + key: k.to_vec(), + }, extrinsics)); + }, + Entry::Occupied(mut entry) => { + // we do not need to check for temporary values here, because entry is Occupied + // AND we are checking it before insertion + let extrinsics = &mut entry.get_mut().1; + extrinsics.extend( + v.extrinsics.as_ref() + .expect("filtered by filter() call above; qed") + .iter() + .cloned() + ); + extrinsics.sort_unstable(); + }, } - } - - extrinsic_map.entry(key.clone()).or_default() - .extend(extrinsics.iter().cloned()); - } - Ok(extrinsic_map.into_iter() - .map(move |(key, extrinsics)| InputPair::ExtrinsicIndex(ExtrinsicIndex { - block: block.clone(), - key, - }, extrinsics.iter().cloned().collect()))) + Ok(map) + }) + .map(|pairs| pairs.into_iter().map(|(_, (k, v))| InputPair::ExtrinsicIndex(k, v))) } /// Prepare DigestIndex input pairs. fn prepare_digest_input<'a, S, H, Number>( parent: &'a AnchorBlockId, config: &Configuration, + block: Number, storage: &'a S ) -> Result> + 'a, String> where @@ -108,35 +123,52 @@ fn prepare_digest_input<'a, S, H, Number>( H::Out: 'a, Number: BlockNumber, { - let mut digest_map = BTreeMap::, BTreeSet>::new(); - for digest_build_block in digest_build_iterator(config, parent.number.clone() + One::one()) { - let trie_root = storage.root(parent, digest_build_block.clone())?; - let trie_root = trie_root.ok_or_else(|| format!("No changes trie root for block {}", digest_build_block.clone()))?; - let trie_storage = TrieBackendEssence::<_, H>::new( - crate::changes_trie::TrieBackendStorageAdapter(storage), - trie_root, - ); + digest_build_iterator(config, block.clone()) + .try_fold(BTreeMap::new(), move |mut map, digest_build_block| { + let trie_root = storage.root(parent, digest_build_block.clone())?; + let trie_root = trie_root.ok_or_else(|| format!("No changes trie root for block {}", digest_build_block.clone()))?; + let trie_storage = TrieBackendEssence::<_, H>::new( + crate::changes_trie::TrieBackendStorageAdapter(storage), + trie_root, + ); - let extrinsic_prefix = ExtrinsicIndex::key_neutral_prefix(digest_build_block.clone()); - trie_storage.for_keys_with_prefix(&extrinsic_prefix, |key| - if let Some(InputKey::ExtrinsicIndex::(trie_key)) = Decode::decode(&mut &key[..]) { - digest_map.entry(trie_key.key).or_default() - .insert(digest_build_block.clone()); - }); + let mut insert_to_map = |key: Vec| { + match map.entry(key.clone()) { + Entry::Vacant(entry) => { + entry.insert((DigestIndex { + block: block.clone(), + key, + }, vec![digest_build_block.clone()])); + }, + Entry::Occupied(mut entry) => { + // DigestIndexValue must be sorted. Here we are relying on the fact that digest_build_iterator() + // returns blocks in ascending order => we only need to check for duplicates + // + // is_dup_block could be true when key has been changed in both digest block + // AND other blocks that it covers + let is_dup_block = entry.get().1.last() == Some(&digest_build_block); + if !is_dup_block { + entry.get_mut().1.push(digest_build_block.clone()); + } + }, + } + }; - let digest_prefix = DigestIndex::key_neutral_prefix(digest_build_block.clone()); - trie_storage.for_keys_with_prefix(&digest_prefix, |key| - if let Some(InputKey::DigestIndex::(trie_key)) = Decode::decode(&mut &key[..]) { - digest_map.entry(trie_key.key).or_default() - .insert(digest_build_block.clone()); - }); - } + let extrinsic_prefix = ExtrinsicIndex::key_neutral_prefix(digest_build_block.clone()); + trie_storage.for_keys_with_prefix(&extrinsic_prefix, |key| + if let Some(InputKey::ExtrinsicIndex::(trie_key)) = Decode::decode(&mut &key[..]) { + insert_to_map(trie_key.key); + }); - Ok(digest_map.into_iter() - .map(move |(key, set)| InputPair::DigestIndex(DigestIndex { - block: parent.number.clone() + One::one(), - key - }, set.into_iter().collect()))) + let digest_prefix = DigestIndex::key_neutral_prefix(digest_build_block.clone()); + trie_storage.for_keys_with_prefix(&digest_prefix, |key| + if let Some(InputKey::DigestIndex::(trie_key)) = Decode::decode(&mut &key[..]) { + insert_to_map(trie_key.key); + }); + + Ok(map) + }) + .map(|pairs| pairs.into_iter().map(|(_, (k, v))| InputPair::DigestIndex(k, v))) } #[cfg(test)] @@ -227,32 +259,34 @@ mod test { fn build_changes_trie_nodes_on_non_digest_block() { let (backend, storage, changes) = prepare_for_build(); let config = changes.changes_trie_config.as_ref().unwrap(); + let parent = AnchorBlockId { hash: Default::default(), number: 4 }; let changes_trie_nodes = prepare_input( &backend, &storage, config, &changes, - &AnchorBlockId { hash: Default::default(), number: 4 }, + &parent, ).unwrap(); - assert_eq!(changes_trie_nodes, Some(vec![ + assert_eq!(changes_trie_nodes.collect::>>(), vec![ InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 5, key: vec![100] }, vec![0, 2, 3]), InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 5, key: vec![101] }, vec![1]), InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 5, key: vec![103] }, vec![0, 1]), - ])); + ]); } #[test] fn build_changes_trie_nodes_on_digest_block_l1() { let (backend, storage, changes) = prepare_for_build(); let config = changes.changes_trie_config.as_ref().unwrap(); + let parent = AnchorBlockId { hash: Default::default(), number: 3 }; let changes_trie_nodes = prepare_input( &backend, &storage, config, &changes, - &AnchorBlockId { hash: Default::default(), number: 3 }, + &parent, ).unwrap(); - assert_eq!(changes_trie_nodes, Some(vec![ + assert_eq!(changes_trie_nodes.collect::>>(), vec![ InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 4, key: vec![100] }, vec![0, 2, 3]), InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 4, key: vec![101] }, vec![1]), InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 4, key: vec![103] }, vec![0, 1]), @@ -261,21 +295,22 @@ mod test { InputPair::DigestIndex(DigestIndex { block: 4, key: vec![101] }, vec![1]), InputPair::DigestIndex(DigestIndex { block: 4, key: vec![102] }, vec![2]), InputPair::DigestIndex(DigestIndex { block: 4, key: vec![105] }, vec![1, 3]), - ])); + ]); } #[test] fn build_changes_trie_nodes_on_digest_block_l2() { let (backend, storage, changes) = prepare_for_build(); let config = changes.changes_trie_config.as_ref().unwrap(); + let parent = AnchorBlockId { hash: Default::default(), number: 15 }; let changes_trie_nodes = prepare_input( &backend, &storage, config, &changes, - &AnchorBlockId { hash: Default::default(), number: 15 }, + &parent, ).unwrap(); - assert_eq!(changes_trie_nodes, Some(vec![ + assert_eq!(changes_trie_nodes.collect::>>(), vec![ InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 16, key: vec![100] }, vec![0, 2, 3]), InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 16, key: vec![101] }, vec![1]), InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 16, key: vec![103] }, vec![0, 1]), @@ -285,7 +320,7 @@ mod test { InputPair::DigestIndex(DigestIndex { block: 16, key: vec![102] }, vec![4]), InputPair::DigestIndex(DigestIndex { block: 16, key: vec![103] }, vec![4]), InputPair::DigestIndex(DigestIndex { block: 16, key: vec![105] }, vec![4, 8]), - ])); + ]); } #[test] @@ -299,14 +334,15 @@ mod test { }); let config = changes.changes_trie_config.as_ref().unwrap(); + let parent = AnchorBlockId { hash: Default::default(), number: 3 }; let changes_trie_nodes = prepare_input( &backend, &storage, config, &changes, - &AnchorBlockId { hash: Default::default(), number: 3 }, + &parent, ).unwrap(); - assert_eq!(changes_trie_nodes, Some(vec![ + assert_eq!(changes_trie_nodes.collect::>>(), vec![ InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 4, key: vec![100] }, vec![0, 2, 3]), InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 4, key: vec![101] }, vec![1]), InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 4, key: vec![103] }, vec![0, 1]), @@ -315,6 +351,6 @@ mod test { InputPair::DigestIndex(DigestIndex { block: 4, key: vec![101] }, vec![1]), InputPair::DigestIndex(DigestIndex { block: 4, key: vec![102] }, vec![2]), InputPair::DigestIndex(DigestIndex { block: 4, key: vec![105] }, vec![1, 3]), - ])); + ]); } } diff --git a/core/state-machine/src/changes_trie/build_iterator.rs b/core/state-machine/src/changes_trie/build_iterator.rs index 5d8a8318abf849739be1f94290bac006165e7677..f4fff28765667685e1d35b7c06f2aa894c2100d7 100644 --- a/core/state-machine/src/changes_trie/build_iterator.rs +++ b/core/state-machine/src/changes_trie/build_iterator.rs @@ -15,12 +15,13 @@ // along with Substrate. If not, see . //! Structures and functions to return blocks whose changes are to be included -//! in given block' changes trie. +//! in given block's changes trie. use crate::changes_trie::{Configuration, BlockNumber}; /// Returns iterator of OTHER blocks that are required for inclusion into -/// changes trie of given block. +/// changes trie of given block. Blocks are guaranteed to be returned in +/// ascending order. pub fn digest_build_iterator( config: &Configuration, block: Number, @@ -47,6 +48,8 @@ pub struct DigestBuildIterator { max_step: u32, /// Step of current blocks range. current_step: u32, + /// Reverse step of current blocks range. + current_step_reverse: u32, /// Current blocks range. current_range: Option>, } @@ -58,7 +61,8 @@ impl DigestBuildIterator { block, digest_interval, max_step, - current_step: 0, + current_step: max_step, + current_step_reverse: 0, current_range: None, } } @@ -81,18 +85,27 @@ impl Iterator for DigestBuildIterator { // DigestBuildIterator is created only by internal function that is checking // that all multiplications/subtractions are safe within max_step limit - let next_step = if self.current_step == 0 { 1 } else { self.current_step * self.digest_interval }; - if next_step > self.max_step { + let next_step_reverse = if self.current_step_reverse == 0 { + 1 + } else { + self.current_step_reverse * self.digest_interval + }; + if next_step_reverse > self.max_step { return None; } - self.current_step = next_step; + self.current_step_reverse = next_step_reverse; self.current_range = Some(BlocksRange::new( self.block.clone() - (self.current_step * self.digest_interval - self.current_step).into(), self.block.clone(), self.current_step.into(), )); + self.current_step = self.current_step / self.digest_interval; + if self.current_step == 0 { + self.current_step = 1; + } + Some(self.current_range.as_mut() .expect("assigned one line above; qed") .next() @@ -203,18 +216,18 @@ mod tests { fn digest_iterator_returns_level1_and_level2_blocks() { assert_eq!(digest_build_iterator_blocks(16, 2, 256), vec![ - // level2 is a level1 digest of 16-1 previous blocks: - 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, // level2 points to previous 16-1 level1 digests: 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, + // level2 is a level1 digest of 16-1 previous blocks: + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, ], ); assert_eq!(digest_build_iterator_blocks(16, 2, 4096), vec![ - // level2 is a level1 digest of 16-1 previous blocks: - 4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093, 4094, 4095, // level2 points to previous 16-1 level1 digests: 3856, 3872, 3888, 3904, 3920, 3936, 3952, 3968, 3984, 4000, 4016, 4032, 4048, 4064, 4080, + // level2 is a level1 digest of 16-1 previous blocks: + 4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093, 4094, 4095, ], ); } @@ -223,12 +236,12 @@ mod tests { fn digest_iterator_returns_level1_and_level2_and_level3_blocks() { assert_eq!(digest_build_iterator_blocks(16, 3, 4096), vec![ - // level3 is a level1 digest of 16-1 previous blocks: - 4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093, 4094, 4095, - // level3 points to previous 16-1 level1 digests: - 3856, 3872, 3888, 3904, 3920, 3936, 3952, 3968, 3984, 4000, 4016, 4032, 4048, 4064, 4080, // level3 points to previous 16-1 level2 digests: 256, 512, 768, 1024, 1280, 1536, 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584, 3840, + // level3 points to previous 16-1 level1 digests: + 3856, 3872, 3888, 3904, 3920, 3936, 3952, 3968, 3984, 4000, 4016, 4032, 4048, 4064, 4080, + // level3 is a level1 digest of 16-1 previous blocks: + 4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093, 4094, 4095, ], ); } diff --git a/core/state-machine/src/changes_trie/changes_iterator.rs b/core/state-machine/src/changes_trie/changes_iterator.rs index 0e4716ccab98a44028d44aa104ac9cc98ae3b8fb..ee4b9cc19b8f00089dd682d756a1e0b44adfdfb2 100644 --- a/core/state-machine/src/changes_trie/changes_iterator.rs +++ b/core/state-machine/src/changes_trie/changes_iterator.rs @@ -98,7 +98,7 @@ pub fn key_changes_proof, H: Hasher, Number: BlockNumber>( Ok(iter.extract_proof()) } -/// Check key changes proog and return changes of the key at given blocks range. +/// Check key changes proof and return changes of the key at given blocks range. /// `max` is the number of best known block. /// Changes are returned in descending order (i.e. last block comes first). pub fn key_changes_proof_check, H: Hasher, Number: BlockNumber>( diff --git a/core/state-machine/src/changes_trie/mod.rs b/core/state-machine/src/changes_trie/mod.rs index 7dc95fb5a7ba7350e930d93366ceb5cd1d695cfb..ab36eb6423b2e4fd865341be77ee7372c67905da 100644 --- a/core/state-machine/src/changes_trie/mod.rs +++ b/core/state-machine/src/changes_trie/mod.rs @@ -53,7 +53,7 @@ use parity_codec::{Decode, Encode}; use primitives; use crate::changes_trie::build::prepare_input; use crate::overlayed_changes::OverlayedChanges; -use trie::{DBValue, trie_root}; +use trie::{MemoryDB, TrieDBMut, TrieMut, DBValue}; /// Changes that are made outside of extrinsics are marked with this index; pub const NO_EXTRINSIC_INDEX: u32 = 0xffffffff; @@ -128,13 +128,13 @@ pub type Configuration = primitives::ChangesTrieConfiguration; /// Compute the changes trie root and transaction for given block. /// Returns Err(()) if unknown `parent_hash` has been passed. /// Returns Ok(None) if there's no data to perform computation. -/// Panics if background storage returns an error. -pub fn compute_changes_trie_root<'a, B: Backend, S: Storage, H: Hasher, Number: BlockNumber>( +/// Panics if background storage returns an error OR if insert to MemoryDB fails. +pub fn build_changes_trie<'a, B: Backend, S: Storage, H: Hasher, Number: BlockNumber>( backend: &B, storage: Option<&'a S>, changes: &OverlayedChanges, parent_hash: H::Out, -) -> Result, Vec)>)>, ()> +) -> Result, H::Out)>, ()> where H::Out: Ord + 'static, { @@ -148,16 +148,16 @@ pub fn compute_changes_trie_root<'a, B: Backend, S: Storage, H: Ha // storage errors are considered fatal (similar to situations when runtime fetches values from storage) let input_pairs = prepare_input::(backend, storage, config, changes, &parent) - .expect("storage is not allowed to fail within runtime"); - match input_pairs { - Some(input_pairs) => { - let transaction = input_pairs.into_iter() - .map(Into::into) - .collect::>(); - let root = trie_root::(transaction.iter().map(|(k, v)| (&*k, &*v))); - - Ok(Some((root, transaction))) - }, - None => Ok(None), + .expect("changes trie: storage access is not allowed to fail within runtime"); + let mut root = Default::default(); + let mut mdb = MemoryDB::default(); + { + let mut trie = TrieDBMut::::new(&mut mdb, &mut root); + for (key, value) in input_pairs.map(Into::into) { + trie.insert(&key, &value) + .expect("changes trie: insertion to trie is not allowed to fail within runtime"); + } } + + Ok(Some((mdb, root))) } diff --git a/core/state-machine/src/changes_trie/prune.rs b/core/state-machine/src/changes_trie/prune.rs index 3aedf66f757129081c7c2417598ead6219968c96..08e7c02b8c73f1823c050a9293f74ca3d3318857 100644 --- a/core/state-machine/src/changes_trie/prune.rs +++ b/core/state-machine/src/changes_trie/prune.rs @@ -145,7 +145,7 @@ fn pruning_range( /// blocks. So we can only prune blocks that are earlier than B - max_digest_interval. /// The pruning_delay stands for number of max_digest_interval-s that we want to keep: /// 0 or 1: means that only last changes trie is guaranteed to exists; -/// 2: the last chnages trie + previous changes trie +/// 2: the last changes trie + previous changes trie /// ... fn max_digest_intervals_to_keep( min_blocks_to_keep: Number, diff --git a/core/state-machine/src/ext.rs b/core/state-machine/src/ext.rs index 5a0daeb3488b9179345b9c5c09b92bf4e71e1aaa..4ade53a6f1ae39af034b3ec9b566379b098c98bb 100644 --- a/core/state-machine/src/ext.rs +++ b/core/state-machine/src/ext.rs @@ -14,17 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! Conrete externalities implementation. +//! Concrete externalities implementation. use std::{error, fmt, cmp::Ord}; use log::warn; use crate::backend::Backend; -use crate::changes_trie::{Storage as ChangesTrieStorage, compute_changes_trie_root}; +use crate::changes_trie::{Storage as ChangesTrieStorage, build_changes_trie}; use crate::{Externalities, OverlayedChanges, ChildStorageKey}; use hash_db::Hasher; use primitives::offchain; use primitives::storage::well_known_keys::is_child_storage_key; -use trie::{MemoryDB, TrieDBMut, TrieMut, default_child_trie_root}; +use trie::{MemoryDB, default_child_trie_root}; const EXT_NOT_ALLOWED_TO_FAIL: &str = "Externalities not allowed to fail within runtime"; @@ -115,7 +115,7 @@ where } /// Get the transaction necessary to update the backend. - pub fn transaction(mut self) -> (B::Transaction, Option>) { + pub fn transaction(mut self) -> ((B::Transaction, H::Out), Option>) { let _ = self.storage_root(); let (storage_transaction, changes_trie_transaction) = ( @@ -126,7 +126,7 @@ where ); ( - storage_transaction.0, + storage_transaction, changes_trie_transaction, ) } @@ -320,27 +320,13 @@ where fn storage_changes_root(&mut self, parent_hash: H::Out) -> Result, ()> { let _guard = panic_handler::AbortGuard::new(true); - let root_and_tx = compute_changes_trie_root::<_, T, H, N>( + self.changes_trie_transaction = build_changes_trie::<_, T, H, N>( self.backend, self.changes_trie_storage.clone(), self.overlay, parent_hash, )?; - let root_and_tx = root_and_tx.map(|(root, changes)| { - let mut calculated_root = Default::default(); - let mut mdb = MemoryDB::default(); - { - let mut trie = TrieDBMut::::new(&mut mdb, &mut calculated_root); - for (key, value) in changes { - trie.insert(&key, &value).expect(EXT_NOT_ALLOWED_TO_FAIL); - } - } - - (mdb, root) - }); - let root = root_and_tx.as_ref().map(|(_, root)| root.clone()); - self.changes_trie_transaction = root_and_tx; - Ok(root) + Ok(self.changes_trie_transaction.as_ref().map(|(_, root)| root.clone())) } fn offchain(&mut self) -> Option<&mut dyn offchain::Externalities> { diff --git a/core/state-machine/src/lib.rs b/core/state-machine/src/lib.rs index 2c98cc8a30ff09d41e48441142206f01789bcc4d..f151fedaf5132ba8d6a6ff7a357d52a896c0f06b 100644 --- a/core/state-machine/src/lib.rs +++ b/core/state-machine/src/lib.rs @@ -62,7 +62,7 @@ pub use trie_backend::TrieBackend; /// A wrapper around a child storage key. /// -/// This wrapper ensures that the child storage key is correct and properly used. It is +/// This wrapper ensures that the child storage key is correct and properly used. It is /// impossible to create an instance of this struct without providing a correct `storage_key`. pub struct ChildStorageKey<'a, H: Hasher> { storage_key: Cow<'a, [u8]>, @@ -250,6 +250,7 @@ impl offchain::Externalities for NeverOffchainExt { fn encrypt( &mut self, _key: Option, + _kind: offchain::CryptoKind, _data: &[u8], ) -> Result, ()> { unreachable!() @@ -258,18 +259,25 @@ impl offchain::Externalities for NeverOffchainExt { fn decrypt( &mut self, _key: Option, + _kind: offchain::CryptoKind, _data: &[u8], ) -> Result, ()> { unreachable!() } - fn sign(&mut self, _key: Option, _data: &[u8]) -> Result, ()> { + fn sign( + &mut self, + _key: Option, + _kind: offchain::CryptoKind, + _data: &[u8], + ) -> Result, ()> { unreachable!() } fn verify( &mut self, _key: Option, + _kind: offchain::CryptoKind, _msg: &[u8], _signature: &[u8], ) -> Result { @@ -288,15 +296,21 @@ impl offchain::Externalities for NeverOffchainExt { unreachable!() } - fn local_storage_set(&mut self, _key: &[u8], _value: &[u8]) { + fn local_storage_set(&mut self, _kind: offchain::StorageKind, _key: &[u8], _value: &[u8]) { unreachable!() } - fn local_storage_compare_and_set(&mut self, _key: &[u8], _old_value: &[u8], _new_value: &[u8]) { + fn local_storage_compare_and_set( + &mut self, + _kind: offchain::StorageKind, + _key: &[u8], + _old_value: &[u8], + _new_value: &[u8], + ) -> bool { unreachable!() } - fn local_storage_get(&mut self, _key: &[u8]) -> Option> { + fn local_storage_get(&mut self, _kind: offchain::StorageKind, _key: &[u8]) -> Option> { unreachable!() } @@ -502,7 +516,7 @@ impl<'a, H, N, B, T, O, Exec> StateMachine<'a, H, N, B, T, O, Exec> where pub fn execute( &mut self, strategy: ExecutionStrategy, - ) -> Result<(Vec, B::Transaction, Option>), Box> { + ) -> Result<(Vec, (B::Transaction, H::Out), Option>), Box> { // We are not giving a native call and thus we are sure that the result can never be a native // value. self.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( @@ -522,7 +536,12 @@ impl<'a, H, N, B, T, O, Exec> StateMachine<'a, H, N, B, T, O, Exec> where compute_tx: bool, use_native: bool, native_call: Option, - ) -> (CallResult, bool, Option, Option>) where + ) -> ( + CallResult, + bool, + Option<(B::Transaction, H::Out)>, + Option>, + ) where R: Decode + Encode + PartialEq, NC: FnOnce() -> result::Result + UnwindSafe, { @@ -554,7 +573,7 @@ impl<'a, H, N, B, T, O, Exec> StateMachine<'a, H, N, B, T, O, Exec> where mut native_call: Option, orig_prospective: OverlayedChangeSet, on_consensus_failure: Handler, - ) -> (CallResult, Option, Option>) where + ) -> (CallResult, Option<(B::Transaction, H::Out)>, Option>) where R: Decode + Encode + PartialEq, NC: FnOnce() -> result::Result + UnwindSafe, Handler: FnOnce( @@ -585,7 +604,7 @@ impl<'a, H, N, B, T, O, Exec> StateMachine<'a, H, N, B, T, O, Exec> where compute_tx: bool, mut native_call: Option, orig_prospective: OverlayedChangeSet, - ) -> (CallResult, Option, Option>) where + ) -> (CallResult, Option<(B::Transaction, H::Out)>, Option>) where R: Decode + Encode + PartialEq, NC: FnOnce() -> result::Result + UnwindSafe, { @@ -613,7 +632,11 @@ impl<'a, H, N, B, T, O, Exec> StateMachine<'a, H, N, B, T, O, Exec> where manager: ExecutionManager, compute_tx: bool, mut native_call: Option, - ) -> Result<(NativeOrEncoded, Option, Option>), Box> where + ) -> Result<( + NativeOrEncoded, + Option<(B::Transaction, H::Out)>, + Option> + ), Box> where R: Decode + Encode + PartialEq, NC: FnOnce() -> result::Result + UnwindSafe, Handler: FnOnce( diff --git a/core/state-machine/src/overlayed_changes.rs b/core/state-machine/src/overlayed_changes.rs index 7d6d6081bd26bc9e1c211d94a7fd015e975f18a6..c6d7ab89d3b37ea9f05ccb016f01fa7429d31634 100644 --- a/core/state-machine/src/overlayed_changes.rs +++ b/core/state-machine/src/overlayed_changes.rs @@ -17,7 +17,7 @@ //! The overlayed changes to state. #[cfg(test)] use std::iter::FromIterator; -use std::collections::{HashMap, HashSet}; +use std::collections::{HashMap, BTreeSet}; use parity_codec::Decode; use crate::changes_trie::{NO_EXTRINSIC_INDEX, Configuration as ChangesTrieConfig}; use primitives::storage::well_known_keys::EXTRINSIC_INDEX; @@ -45,7 +45,7 @@ pub struct OverlayedValue { pub value: Option>, /// The set of extinsic indices where the values has been changed. /// Is filled only if runtime has announced changes trie support. - pub extrinsics: Option>, + pub extrinsics: Option>, } /// Prospective or committed overlayed change set. @@ -55,7 +55,7 @@ pub struct OverlayedChangeSet { /// Top level storage changes. pub top: HashMap, OverlayedValue>, /// Child storage changes. - pub children: HashMap, (Option>, HashMap, Option>>)>, + pub children: HashMap, (Option>, HashMap, Option>>)>, } #[cfg(test)] diff --git a/core/state-machine/src/testing.rs b/core/state-machine/src/testing.rs index 68b9d28752c28215131c61e1c71f99f457d3dcda..dc19dad7b34bba61d43fc7b14a42f68443d52b0e 100644 --- a/core/state-machine/src/testing.rs +++ b/core/state-machine/src/testing.rs @@ -16,13 +16,13 @@ //! Test implementation for Externalities. -use std::collections::{HashMap, BTreeMap}; +use std::collections::{HashMap}; use std::iter::FromIterator; use hash_db::Hasher; use crate::backend::{InMemory, Backend}; use primitives::storage::well_known_keys::is_child_storage_key; use crate::changes_trie::{ - compute_changes_trie_root, InMemoryStorage as ChangesTrieInMemoryStorage, + build_changes_trie, InMemoryStorage as ChangesTrieInMemoryStorage, BlockNumber as ChangesTrieBlockNumber, }; use primitives::offchain; @@ -32,6 +32,8 @@ use super::{ChildStorageKey, Externalities, OverlayedChanges}; const EXT_NOT_ALLOWED_TO_FAIL: &str = "Externalities not allowed to fail within runtime"; +type StorageTuple = (HashMap, Vec>, HashMap, HashMap, Vec>>); + /// Simple HashMap-based Externalities impl. pub struct TestExternalities { overlay: OverlayedChanges, @@ -41,28 +43,46 @@ pub struct TestExternalities { } impl TestExternalities { - /// Create a new instance of `TestExternalities` - pub fn new(inner: HashMap, Vec>) -> Self { - Self::new_with_code(&[], inner) + /// Create a new instance of `TestExternalities` with storage. + pub fn new(storage: HashMap, Vec>) -> Self { + Self::new_with_children((storage, Default::default())) + } + + /// Create a new instance of `TestExternalities` with storage and children. + pub fn new_with_children(storage: StorageTuple) -> Self { + Self::new_with_code_with_children(&[], storage) + } + + /// Create a new instance of `TestExternalities` with code and storage. + pub fn new_with_code(code: &[u8], storage: HashMap, Vec>) -> Self { + Self::new_with_code_with_children(code, (storage, Default::default())) } - /// Create a new instance of `TestExternalities` - pub fn new_with_code(code: &[u8], mut inner: HashMap, Vec>) -> Self { + /// Create a new instance of `TestExternalities` with code, storage and children. + pub fn new_with_code_with_children(code: &[u8], mut storage: StorageTuple) -> Self { let mut overlay = OverlayedChanges::default(); + assert!(storage.0.keys().all(|key| !is_child_storage_key(key))); + assert!(storage.1.keys().all(|key| is_child_storage_key(key))); + super::set_changes_trie_config( &mut overlay, - inner.get(&CHANGES_TRIE_CONFIG.to_vec()).cloned(), + storage.0.get(&CHANGES_TRIE_CONFIG.to_vec()).cloned(), false, ).expect("changes trie configuration is correct in test env; qed"); - inner.insert(HEAP_PAGES.to_vec(), 8u64.encode()); - inner.insert(CODE.to_vec(), code.to_vec()); + storage.0.insert(HEAP_PAGES.to_vec(), 8u64.encode()); + storage.0.insert(CODE.to_vec(), code.to_vec()); + + let backend: HashMap<_, _> = storage.1.into_iter() + .map(|(keyspace, map)| (Some(keyspace), map)) + .chain(Some((None, storage.0)).into_iter()) + .collect(); TestExternalities { overlay, changes_trie_storage: ChangesTrieInMemoryStorage::new(), - backend: inner.into(), + backend: backend.into(), offchain: None, } } @@ -72,17 +92,6 @@ impl TestExternalities { self.backend = self.backend.update(vec![(None, k, Some(v))]); } - /// Iter to all pairs in key order - pub fn iter_pairs_in_order(&self) -> impl Iterator, Vec)> { - self.backend.pairs().iter() - .map(|&(ref k, ref v)| (k.to_vec(), Some(v.to_vec()))) - .chain(self.overlay.committed.top.clone().into_iter().map(|(k, v)| (k, v.value))) - .chain(self.overlay.prospective.top.clone().into_iter().map(|(k, v)| (k, v.value))) - .collect::>() - .into_iter() - .filter_map(|(k, maybe_val)| maybe_val.map(|val| (k, val))) - } - /// Set offchain externaltiies. pub fn set_offchain_externalities(&mut self, offchain: impl offchain::Externalities + 'static) { self.offchain = Some(Box::new(offchain)); @@ -92,9 +101,26 @@ impl TestExternalities { pub fn changes_trie_storage(&mut self) -> &mut ChangesTrieInMemoryStorage { &mut self.changes_trie_storage } + + /// Return a new backend with all pending value. + pub fn commit_all(&self) -> InMemory { + let top = self.overlay.committed.top.clone().into_iter() + .chain(self.overlay.prospective.top.clone().into_iter()) + .map(|(k, v)| (None, k, v.value)); + + let children = self.overlay.committed.children.clone().into_iter() + .chain(self.overlay.prospective.children.clone().into_iter()) + .flat_map(|(keyspace, map)| { + map.1.into_iter() + .map(|(k, v)| (Some(keyspace.clone()), k, v)) + .collect::>() + }); + + self.backend.update(top.chain(children).collect()) + } } -impl ::std::fmt::Debug for TestExternalities { +impl std::fmt::Debug for TestExternalities { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, "overlay: {:?}\nbackend: {:?}", self.overlay, self.backend.pairs()) } @@ -104,15 +130,13 @@ impl PartialEq for TestExternalities /// This doesn't test if they are in the same state, only if they contains the /// same data at this state fn eq(&self, other: &TestExternalities) -> bool { - self.iter_pairs_in_order().eq(other.iter_pairs_in_order()) + self.commit_all().eq(&other.commit_all()) } } impl FromIterator<(Vec, Vec)> for TestExternalities { fn from_iter, Vec)>>(iter: I) -> Self { - let mut t = Self::new(Default::default()); - t.backend = t.backend.update(iter.into_iter().map(|(k, v)| (None, k, Some(v))).collect()); - t + Self::new(iter.into_iter().collect()) } } @@ -120,15 +144,15 @@ impl Default for TestExternalities { fn default() -> Self { Self::new(Default::default()) } } -impl From> for HashMap, Vec> { - fn from(tex: TestExternalities) -> Self { - tex.iter_pairs_in_order().collect() +impl From, Vec>> for TestExternalities { + fn from(hashmap: HashMap, Vec>) -> Self { + Self::from_iter(hashmap) } } -impl From< HashMap, Vec> > for TestExternalities { - fn from(hashmap: HashMap, Vec>) -> Self { - Self::from_iter(hashmap) +impl From for TestExternalities { + fn from(storage: StorageTuple) -> Self { + Self::new_with_children(storage) } } @@ -226,12 +250,12 @@ impl Externalities for TestExternalities } fn storage_changes_root(&mut self, parent: H::Out) -> Result, ()> { - Ok(compute_changes_trie_root::<_, _, H, N>( + Ok(build_changes_trie::<_, _, H, N>( &self.backend, Some(&self.changes_trie_storage), &self.overlay, parent, - )?.map(|(root, _)| root.clone())) + )?.map(|(_, root)| root)) } fn offchain(&mut self) -> Option<&mut dyn offchain::Externalities> { diff --git a/core/telemetry/Cargo.toml b/core/telemetry/Cargo.toml index 1b19796836abb060f2911b30e4fc9411998254fb..ca95fe94e55a3ddc3ef3fc03fb44425550494471 100644 --- a/core/telemetry/Cargo.toml +++ b/core/telemetry/Cargo.toml @@ -8,8 +8,10 @@ edition = "2018" [dependencies] bytes = "0.4" parking_lot = "0.8.0" -futures = "0.1" -libp2p = { version = "0.9.1", default-features = false, features = ["libp2p-websocket"] } +futures01 = { package = "futures", version = "0.1" } +futures-preview = { version = "0.3.0-alpha.17", features = ["compat"] } +futures-timer = "0.2.1" +libp2p = { version = "0.10.0", default-features = false, features = ["libp2p-websocket"] } log = "0.4" rand = "0.6" serde = { version = "1.0.81", features = ["derive"] } @@ -17,8 +19,4 @@ slog = { version = "^2", features = ["nested-values"] } slog-json = { version = "^2", features = ["nested-values"] } slog-scope = "^4" tokio-io = "0.1" -tokio-timer = "0.2" void = "1.0" - -[dev-dependencies] -tokio = "0.1" diff --git a/core/telemetry/src/lib.rs b/core/telemetry/src/lib.rs index b9d99548510bb62735761421a2fcb5a2ae8ab9a7..88d515e5385d27697c60505ee79f63a89267ed0f 100644 --- a/core/telemetry/src/lib.rs +++ b/core/telemetry/src/lib.rs @@ -48,7 +48,7 @@ //! //! // The `telemetry` object implements `Stream` and must be processed. //! std::thread::spawn(move || { -//! tokio::run(telemetry.for_each(|_| Ok(()))); +//! futures::executor::block_on(telemetry.for_each(|_| future::ready(()))); //! }); //! //! // Sends a message on the telemetry. @@ -58,13 +58,12 @@ //! ``` //! -use futures::{prelude::*, task::AtomicTask}; +use futures::{prelude::*, task::AtomicWaker}; use libp2p::{Multiaddr, wasm_ext}; use log::warn; use parking_lot::Mutex; use serde::{Serialize, Deserialize}; -use std::sync::{Arc, Weak}; -use std::time::{Duration, Instant}; +use std::{pin::Pin, sync::{Arc, Weak}, task::{Context, Poll}, time::{Duration, Instant}}; pub use slog_scope::with_logger; pub use slog; @@ -131,8 +130,8 @@ pub struct Telemetry { struct TelemetryInner { /// Worker for the telemetry. worker: Mutex, - /// Task to wake up when we add a log entry to the worker. - polling_task: AtomicTask, + /// Waker to wake up when we add a log entry to the worker. + polling_waker: AtomicWaker, } /// Implements `slog::Drain`. @@ -156,7 +155,7 @@ pub fn init_telemetry(config: TelemetryConfig) -> Telemetry { let inner = Arc::new(TelemetryInner { worker: Mutex::new(worker::TelemetryWorker::new(endpoints, config.wasm_external_transport)), - polling_task: AtomicTask::new(), + polling_waker: AtomicWaker::new(), }); let guard = { @@ -181,13 +180,12 @@ pub enum TelemetryEvent { impl Stream for Telemetry { type Item = TelemetryEvent; - type Error = (); - fn poll(&mut self) -> Poll, Self::Error> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { let before = Instant::now(); let mut has_connected = false; - while let Async::Ready(event) = self.inner.worker.lock().poll() { + while let Poll::Ready(event) = self.inner.worker.lock().poll(cx) { // Right now we only have one possible event. This line is here in order to not // forget to handle any possible new event type. let worker::TelemetryWorkerEvent::Connected = event; @@ -199,10 +197,10 @@ impl Stream for Telemetry { } if has_connected { - Ok(Async::Ready(Some(TelemetryEvent::Connected))) + Poll::Ready(Some(TelemetryEvent::Connected)) } else { - self.inner.polling_task.register(); - Ok(Async::NotReady) + self.inner.polling_waker.register(cx.waker()); + Poll::Pending } } } @@ -215,7 +213,7 @@ impl slog::Drain for TelemetryDrain { if let Some(inner) = self.inner.0.upgrade() { let before = Instant::now(); let result = inner.worker.lock().log(record, values); - inner.polling_task.notify(); + inner.polling_waker.wake(); if before.elapsed() > Duration::from_millis(50) { warn!(target: "telemetry", "Writing a telemetry log took more than 50ms"); } diff --git a/core/telemetry/src/worker.rs b/core/telemetry/src/worker.rs index 87a3deb6ef9605793893ede5f9f5ddea8c4e279e..e13270937899c69bc610fb949ca67986ef20cb85 100644 --- a/core/telemetry/src/worker.rs +++ b/core/telemetry/src/worker.rs @@ -27,12 +27,11 @@ //! use bytes::BytesMut; -use futures::prelude::*; +use futures::compat::Compat01As03Sink; use libp2p::{core::transport::OptionalTransport, core::ConnectedPoint, Multiaddr, Transport, wasm_ext}; use log::{trace, warn, error}; use slog::Drain; -use std::{io, time}; -use tokio_io::AsyncWrite; +use std::{io, pin::Pin, task::Context, task::Poll, time}; mod node; @@ -58,19 +57,29 @@ pub struct TelemetryWorker { /// The pile of libp2p transports. #[cfg(not(target_os = "unknown"))] type WsTrans = libp2p::core::transport::timeout::TransportTimeout< - libp2p::core::transport::OrTransport< - libp2p::core::transport::map::Map< - OptionalTransport, - fn(wasm_ext::Connection, ConnectedPoint) -> StreamSink + libp2p::core::transport::map::Map< + libp2p::core::transport::OrTransport< + libp2p::core::transport::map::Map< + OptionalTransport, + fn(wasm_ext::Connection, ConnectedPoint) -> StreamSink + >, + libp2p::websocket::framed::WsConfig> >, - libp2p::websocket::framed::WsConfig> + fn(libp2p::core::either::EitherOutput, + libp2p::websocket::framed::BytesConnection>, ConnectedPoint) + -> Compat01As03Sink, + libp2p::websocket::framed::BytesConnection>, BytesMut> > >; #[cfg(target_os = "unknown")] type WsTrans = libp2p::core::transport::timeout::TransportTimeout< libp2p::core::transport::map::Map< - OptionalTransport, - fn(wasm_ext::Connection, ConnectedPoint) -> StreamSink + libp2p::core::transport::map::Map< + OptionalTransport, + fn(wasm_ext::Connection, ConnectedPoint) -> StreamSink + >, + fn(StreamSink, ConnectedPoint) + -> Compat01As03Sink, BytesMut> > >; @@ -98,7 +107,9 @@ impl TelemetryWorker { libp2p::websocket::framed::WsConfig::new(inner) }); - let transport = transport.with_timeout(CONNECT_TIMEOUT); + let transport = transport + .map((|inner, _| Compat01As03Sink::new(inner)) as fn(_, _) -> _) + .with_timeout(CONNECT_TIMEOUT); TelemetryWorker { nodes: endpoints.into_iter().map(|(addr, verbosity)| { @@ -109,19 +120,19 @@ impl TelemetryWorker { } /// Polls the worker for events that happened. - pub fn poll(&mut self) -> Async { + pub fn poll(&mut self, cx: &mut Context) -> Poll { for (node, _) in &mut self.nodes { loop { - match node.poll() { - Async::Ready(node::NodeEvent::Connected) => - return Async::Ready(TelemetryWorkerEvent::Connected), - Async::Ready(node::NodeEvent::Disconnected(_)) => continue, - Async::NotReady => break, + match node::Node::poll(Pin::new(node), cx) { + Poll::Ready(node::NodeEvent::Connected) => + return Poll::Ready(TelemetryWorkerEvent::Connected), + Poll::Ready(node::NodeEvent::Disconnected(_)) => continue, + Poll::Pending => break, } } } - Async::NotReady + Poll::Pending } /// Equivalent to `slog::Drain::log`, but takes `self` by `&mut` instead, which is more convenient. @@ -132,7 +143,7 @@ impl TelemetryWorker { let msg_verbosity = match record.tag().parse::() { Ok(v) => v, Err(err) => { - warn!(target: "telemetry", "Failed to parse telemetry tag {:?}: {:?}", + warn!(target: "telemetry", "Failed to parse telemetry tag {:?}: {:?}", record.tag(), err); return Err(()) } @@ -176,27 +187,29 @@ impl TelemetryWorker { /// For some context, we put this object around the `wasm_ext::ExtTransport` in order to make sure /// that each telemetry message maps to one single call to `write` in the WASM FFI. struct StreamSink(T); -impl Sink for StreamSink { +impl futures01::Sink for StreamSink { type SinkItem = BytesMut; type SinkError = io::Error; - fn start_send(&mut self, item: Self::SinkItem) -> Result, io::Error> { + fn start_send(&mut self, item: Self::SinkItem) + -> Result, io::Error> { match self.0.write(&item[..]) { - Ok(n) if n == item.len() => Ok(AsyncSink::Ready), + Ok(n) if n == item.len() => Ok(futures01::AsyncSink::Ready), Ok(_) => { error!(target: "telemetry", "Detected some internal buffering happening in the telemetry"); Err(io::Error::new(io::ErrorKind::Other, "Internal buffering detected")) }, - Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => Ok(AsyncSink::NotReady(item)), + Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => + Ok(futures01::AsyncSink::NotReady(item)), Err(err) => Err(err), } } - fn poll_complete(&mut self) -> Poll<(), io::Error> { + fn poll_complete(&mut self) -> futures01::Poll<(), io::Error> { match self.0.flush() { - Ok(()) => Ok(Async::Ready(())), - Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => Ok(Async::NotReady), + Ok(()) => Ok(futures01::Async::Ready(())), + Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => Ok(futures01::Async::NotReady), Err(err) => Err(err), } } diff --git a/core/telemetry/src/worker/node.rs b/core/telemetry/src/worker/node.rs index a4d8f8d84e2cb22f0db900625e4fa4bf58af1fea..fc09e90c7db54a4cab6d4e7864b20747a893df4d 100644 --- a/core/telemetry/src/worker/node.rs +++ b/core/telemetry/src/worker/node.rs @@ -17,13 +17,13 @@ //! Contains the `Node` struct, which handles communications with a single telemetry endpoint. use bytes::BytesMut; -use futures::prelude::*; +use futures::{prelude::*, compat::{Future01CompatExt as _, Compat01As03}}; +use futures_timer::Delay; use libp2p::Multiaddr; use libp2p::core::transport::Transport; use log::{trace, debug, warn, error}; use rand::Rng as _; -use std::{collections::VecDeque, fmt, mem, time::Duration, time::Instant}; -use tokio_timer::Delay; +use std::{collections::VecDeque, fmt, mem, pin::Pin, task::Context, task::Poll, time::Duration}; /// Maximum number of pending telemetry messages. const MAX_PENDING: usize = 10; @@ -42,7 +42,7 @@ enum NodeSocket { /// We're connected to the node. This is the normal state. Connected(NodeSocketConnected), /// We are currently dialing the node. - Dialing(TTrans::Dial), + Dialing(Compat01As03), /// A new connection should be started as soon as possible. ReconnectNow, /// Waiting before attempting to dial again. @@ -86,8 +86,8 @@ impl Node { } impl Node -where TTrans: Clone, TTrans::Output: Sink, - TSinkErr: fmt::Debug { +where TTrans: Clone + Unpin, TTrans::Dial: Unpin, + TTrans::Output: Sink + Unpin, TSinkErr: fmt::Debug { /// Sends a WebSocket frame to the node. Returns an error if we are not connected to the node. /// /// After calling this method, you should call `poll` in order for it to be properly processed. @@ -108,29 +108,30 @@ where TTrans: Clone, TTrans::Output: Sink Async> { + pub fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { let mut socket = mem::replace(&mut self.socket, NodeSocket::Poisoned); self.socket = loop { match socket { - NodeSocket::Connected(mut conn) => match conn.poll(&self.addr) { - Ok(Async::Ready(v)) => void::unreachable(v), - Ok(Async::NotReady) => break NodeSocket::Connected(conn), - Err(err) => { - debug!(target: "telemetry", "Disconnected from {}: {:?}", self.addr, err); - let timeout = gen_rand_reconnect_delay(); - self.socket = NodeSocket::WaitingReconnect(timeout); - return Async::Ready(NodeEvent::Disconnected(err)) + NodeSocket::Connected(mut conn) => + match NodeSocketConnected::poll(Pin::new(&mut conn), cx, &self.addr) { + Poll::Ready(Ok(v)) => match v {} + Poll::Pending => break NodeSocket::Connected(conn), + Poll::Ready(Err(err)) => { + debug!(target: "telemetry", "Disconnected from {}: {:?}", self.addr, err); + let timeout = gen_rand_reconnect_delay(); + self.socket = NodeSocket::WaitingReconnect(timeout); + return Poll::Ready(NodeEvent::Disconnected(err)) + } } - } - NodeSocket::Dialing(mut s) => match s.poll() { - Ok(Async::Ready(sink)) => { + NodeSocket::Dialing(mut s) => match Future::poll(Pin::new(&mut s), cx) { + Poll::Ready(Ok(sink)) => { debug!(target: "telemetry", "Connected to {}", self.addr); let conn = NodeSocketConnected { sink, pending: VecDeque::new(), need_flush: false }; self.socket = NodeSocket::Connected(conn); - return Async::Ready(NodeEvent::Connected) + return Poll::Ready(NodeEvent::Connected) }, - Ok(Async::NotReady) => break NodeSocket::Dialing(s), - Err(err) => { + Poll::Pending => break NodeSocket::Dialing(s), + Poll::Ready(Err(err)) => { debug!(target: "telemetry", "Error while dialing {}: {:?}", self.addr, err); let timeout = gen_rand_reconnect_delay(); socket = NodeSocket::WaitingReconnect(timeout); @@ -139,7 +140,7 @@ where TTrans: Clone, TTrans::Output: Sink match self.transport.clone().dial(self.addr.clone()) { Ok(d) => { debug!(target: "telemetry", "Started dialing {}", self.addr); - socket = NodeSocket::Dialing(d); + socket = NodeSocket::Dialing(d.compat()); } Err(err) => { debug!(target: "telemetry", "Error while dialing {}: {:?}", self.addr, err); @@ -147,11 +148,12 @@ where TTrans: Clone, TTrans::Output: Sink if let Ok(Async::Ready(_)) = s.poll() { - socket = NodeSocket::ReconnectNow; - } else { - break NodeSocket::WaitingReconnect(s) - } + NodeSocket::WaitingReconnect(mut s) => + if let Poll::Ready(_) = Future::poll(Pin::new(&mut s), cx) { + socket = NodeSocket::ReconnectNow; + } else { + break NodeSocket::WaitingReconnect(s) + } NodeSocket::Poisoned => { error!(target: "telemetry", "Poisoned connection with {}", self.addr); break NodeSocket::Poisoned @@ -159,7 +161,7 @@ where TTrans: Clone, TTrans::Output: Sink Delay { let random_delay = rand::thread_rng().gen_range(5, 10); - Delay::new(Instant::now() + Duration::from_secs(random_delay)) + Delay::new(Duration::from_secs(random_delay)) } impl NodeSocketConnected -where TTrans::Output: Sink { +where TTrans::Output: Sink + Unpin { /// Processes the queue of messages for the connected socket. /// /// The address is passed for logging purposes only. - fn poll(&mut self, my_addr: &Multiaddr) -> Poll { + fn poll( + mut self: Pin<&mut Self>, + cx: &mut Context, + my_addr: &Multiaddr + ) -> Poll> { loop { if let Some(item) = self.pending.pop_front() { - let item_len = item.len(); - if let AsyncSink::NotReady(item) = self.sink.start_send(item)? { + if let Poll::Pending = Sink::poll_ready(Pin::new(&mut self.sink), cx) { self.pending.push_front(item); - break - } else { - trace!(target: "telemetry", "Successfully sent {:?} bytes message to {}", - item_len, my_addr); - self.need_flush = true; + return Poll::Pending } - } else if self.need_flush && self.sink.poll_complete()?.is_ready() { - self.need_flush = false; + let item_len = item.len(); + if let Err(err) = Sink::start_send(Pin::new(&mut self.sink), item) { + return Poll::Ready(Err(err)) + } + trace!( + target: "telemetry", "Successfully sent {:?} bytes message to {}", + item_len, my_addr + ); + self.need_flush = true; + } else if self.need_flush { + match Sink::poll_flush(Pin::new(&mut self.sink), cx) { + Poll::Pending => {} + Poll::Ready(Err(err)) => return Poll::Ready(Err(err)), + Poll::Ready(Ok(())) => self.need_flush = false, + } } else { break } } - Ok(Async::NotReady) + Poll::Pending } } diff --git a/core/test-client/Cargo.toml b/core/test-client/Cargo.toml index 0bb8367c146dc4df6cedd3c62e311e3f75a1055e..0d709fab68305b2e4209bf7e8712fc7f2bad19ac 100644 --- a/core/test-client/Cargo.toml +++ b/core/test-client/Cargo.toml @@ -9,10 +9,10 @@ client = { package = "substrate-client", path = "../client" } client-db = { package = "substrate-client-db", path = "../client/db", features = ["test-helpers"] } consensus = { package = "substrate-consensus-common", path = "../consensus/common" } executor = { package = "substrate-executor", path = "../executor" } -futures = { version = "0.1.27" } -hash-db = "0.12" +futures-preview = "0.3.0-alpha.17" +hash-db = "0.14.0" keyring = { package = "substrate-keyring", path = "../keyring" } -parity-codec = "3.5.1" +parity-codec = "4.1.1" primitives = { package = "substrate-primitives", path = "../primitives" } runtime_primitives = { package = "sr-primitives", path = "../sr-primitives" } state_machine = { package = "substrate-state-machine", path = "../state-machine" } diff --git a/core/test-client/src/client_ext.rs b/core/test-client/src/client_ext.rs index 7d05b1f570da9600eedb5360d21de9b1418f8d0d..5f677108c359d2000fcb3a348ee95b8fac49bf51 100644 --- a/core/test-client/src/client_ext.rs +++ b/core/test-client/src/client_ext.rs @@ -57,7 +57,7 @@ impl ClientExt for Client where B: client::backend::Backend, E: client::CallExecutor, - Self: BlockImport, + for<'r> &'r Self: BlockImport, Block: BlockT::Out>, { fn import(&self, origin: BlockOrigin, block: Block) @@ -75,7 +75,7 @@ impl ClientExt for Client fork_choice: ForkChoiceStrategy::LongestChain, }; - self.import_block(import, HashMap::new()).map(|_| ()) + BlockImport::import_block(&mut (&*self), import, HashMap::new()).map(|_| ()) } fn import_justified( @@ -96,7 +96,7 @@ impl ClientExt for Client fork_choice: ForkChoiceStrategy::LongestChain, }; - self.import_block(import, HashMap::new()).map(|_| ()) + BlockImport::import_block(&mut (&*self), import, HashMap::new()).map(|_| ()) } fn finalize_block( diff --git a/core/test-client/src/lib.rs b/core/test-client/src/lib.rs index 40fbd10d9e43870d50fbd463da7b9709b3a314ed..509863e4e56ae544463a50af457e955d98580c38 100644 --- a/core/test-client/src/lib.rs +++ b/core/test-client/src/lib.rs @@ -32,7 +32,7 @@ pub use state_machine::ExecutionStrategy; use std::sync::Arc; use std::collections::HashMap; -use futures::future::FutureResult; +use futures::future::Ready; use hash_db::Hasher; use primitives::storage::well_known_keys; use runtime_primitives::traits::{ @@ -220,11 +220,11 @@ impl TestClientBuilder< } impl client::light::fetcher::Fetcher for LightFetcher { - type RemoteHeaderResult = FutureResult; - type RemoteReadResult = FutureResult>, client::error::Error>; - type RemoteCallResult = FutureResult, client::error::Error>; - type RemoteChangesResult = FutureResult, u32)>, client::error::Error>; - type RemoteBodyResult = FutureResult, client::error::Error>; + type RemoteHeaderResult = Ready>; + type RemoteReadResult = Ready>, client::error::Error>>; + type RemoteCallResult = Ready, client::error::Error>>; + type RemoteChangesResult = Ready, u32)>, client::error::Error>>; + type RemoteBodyResult = Ready, client::error::Error>>; fn remote_header( &self, diff --git a/core/test-runtime/Cargo.toml b/core/test-runtime/Cargo.toml index 64725177fc970f3ef06290c0a3247346fd3982de..d14d324006cbbc218874f170d50b247603374c92 100644 --- a/core/test-runtime/Cargo.toml +++ b/core/test-runtime/Cargo.toml @@ -3,11 +3,12 @@ name = "substrate-test-runtime" version = "2.0.0" authors = ["Parity Technologies "] edition = "2018" +build = "build.rs" [dependencies] log = { version = "0.4", optional = true } serde = { version = "1.0", optional = true, features = ["derive"] } -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } keyring = { package = "substrate-keyring", path = "../keyring", optional = true } substrate-client = { path = "../client", default-features = false } primitives = { package = "substrate-primitives", path = "../primitives", default-features = false } @@ -20,8 +21,7 @@ runtime_primitives = { package = "sr-primitives", path = "../sr-primitives", def runtime_version = { package = "sr-version", path = "../sr-version", default-features = false } runtime_support = { package = "srml-support", path = "../../srml/support", default-features = false } substrate-trie = { path = "../trie", default-features = false } -trie-db = { version = "0.12", default-features = false } -memory-db = { version = "0.12", default-features = false } +trie-db = { version = "0.14.0", default-features = false } offchain-primitives = { package = "substrate-offchain-primitives", path = "../offchain/primitives", default-features = false} executive = { package = "srml-executive", path = "../../srml/executive", default-features = false } cfg-if = "0.1.6" @@ -30,11 +30,14 @@ cfg-if = "0.1.6" substrate-executor = { path = "../executor" } substrate-test-runtime-client = { path = "./client" } +[build-dependencies] +wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.2", path = "../utils/wasm-builder-runner" } + [features] default = [ "std", - "include-wasm-blob" ] +no_std = [] std = [ "log", "serde", @@ -53,9 +56,6 @@ std = [ "primitives/std", "substrate-trie/std", "trie-db/std", - "memory-db/std", "offchain-primitives/std", "executive/std", ] -# If enabled, the WASM blob is added to the `GenesisConfig`. -include-wasm-blob = [] diff --git a/node/runtime/wasm/src/lib.rs b/core/test-runtime/build.rs similarity index 70% rename from node/runtime/wasm/src/lib.rs rename to core/test-runtime/build.rs index a87b3f7c79dbd94a34a14537822b8c94fc67fab7..f543f68ccd72fd30254e678804e9a897c5a81b5e 100644 --- a/node/runtime/wasm/src/lib.rs +++ b/core/test-runtime/build.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2019 Parity Technologies (UK) Ltd. +// Copyright 2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -14,8 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! The Substrate runtime reexported for WebAssembly compile. +use wasm_builder_runner::{build_current_project, WasmBuilderSource}; -#![cfg_attr(not(feature = "std"), no_std)] - -pub use node_runtime::*; +fn main() { + build_current_project( + "wasm_binary.rs", + WasmBuilderSource::CratesOrPath { + path: "../utils/wasm-builder", + version: "1.0.4", + }, + ); +} diff --git a/core/test-runtime/client/Cargo.toml b/core/test-runtime/client/Cargo.toml index 9ddeb7ba2508b627132bdbc2b906f525296f4192..4905678ae9c30953f5f304313a3aba5953012f14 100644 --- a/core/test-runtime/client/Cargo.toml +++ b/core/test-runtime/client/Cargo.toml @@ -13,7 +13,6 @@ runtime_primitives = { package = "sr-primitives", path = "../../sr-primitives" } [features] default = [ "std", - "runtime/include-wasm-blob", ] std = [ "runtime/std", diff --git a/core/test-runtime/client/src/lib.rs b/core/test-runtime/client/src/lib.rs index ee1ad2421472695855215810fc717692afa286f8..104ffac820c50389b8cd08db7ff00b2e032f9651 100644 --- a/core/test-runtime/client/src/lib.rs +++ b/core/test-runtime/client/src/lib.rs @@ -51,7 +51,7 @@ mod local_executor { pub LocalExecutor, runtime::api::dispatch, runtime::native_version, - include_bytes!("../../wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm") + runtime::WASM_BINARY ); } diff --git a/core/test-runtime/src/genesismap.rs b/core/test-runtime/src/genesismap.rs index f14ddf6989e6701e280607b85662a632f5379ef2..21d7aae0a1a064a0ea5cf4b135ecf413f645e815 100644 --- a/core/test-runtime/src/genesismap.rs +++ b/core/test-runtime/src/genesismap.rs @@ -18,7 +18,7 @@ use std::collections::HashMap; use runtime_io::{blake2_256, twox_128}; -use super::{AuthorityId, AccountId}; +use super::{AuthorityId, AccountId, WASM_BINARY}; use parity_codec::{Encode, KeyedVec, Joiner}; use primitives::{ChangesTrieConfiguration, map, storage::well_known_keys}; use runtime_primitives::traits::Block; @@ -48,13 +48,11 @@ impl GenesisConfig { } pub fn genesis_map(&self) -> HashMap, Vec> { - #[cfg(feature = "include-wasm-blob")] - let wasm_runtime = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm").to_vec(); + let wasm_runtime = WASM_BINARY.to_vec(); let mut map: HashMap, Vec> = self.balances.iter() .map(|&(ref account, balance)| (account.to_keyed_vec(b"balance:"), vec![].and(&balance))) .map(|(k, v)| (blake2_256(&k[..])[..].to_vec(), v.to_vec())) .chain(vec![ - #[cfg(feature = "include-wasm-blob")] (well_known_keys::CODE.into(), wasm_runtime), (well_known_keys::HEAP_PAGES.into(), vec![].and(&(16 as u64))), ].into_iter()) diff --git a/core/test-runtime/src/lib.rs b/core/test-runtime/src/lib.rs index 7a68439a07b61d5d8734a4f77b383a848d7b5381..b72d2af62a9ac42b8ea690be157122ee7399b44f 100644 --- a/core/test-runtime/src/lib.rs +++ b/core/test-runtime/src/lib.rs @@ -56,6 +56,10 @@ pub type AuraId = AuthorityId; // Ensure Babe and Aura use the same crypto to simplify things a bit. pub type BabeId = AuthorityId; +// Inlucde the WASM binary +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + /// Test runtime version. pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("test"), @@ -470,6 +474,7 @@ cfg_if! { slot_duration: 1, expected_block_time: 1, threshold: std::u64::MAX, + median_required_blocks: 100, } } fn authorities() -> Vec { system::authorities() } @@ -611,6 +616,7 @@ cfg_if! { impl consensus_babe::BabeApi for Runtime { fn startup_data() -> consensus_babe::BabeConfiguration { consensus_babe::BabeConfiguration { + median_required_blocks: 0, slot_duration: 1, expected_block_time: 1, threshold: core::u64::MAX, diff --git a/core/test-runtime/src/system.rs b/core/test-runtime/src/system.rs index 267d322e87b136abbd94b882e234dc6e34d4849d..f4433e391c7df8812ede37fd59a0c14e1c4ff2a4 100644 --- a/core/test-runtime/src/system.rs +++ b/core/test-runtime/src/system.rs @@ -110,6 +110,8 @@ fn execute_block_with_state_root_handler( storage::unhashed::kill(well_known_keys::EXTRINSIC_INDEX); }); + let o_new_authorities = ::take(); + if let Mode::Overwrite = mode { header.state_root = storage_root().into(); } else { @@ -124,7 +126,7 @@ fn execute_block_with_state_root_handler( if let Some(storage_changes_root) = storage_changes_root(header.parent_hash.into()) { digest.push(generic::DigestItem::ChangesTrieRoot(storage_changes_root.into())); } - if let Some(new_authorities) = ::take() { + if let Some(new_authorities) = o_new_authorities { digest.push(generic::DigestItem::Consensus(*b"aura", new_authorities.encode())); digest.push(generic::DigestItem::Consensus(*b"babe", new_authorities.encode())); } @@ -203,6 +205,7 @@ pub fn finalize_block() -> Header { let parent_hash = ::take(); let mut digest = ::take().expect("StorageDigest is set by `initialize_block`"); + let o_new_authorities = ::take(); // This MUST come after all changes to storage are done. Otherwise we will fail the // “Storage root does not match that calculated” assertion. let storage_root = BlakeTwo256::storage_root(); @@ -211,7 +214,8 @@ pub fn finalize_block() -> Header { if let Some(storage_changes_root) = storage_changes_root { digest.push(generic::DigestItem::ChangesTrieRoot(storage_changes_root)); } - if let Some(new_authorities) = ::take() { + + if let Some(new_authorities) = o_new_authorities { digest.push(generic::DigestItem::Consensus(*b"aura", new_authorities.encode())); digest.push(generic::DigestItem::Consensus(*b"babe", new_authorities.encode())); } @@ -309,13 +313,10 @@ mod tests { use runtime_io::{with_externalities, TestExternalities}; use substrate_test_runtime_client::{AuthorityKeyring, AccountKeyring}; - use crate::{Header, Transfer}; + use crate::{Header, Transfer, WASM_BINARY}; use primitives::{Blake2Hasher, map}; use substrate_executor::WasmExecutor; - const WASM_CODE: &'static [u8] = - include_bytes!("../wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm"); - fn new_test_ext() -> TestExternalities { let authorities = vec![ AuthorityKeyring::Alice.to_raw_public(), @@ -361,7 +362,7 @@ mod tests { #[test] fn block_import_works_wasm() { block_import_works(|b, ext| { - WasmExecutor::new().call(ext, 8, &WASM_CODE, "Core_execute_block", &b.encode()).unwrap(); + WasmExecutor::new().call(ext, 8, &WASM_BINARY, "Core_execute_block", &b.encode()).unwrap(); }) } @@ -449,7 +450,7 @@ mod tests { #[test] fn block_import_with_transaction_works_wasm() { block_import_with_transaction_works(|b, ext| { - WasmExecutor::new().call(ext, 8, &WASM_CODE, "Core_execute_block", &b.encode()).unwrap(); + WasmExecutor::new().call(ext, 8, &WASM_BINARY, "Core_execute_block", &b.encode()).unwrap(); }) } } diff --git a/core/test-runtime/wasm/Cargo.lock b/core/test-runtime/wasm/Cargo.lock deleted file mode 100644 index 833c31c3e429dffb2843f066b0a1c5d4d502bc8d..0000000000000000000000000000000000000000 --- a/core/test-runtime/wasm/Cargo.lock +++ /dev/null @@ -1,3740 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "adler32" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "aes-ctr" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aes-soft" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aesni" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aho-corasick" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aio-limited" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "arrayref" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "arrayvec" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "asn1_der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "asn1_der_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "asn1_der_derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "atty" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "autocfg" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "backtrace" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "backtrace-sys" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "base58" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "base64" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bigint" -version = "4.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bitflags" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitmask" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "blake2" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "blake2-rfc" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "block-buffer" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "block-cipher-trait" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "block-padding" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bs58" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "build_const" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bumpalo" -version = "2.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byte-tools" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byteorder" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byteorder" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bytes" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "c_linked_list" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cc" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cfg-if" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "chrono" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "clear_on_drop" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "constant_time_eq" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "crc" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crc32fast" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-channel" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-deque" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-deque" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-deque" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-queue" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-utils" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-utils" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crunchy" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "crypto-mac" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crypto-mac" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ctr" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cuckoofilter" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "curve25519-dalek" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "data-encoding" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "derive_more" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "digest" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "digest" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "dns-parser" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ed25519-dalek" -version = "1.0.0-pre.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "curve25519-dalek 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "either" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "elastic-array" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "env_logger" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "environmental" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "erased-serde" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "failure" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "failure_derive" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fixed-hash" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "flate2" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fnv" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "futures" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "futures-cpupool" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "gcc" -version = "0.3.55" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "generic-array" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "generic-array" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "get_if_addrs" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "c_linked_list 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "get_if_addrs-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "get_if_addrs-sys" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hash-db" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "hash256-std-hasher" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hashbrown" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hashmap_core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "heapsize" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "heck" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hex" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "hex-literal" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "hex-literal-impl 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hex-literal-impl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hmac" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crypto-mac 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hmac" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hmac-drbg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "http" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "httparse" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "humantime" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "idna" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "impl-codec" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "impl-serde" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "impl-serde" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "integer-sqrt" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "iovec" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ipnet" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "itoa" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "js-sys" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "keccak" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kvdb" -version = "0.1.0" -source = "git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d#b0317f649ab2c665b7987b8475878fc4d2e1f81d" -dependencies = [ - "elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)", -] - -[[package]] -name = "lazy_static" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.55" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libp2p" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core-derive 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-deflate 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-dns 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-floodsub 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-identify 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-kad 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-mdns 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-mplex 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-noise 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-ping 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-plaintext 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-ratelimit 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-secio 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-tcp 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-uds 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-wasm-ext 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-websocket 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-yamux 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multihash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-core" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "asn1_der 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "multistream-select 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multihash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rw-stream-sink 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-core-derive" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-deflate" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-dns" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-dns-unofficial 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-floodsub" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "cuckoofilter 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-identify" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-kad" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multihash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-mdns" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "dns-parser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-mplex" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-noise" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "curve25519-dalek 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "snow 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "x25519-dalek 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-ping" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-plaintext" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-ratelimit" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aio-limited 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-secio" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "asn1_der 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rw-stream-sink 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "twofish 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-futures 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-tcp" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "get_if_addrs 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ipnet 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tk-listen 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-uds" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-wasm-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-futures 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-websocket" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rw-stream-sink 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "soketto 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-rustls 0.10.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki-roots 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-yamux" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "yamux 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libsecp256k1" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac-drbg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lock_api" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lock_api" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "log" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "matches" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "memchr" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "memoffset" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "memory-db" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hashmap_core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "memory_units" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "merlin" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miniz-sys" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miniz_oxide" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miniz_oxide_c_api" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mio" -version = "0.6.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mio-uds" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miow" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (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 = "multistream-select" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "net2" -version = "0.2.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "nodrop" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "nohash-hasher" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "nom" -version = "4.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-integer" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-traits" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num_cpus" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "numtoa" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "once_cell" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "opaque-debug" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "owning_ref" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "owning_ref" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-bytes" -version = "0.1.0" -source = "git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d#b0317f649ab2c665b7987b8475878fc4d2e1f81d" - -[[package]] -name = "parity-codec" -version = "3.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-codec-derive" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-multiaddr" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multihash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-multihash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "blake2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-send-wrapper" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "parity-wasm" -version = "0.31.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot_core" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot_core" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "paste" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "paste-impl" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-hack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "pbkdf2" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "percent-encoding" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "primitive-types" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fixed-hash 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-codec 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "uint 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro-crate" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro-hack" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro-hack-impl" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "protobuf" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quick-error" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quick-error" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quote" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rayon" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rayon-core" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "redox_syscall" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_termios" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex-syntax" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ring" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rustc-hex" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustls" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "sct 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rw-stream-sink" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ryu" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "safe-mix" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "schnorrkel" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "curve25519-dalek 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "merlin 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "scopeguard" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "scopeguard" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "sct" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "send_wrapper" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "serde" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_derive" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_json" -version = "1.0.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sha-1" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sha1" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "sha2" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sha2" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sha3" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "slab" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "slog" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "slog-json" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "slog-scope" -version = "4.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "smallvec" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "snow" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "static_slice 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "soketto" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sourcefile" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "spin" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "sr-api-macros" -version = "2.0.0" -dependencies = [ - "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sr-io" -version = "2.0.0" -dependencies = [ - "environmental 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-std 2.0.0", - "substrate-primitives 2.0.0", - "substrate-state-machine 2.0.0", - "substrate-trie 2.0.0", - "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sr-primitives" -version = "2.0.0" -dependencies = [ - "integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-std 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "sr-std" -version = "2.0.0" -dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sr-version" -version = "2.0.0" -dependencies = [ - "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", -] - -[[package]] -name = "srml-executive" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", -] - -[[package]] -name = "srml-metadata" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-std 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "srml-support" -version = "2.0.0" -dependencies = [ - "bitmask 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-metadata 2.0.0", - "srml-support-procedural 2.0.0", - "substrate-inherents 2.0.0", -] - -[[package]] -name = "srml-support-procedural" -version = "2.0.0" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-api-macros 2.0.0", - "srml-support-procedural-tools 2.0.0", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "srml-support-procedural-tools" -version = "2.0.0" -dependencies = [ - "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "srml-support-procedural-tools-derive 2.0.0", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "srml-support-procedural-tools-derive" -version = "2.0.0" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "srml-system" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-support 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "stable_deref_trait" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "static_assertions" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "static_slice" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "stream-cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "strum" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "strum_macros" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-bip39" -version = "0.2.1" -source = "git+https://github.com/paritytech/substrate-bip39#44307fda4ea17fe97aeb93af317fbc8f6ed34193" -dependencies = [ - "hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-client" -version = "2.0.0" -dependencies = [ - "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "kvdb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-api-macros 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "sr-version 2.0.0", - "substrate-consensus-common 2.0.0", - "substrate-executor 2.0.0", - "substrate-inherents 2.0.0", - "substrate-keyring 2.0.0", - "substrate-primitives 2.0.0", - "substrate-state-machine 2.0.0", - "substrate-telemetry 2.0.0", - "substrate-trie 2.0.0", -] - -[[package]] -name = "substrate-consensus-aura-primitives" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "substrate-client 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "substrate-consensus-babe-primitives" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "substrate-client 2.0.0", - "substrate-consensus-slots 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "substrate-consensus-common" -version = "2.0.0" -dependencies = [ - "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "sr-version 2.0.0", - "substrate-inherents 2.0.0", - "substrate-primitives 2.0.0", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-consensus-slots" -version = "2.0.0" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "substrate-client 2.0.0", - "substrate-consensus-common 2.0.0", - "substrate-inherents 2.0.0", - "substrate-primitives 2.0.0", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-executor" -version = "2.0.0" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-version 2.0.0", - "substrate-panic-handler 2.0.0", - "substrate-primitives 2.0.0", - "substrate-serializer 2.0.0", - "substrate-state-machine 2.0.0", - "substrate-trie 2.0.0", - "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-inherents" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", -] - -[[package]] -name = "substrate-keyring" -version = "2.0.0" -dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "strum 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "strum_macros 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "substrate-offchain-primitives" -version = "2.0.0" -dependencies = [ - "sr-primitives 2.0.0", - "substrate-client 2.0.0", -] - -[[package]] -name = "substrate-panic-handler" -version = "2.0.0" -dependencies = [ - "backtrace 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-primitives" -version = "2.0.0" -dependencies = [ - "base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hash256-std-hasher 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "primitive-types 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-std 2.0.0", - "substrate-bip39 0.2.1 (git+https://github.com/paritytech/substrate-bip39)", - "tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "twox-hash 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-serializer" -version = "2.0.0" -dependencies = [ - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-state-machine" -version = "2.0.0" -dependencies = [ - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "substrate-panic-handler 2.0.0", - "substrate-primitives 2.0.0", - "substrate-trie 2.0.0", - "trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-telemetry" -version = "2.0.0" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-scope 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-test-runtime" -version = "2.0.0" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memory-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "sr-version 2.0.0", - "srml-executive 2.0.0", - "srml-support 2.0.0", - "substrate-client 2.0.0", - "substrate-consensus-aura-primitives 2.0.0", - "substrate-consensus-babe-primitives 2.0.0", - "substrate-inherents 2.0.0", - "substrate-keyring 2.0.0", - "substrate-offchain-primitives 2.0.0", - "substrate-primitives 2.0.0", - "substrate-trie 2.0.0", - "trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-test-runtime-wasm" -version = "2.0.0" -dependencies = [ - "substrate-test-runtime 2.0.0", -] - -[[package]] -name = "substrate-trie" -version = "2.0.0" -dependencies = [ - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "memory-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-std 2.0.0", - "substrate-primitives 2.0.0", - "trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "subtle" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "subtle" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "syn" -version = "0.15.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "synstructure" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "termcolor" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "termion" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread_local" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "time" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tiny-bip39" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tiny-keccak" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tk-listen" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-trace-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-codec" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-current-thread" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-dns-unofficial" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-executor" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-fs" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-io" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-reactor" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-rustls" -version = "0.10.0-alpha.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustls 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-sync" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-tcp" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-threadpool" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-timer" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-trace-core" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-udp" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-uds" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "toml" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "trie-db" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hashmap_core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "trie-root" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "twofish" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "twox-hash" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "typenum" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "ucd-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "uint" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-segmentation" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unsigned-varint" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "untrusted" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "url" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "utf8-ranges" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "wasm-bindgen" -version = "0.2.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "wasm-bindgen-macro 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bumpalo 2.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro-support 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-backend 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.45" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "wasm-bindgen-webidl" -version = "0.2.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-backend 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "weedle 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasm-timer" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "send_wrapper 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasmi" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmi-validation 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasmi-validation" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "web-sys" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-webidl 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "webpki" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "webpki-roots" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "weedle" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-util" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "wincolor" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "x25519-dalek" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "curve25519-dalek 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "yamux" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "nohash-hasher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zeroize" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "zeroize" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "zeroize_derive 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zeroize_derive" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[metadata] -"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" -"checksum aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2e5b0458ea3beae0d1d8c0f3946564f8e10f90646cf78c06b4351052058d1ee" -"checksum aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" -"checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" -"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" -"checksum aio-limited 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f10b352bc3fc08ae24dc5d2d3ddcac153678533986122dc283d747b12071000" -"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" -"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" -"checksum asn1_der 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9893d63fc3b1c44231e667da6836a33f27d8b6b3bdc82f83da5dfd579d1b6528" -"checksum asn1_der_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e7f92edafad155aff997fa5b727c6429b91e996b5a5d62a2b0adbae1306b5fe" -"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" -"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" -"checksum backtrace 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)" = "1a13fc43f04daf08ab4f71e3d27e1fc27fc437d3e95ac0063a796d92fb40f39b" -"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" -"checksum base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" -"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" -"checksum bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebecac13b3c745150d7b6c3ea7572d372f09d627c2077e893bf26c5c7f70d282" -"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum bitmask 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5da9b3d9f6f585199287a473f4f8dfab6566cf827d15c00c219f53c645687ead" -"checksum blake2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91721a6330935673395a0607df4d49a9cb90ae12d259f1b3e0a3f6e1d486872e" -"checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" -"checksum block-buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1339a1042f5d9f295737ad4d9a6ab6bf81c84a933dba110b9200cd6d1448b814" -"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" -"checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" -"checksum bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0de79cfb98e7aa9988188784d8664b4b5dad6eaaa0863b91d9a4ed871d4f7a42" -"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" -"checksum bumpalo 2.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "84dca3afd8e01b9526818b7963e5b4916063b3cdf9f10cf6b73ef0bd0ec37aa5" -"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" -"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" -"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" -"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" -"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -"checksum c_linked_list 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4964518bd3b4a8190e832886cdc0da9794f12e8e6c1613a9e90ff331c4c8724b" -"checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d" -"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" -"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" -"checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" -"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" -"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" -"checksum crossbeam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad4c7ea749d9fb09e23c5cb17e3b70650860553a0e2744e38446b1803bf7db94" -"checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" -"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" -"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" -"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" -"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" -"checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" -"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" -"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" -"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" -"checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" -"checksum crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -"checksum crypto-mac 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "779015233ac67d65098614aec748ac1c756ab6677fa2e14cf8b37c08dfed1198" -"checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" -"checksum ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "022cd691704491df67d25d006fe8eca083098253c4d43516c2206479c58c6736" -"checksum cuckoofilter 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd43f7cfaffe0a386636a10baea2ee05cc50df3b77bea4a456c9572a939bf1f" -"checksum curve25519-dalek 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "750226d75fc2f5a8daec6e7477624e258674023eb73d8d647f63b943ca182a4a" -"checksum data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f47ca1860a761136924ddd2422ba77b2ea54fe8cc75b9040804a0d9d32ad97" -"checksum derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6d944ac6003ed268757ef1ee686753b57efc5fcf0ebe7b64c9fc81e7e32ff839" -"checksum digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5b29bf156f3f4b3c4f610a25ff69370616ae6e0657d416de22645483e72af0a" -"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" -"checksum dns-parser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea" -"checksum ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81956bcf7ef761fb4e1d88de3fa181358a0d26cbcb9755b587a08f9119824b86" -"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" -"checksum elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "073be79b6538296faf81c631872676600616073817dd9a440c477ad09b408983" -"checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a" -"checksum environmental 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c7464757b80de8930c91c9afe77ddce501826bf9d134a87db2c67d9dc177e2c" -"checksum erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3beee4bc16478a1b26f2e80ad819a52d24745e292f521a63c16eea5f74b7eb60" -"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" -"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" -"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" -"checksum fixed-hash 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d1a683d1234507e4f3bf2736eeddf0de1dc65996dc0164d57eba0a74bcf29489" -"checksum flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f87e68aa82b2de08a6e037f1385455759df6e445a8df5e005b4297191dbf18aa" -"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)" = "a2037ec1c6c1c4f79557762eab1f7eae1f64f6cb418ace90fae88f0942b60139" -"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" -"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" -"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" -"checksum generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fceb69994e330afed50c93524be68c42fa898c2d9fd4ee8da03bd7363acd26f2" -"checksum get_if_addrs 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "abddb55a898d32925f3148bd281174a68eeb68bbfd9a5938a57b18f506ee4ef7" -"checksum get_if_addrs-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0d04f9fb746cf36b191c00f3ede8bde9c8e64f9f4b05ae2694a9ccf5e3f5ab48" -"checksum hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ba7fb417e5c470acdd61068c79767d0e65962e70836cf6c9dfd2409f06345ce0" -"checksum hash256-std-hasher 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b2027c19ec91eb304999abae7307d225cf93be42af53b0039f76e98ed5af86" -"checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da" -"checksum hashmap_core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8e04cb7a5051270ef3fa79f8c7604d581ecfa73d520e74f554e45541c4b5881a" -"checksum heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461" -"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" -"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" -"checksum hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ddc2928beef125e519d69ae1baa8c37ea2e0d3848545217f6db0179c5eb1d639" -"checksum hex-literal-impl 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "520870c3213943eb8d7803e80180d12a6c7ceb4ae74602544529d1643dc4ddda" -"checksum hmac 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a13f4163aa0c5ca1be584aace0e2212b2e41be5478218d4f657f5f778b2ae2a" -"checksum hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f127a908633569f208325f86f71255d3363c79721d7f9fe31cd5569908819771" -"checksum hmac-drbg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fe727d41d2eec0a6574d887914347e5ff96a3b87177817e2a9820c5c87fecc2" -"checksum http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "eed324f0f0daf6ec10c474f150505af2c143f251722bf9dbd1261bd1f2ee2c1a" -"checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" -"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" -"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -"checksum impl-codec 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2050d823639fbeae26b2b5ba09aca8907793117324858070ade0673c49f793b" -"checksum impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5158079de9d4158e0ce1de3ae0bd7be03904efc40b3d7dd8b8c301cbf6b52b56" -"checksum impl-serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d26be4b97d738552ea423f76c4f681012ff06c3fa36fa968656b3679f60b4a1" -"checksum integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ea155abb3ba6f382a75f1418988c05fe82959ed9ce727de427f9cfd425b0c903" -"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" -"checksum ipnet 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e61c2da0d0f700c77d2d313dbf4f93e41d235fa12c6681fee06621036df4c2af" -"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" -"checksum js-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "9987e7c13a91d9cf0efe59cca48a3a7a70e2b11695d5a4640f85ae71e28f5e73" -"checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum kvdb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" -"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "42914d39aad277d9e176efbdad68acb1d5443ab65afe0e0e4f0d49352a950880" -"checksum libp2p 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6abde4e6fc777dc06ae2a15202ddedb1a38d7c71ed16bc10fa704b03f73aec37" -"checksum libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b4ceb4791289534d4c1ad8e4bd3c6f06d3670efa55ce71482951a287df93ddd1" -"checksum libp2p-core-derive 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "851a59dcaab66c96777ae0cace96de88a700243c3b8360ab51c7e093f3727066" -"checksum libp2p-deflate 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "902b44e92e1f8b7e697b3a186d15c841e0e38037f14286513207a5407650a635" -"checksum libp2p-dns 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71a6630a84552b39e5f752e1f6a951d31f3211079465d2e7af73491b6f48fc3f" -"checksum libp2p-floodsub 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9fced4da0c31e0dc8a759472c65fab41db40c01de2d93bc45e1431c13f0564f0" -"checksum libp2p-identify 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1ba5e882d72c71cdf77f45ab68dd715451d3b78a23085f8d385c7a31ec1b4272" -"checksum libp2p-kad 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d71966dbbb4cedcfcdb1d4c87d5dbb6f3f07b465d1ca74f2624256669997d1f2" -"checksum libp2p-mdns 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdbdaea6f0049cc09ba5db00308f5b93105a8a33b65ba2e36bd35da707850ea2" -"checksum libp2p-mplex 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b351bfd67e97154e7b60f62402237671486c8a89f83eabdb6838f37d4d5f006" -"checksum libp2p-noise 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44324032b2f9260d2b862c741d79d250dc02298dbba56354a992528a826ee2d5" -"checksum libp2p-ping 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1ac43ffd01de4210cf1b969bbb55a008c77f9ec22b74df26a6590bb6bd4c93f" -"checksum libp2p-plaintext 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0506e10770bcbcb59f2a6154ce93c8fd5cb9730b6ceb5aa1463164af1fd0b9c6" -"checksum libp2p-ratelimit 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3886b79a35c0348497bab763517a9a2b4965173f4b4c7438d59f1e4dcf5122ff" -"checksum libp2p-secio 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b811272e5cd86d39bd71fb94687025d9802b13daf0998ebe0d3f2885c636c51a" -"checksum libp2p-tcp 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b2c54cb75f17557de6ce0149aa03e729455e2d240f84d854272bc4b11012a324" -"checksum libp2p-uds 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fbedf4a1e72a5f67523915414e9e12d71d128731873f0f24d8b878398fb47aa4" -"checksum libp2p-wasm-ext 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c1f615b56aa2a6f4ec07bf9667be9fff8877b9c5bd5335601af47490eda341" -"checksum libp2p-websocket 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a0d1bfe60577558f48a9fdf9f35c0ee2dc5baa01f685ff847d3b5cf4f12ee135" -"checksum libp2p-yamux 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bf4bfc7ff127cd622502dbe56f10513dd6776b970e33d8ebb6e367f0752324f6" -"checksum libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "688e8d65e495567c2c35ea0001b26b9debf0b4ea11f8cccc954233b75fc3428a" -"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" -"checksum lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed946d4529956a20f2d63ebe1b69996d5a2137c91913fe3ebbeff957f5bca7ff" -"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" -"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" -"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum memory-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7623b01a4f1b7acb7cf8e3f678f05e15e6ae26cb0b738dfeb5cc186fd6b82ef4" -"checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" -"checksum merlin 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8c39467de91b004f5b9c06fac5bbc8e7d28309a205ee66905166b70804a71fea" -"checksum miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9e3ae51cea1576ceba0dde3d484d30e6e5b86dee0b2d412fe3a16a15c98202" -"checksum miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c468f2369f07d651a5d0bb2c9079f8488a66d5466efe42d0c5c6466edcb7f71e" -"checksum miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7fe927a42e3807ef71defb191dc87d4e24479b221e67015fe38ae2b7b447bab" -"checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" -"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" -"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum multistream-select 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f989d40aab0ed0d83c1cdb4856b5790e980b96548d1a921f280e985eb049f38d" -"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" -"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" -"checksum nohash-hasher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0d138afcce92d219ccb6eb53d9b1e8a96ac0d633cfd3c53cd9856d96d1741bb8" -"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" -"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" -"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" -"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" -"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" -"checksum once_cell 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "532c29a261168a45ce28948f9537ddd7a5dd272cc513b3017b1e82a88f962c37" -"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" -"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" -"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" -"checksum parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" -"checksum parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dcb43c05fb71c03b4ea7327bf15694da1e0f23f19d5b1e95bab6c6d74097e336" -"checksum parity-codec-derive 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "00a486fd383382ddcb2de928364b1f82571c1e48274fc43b7667a4738ee4056c" -"checksum parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "045b3c7af871285146300da35b1932bb6e4639b66c7c98e85d06a32cbc4e8fa7" -"checksum parity-multihash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05d6a68e07ab34a9e87bd8dd4936f6bb5be21e4f6dbcdbaf04d8e854eba0af01" -"checksum parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f" -"checksum parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)" = "511379a8194230c2395d2f5fa627a5a7e108a9f976656ce723ae68fca4097bfc" -"checksum parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4d05f1349491390b1730afba60bb20d55761bef489a954546b58b4b34e1e2ac" -"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" -"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" -"checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7" -"checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" -"checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c" -"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" -"checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c" -"checksum paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4a4a1c555c6505821f9d58b8779d0f630a6b7e4e1be24ba718610acf01fa79" -"checksum paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "26e796e623b8b257215f27e6c80a5478856cae305f5b59810ff9acdaa34570e6" -"checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" -"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" -"checksum primitive-types 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6e8612a8dc70f26276fed6131c153ca277cf275ee0a5e2a50cd8a69c697beb8f" -"checksum proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e" -"checksum proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c725b36c99df7af7bf9324e9c999b9e37d92c8f8caf106d82e1d7953218d2d8" -"checksum proc-macro-hack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0c1dd4172a1e1f96f709341418f49b11ea6c2d95d53dca08c0f74cbd332d9cf3" -"checksum proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b753ad9ed99dd8efeaa7d2fb8453c8f6bc3e54b97966d35f1bc77ca6865254a" -"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a151c11a92df0059d6ab446fafa3b21a1210aad4bc2293e1c946e8132b10db01" -"checksum quick-error 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5fb6ccf8db7bbcb9c2eae558db5ab4f3da1c2a87e4e597ed394726bc8ea6ca1d" -"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" -"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" -"checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" -"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -"checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473" -"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" -"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58" -"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" -"checksum ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)" = "426bc186e3e95cac1e4a4be125a4aca7e84c2d616ffc02244eef36e2a60a093c" -"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" -"checksum rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "403bb3a286107a04825a5f82e1270acc1e14028d3d554d7a1e08914549575ab8" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rustls 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f271e3552cd835fa28c541c34a7e8fdd8cdff09d77fe4eb8f6c42e87a11b096e" -"checksum rw-stream-sink 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9cbe61c20455d3015b2bb7be39e1872310283b8e5a52f5b242b0ac7581fe78" -"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f" -"checksum safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7bf422d23a88c16d5090d455f182bc99c60af4df6a345c63428acf5129e347" -"checksum schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5eff518f9bed3d803a0d002af0ab96339b0ebbedde3bec98a684986134b7a39" -"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" -"checksum sct 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f5adf8fbd58e1b1b52699dc8bed2630faecb6d8c7bee77d009d6bbe4af569b9" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum send_wrapper 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0eddf2e8f50ced781f288c19f18621fa72a3779e3cb58dbf23b07469b0abeb4" -"checksum serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)" = "a72e9b96fa45ce22a4bc23da3858dfccfd60acd28a25bcd328a98fdd6bea43fd" -"checksum serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)" = "101b495b109a3e3ca8c4cbe44cf62391527cdfb6ba15821c5ce80bcd5ea23f9f" -"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" -"checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68" -"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" -"checksum sha2 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d963c78ce367df26d7ea8b8cc655c651b42e8a1e584e869c1e17dae3ccb116a" -"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" -"checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" -"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1e1a2eec401952cd7b12a84ea120e2d57281329940c3f93c2bf04f462539508e" -"checksum slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddc0d2aff1f8f325ef660d9a0eb6e6dcd20b30b3f581a5897f58bf42d061c37a" -"checksum slog-scope 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "60c04b4726fa04595ccf2c2dad7bcd15474242c4c5e109a8a376e8a2c9b1539a" -"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" -"checksum snow 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5a64f02fd208ef15bd2d1a65861df4707e416151e1272d02c8faafad1c138100" -"checksum soketto 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8cf3ae22c0bce5437c7dce6a2b00e492c19da1feb21ad64a7b6fd7058438c3f2" -"checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3" -"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" -"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" -"checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" -"checksum static_slice 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "92a7e0c5e3dfb52e8fbe0e63a1b947bbb17b4036408b151353c4491374931362" -"checksum stream-cipher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8861bc80f649f5b4c9bd38b696ae9af74499d479dbfb327f0607de6b326a36bc" -"checksum strum 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1810e25f576e7ffce1ff5243b37066da5ded0310b3274c20baaeccb1145b2806" -"checksum strum_macros 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "572a2f4e53dd4c3483fd79e5cc10ddd773a3acb1169bbfe8762365e107110579" -"checksum substrate-bip39 0.2.1 (git+https://github.com/paritytech/substrate-bip39)" = "" -"checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" -"checksum subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "01dca13cf6c3b179864ab3292bd794e757618d35a7766b7c46050c614ba00829" -"checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe" -"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" -"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" -"checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea" -"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" -"checksum tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c1c5676413eaeb1ea35300a0224416f57abc3bd251657e0fafc12c47ff98c060" -"checksum tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e9175261fbdb60781fcd388a4d6cc7e14764a2b629a7ad94abb439aed223a44f" -"checksum tk-listen 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5462b0f968c0457efe38fcd2df7e487096b992419e4f5337b06775a614bbda4b" -"checksum tokio 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "94a1f9396aec29d31bb16c24d155cfa144d1af91c40740125db3131bdaf76da8" -"checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" -"checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443" -"checksum tokio-dns-unofficial 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82c65483db54eb91b4ef3a9389a3364558590faf30ce473141707c0e16fda975" -"checksum tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "83ea44c6c0773cc034771693711c35c677b4b5a4b21b9e7071704c54de7d555e" -"checksum tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe6dc22b08d6993916647d108a1a7d15b9cd29c4f4496c62b92c45b5041b7af" -"checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926" -"checksum tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6af16bfac7e112bea8b0442542161bfc41cbfa4466b580bdda7d18cb88b911ce" -"checksum tokio-rustls 0.10.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)" = "316fdbc899efec48b3b492bd0f339e6d81c4ee96a409257572147ec341943452" -"checksum tokio-sync 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "5b2f843ffdf8d6e1f90bddd48da43f99ab071660cd92b7ec560ef3cdfd7a409a" -"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" -"checksum tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72558af20be886ea124595ea0f806dd5703b8958e4705429dd58b3d8231f72f2" -"checksum tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f2106812d500ed25a4f38235b9cae8f78a09edf43203e16e59c3b769a342a60e" -"checksum tokio-trace-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "350c9edade9830dc185ae48ba45667a445ab59f6167ef6d0254ec9d2430d9dd3" -"checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92" -"checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" -"checksum toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8c96d7873fa7ef8bdeb3a9cda3ac48389b4154f32b9803b4bc26220b677b039" -"checksum trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1ba73747fd3a64ab531274c04cb588dfa9d30d972d62990831e63fbce2cfec59" -"checksum trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfa2e20c4f1418ac2e71ddc418e35e1b56e34022e2146209ffdbf1b2de8b1bd9" -"checksum twofish 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d261e83e727c8e2dbb75dacac67c36e35db36a958ee504f2164fc052434e1" -"checksum twox-hash 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6c7bcecad121018bdcd6b709fa2325b004878fcb3d3067934ce90749f0faff9a" -"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" -"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" -"checksum uint 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2143cded94692b156c356508d92888acc824db5bffc0b4089732264c6fcf86d4" -"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" -"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2c64cdf40b4a9645534a943668681bcb219faf51874d4b65d2e0abda1b10a2ab" -"checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" -"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" -"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "b7ccc7b93cfd13e26700a9e2e41e6305f1951b87e166599069f77d10358100e6" -"checksum wasm-bindgen-backend 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "1953f91b1608eb1522513623c7739f047bb0fed4128ce51a93f08e12cc314645" -"checksum wasm-bindgen-futures 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "fa1af11c73eca3dc8c51c76ea475a4416e912da6402064a49fc6c0214701866d" -"checksum wasm-bindgen-macro 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "0f69da5696545d7ca6607a2e4b1a0edf5a6b36b2c49dbb0f1df6ad1d92884047" -"checksum wasm-bindgen-macro-support 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d4246f3bc73223bbb846f4f2430a60725826a96c9389adf715ed1d5af46dec6" -"checksum wasm-bindgen-shared 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "c08381e07e7a79e5e229ad7c60d15833d19033542cc5dd91d085df59d235f4a6" -"checksum wasm-bindgen-webidl 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "1f42ff7adb8102bf5ad8adbc45b1635c520c8175f9fdf6eb2c54479d485d435a" -"checksum wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad9ac33c834103916e373d648adf65f58c83fb3d8a0f3e6b9a64bca7253a4dca" -"checksum wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aebbaef470840d157a5c47c8c49f024da7b1b80e90ff729ca982b2b80447e78b" -"checksum wasmi-validation 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab380192444b3e8522ae79c0a1976e42a82920916ccdfbce3def89f456ea33f3" -"checksum web-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "540b8259eb242ff3a566fa0140bda03a4ece4e5c226e1284b5c95dddcd4341f6" -"checksum webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4f7e1cd7900a3a6b65a3e8780c51a3e6b59c0e2c55c6dc69578c288d69f7d082" -"checksum webpki-roots 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c10fa4212003ba19a564f25cd8ab572c6791f99a03cc219c13ed35ccab00de0e" -"checksum weedle 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc44aa200daee8b1f3a004beaf16554369746f1b4486f0cf93b0caf8a3c2d1e" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" -"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -"checksum x25519-dalek 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7ee1585dc1484373cbc1cee7aafda26634665cf449436fd6e24bfd1fad230538" -"checksum yamux 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "01bd67889938c48f0049fc60a77341039e6c3eaf16cb7693e6ead7c0ba701295" -"checksum zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8ddfeb6eee2fb3b262ef6e0898a52b7563bb8e0d5955a313b3cf2f808246ea14" -"checksum zeroize 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b60a6c572b91d8ecb0a460950d84fe5b40699edd07d65f73789b31237afc8f66" -"checksum zeroize_derive 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9dac4b660d969bff9c3fe1847a891cacaa8b21dd5f2aae6e0a3e0975aea96431" diff --git a/core/test-runtime/wasm/Cargo.toml b/core/test-runtime/wasm/Cargo.toml deleted file mode 100644 index a056eab3840740e0ee3f2f07f99214446b23a0f5..0000000000000000000000000000000000000000 --- a/core/test-runtime/wasm/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "substrate-test-runtime-wasm" -version = "2.0.0" -authors = ["Parity Technologies "] -edition = "2018" - -[lib] -name = "substrate_test_runtime" -crate-type = ["cdylib"] - -[dependencies] -substrate-test-runtime = { path = "..", default-features = false } - -[features] -default = [] -std = [ - "substrate-test-runtime/std", -] - -[profile.release] -panic = "abort" -lto = true - -[workspace] -members = [] diff --git a/core/test-runtime/wasm/build.sh b/core/test-runtime/wasm/build.sh deleted file mode 100755 index 059e475c71e78c7c23f2acb6ffcfa7a8e31f95b6..0000000000000000000000000000000000000000 --- a/core/test-runtime/wasm/build.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -set -e - -if cargo --version | grep -q "nightly"; then - CARGO_CMD="cargo" -else - CARGO_CMD="cargo +nightly" -fi -CARGO_INCREMENTAL=0 RUSTFLAGS="-C link-arg=--export-table" $CARGO_CMD build --target=wasm32-unknown-unknown --release "$@" -for i in substrate_test_runtime -do - wasm-gc "target/wasm32-unknown-unknown/release/$i.wasm" "target/wasm32-unknown-unknown/release/$i.compact.wasm" -done diff --git a/core/transaction-pool/Cargo.toml b/core/transaction-pool/Cargo.toml index 2bcad4d4d6c2e624b0b887e4c3d34ff8cd6199bf..2e4f32197b11e5804736316426ef861a1b524283 100644 --- a/core/transaction-pool/Cargo.toml +++ b/core/transaction-pool/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" derive_more = "0.14.0" futures = "0.1" log = "0.4" -parity-codec = "3.3" +parity-codec = "4.1.1" parking_lot = "0.8.0" sr-primitives = { path = "../sr-primitives" } client = { package = "substrate-client", path = "../client" } diff --git a/core/transaction-pool/graph/Cargo.toml b/core/transaction-pool/graph/Cargo.toml index 3f918efa4a2ea7c61b5717123f7fdd37e4a85a8e..951a595810d7453a152c180f7bca62d2e43a94e3 100644 --- a/core/transaction-pool/graph/Cargo.toml +++ b/core/transaction-pool/graph/Cargo.toml @@ -16,5 +16,5 @@ sr-primitives = { path = "../../sr-primitives" } [dev-dependencies] assert_matches = "1.3.0" env_logger = "0.6.1" -parity-codec = "3.5.1" +parity-codec = "4.1.1" test_runtime = { package = "substrate-test-runtime", path = "../../test-runtime" } diff --git a/core/transaction-pool/graph/src/ready.rs b/core/transaction-pool/graph/src/ready.rs index 3497c1bc4ba72408535c33d43813fc08031c465c..85bb4dd783c42292b07dfb7292bbd709de081960 100644 --- a/core/transaction-pool/graph/src/ready.rs +++ b/core/transaction-pool/graph/src/ready.rs @@ -350,7 +350,7 @@ impl ReadyTransactions { /// we are about to replace is lower than the priority of the replacement transaction. /// We remove/replace old transactions in case they have lower priority. /// - /// In case replacement is succesful returns a list of removed transactions. + /// In case replacement is successful returns a list of removed transactions. fn replace_previous(&mut self, tx: &Transaction) -> error::Result>>> { let mut to_remove = { // check if we are replacing a transaction diff --git a/core/trie/Cargo.toml b/core/trie/Cargo.toml index dc245a442bd06962a6da73adb7eb3cadd5d337f1..ef00e52edadc47c4d8bf74c777f7c6215c23371a 100644 --- a/core/trie/Cargo.toml +++ b/core/trie/Cargo.toml @@ -12,18 +12,18 @@ name = "bench" harness = false [dependencies] -codec = { package = "parity-codec", version = "3.2", default-features = false } +codec = { package = "parity-codec", version = "4.1.1", default-features = false } rstd = { package = "sr-std", path = "../sr-std", default-features = false } -hash-db = { version = "0.12.2", default-features = false } -trie-db = { version = "0.12.2", default-features = false } -trie-root = { version = "0.12.2", default-features = false } -memory-db = { version = "0.12.2", default-features = false } +hash-db = { version = "0.14.0", default-features = false } +trie-db = { version = "0.14.0", default-features = false } +trie-root = { version = "0.14.0", default-features = false } +memory-db = { version = "0.14.0", default-features = false } substrate-primitives = { path = "../primitives", default-features = false } [dev-dependencies] -trie-bench = { version = "0.12" } -trie-standardmap = { version = "0.12" } -keccak-hasher = { version = "0.12" } +trie-bench = { version = "0.14.0" } +trie-standardmap = { version = "0.14.0" } +keccak-hasher = { version = "0.14.0" } criterion = "0.2" hex-literal = "0.2.0" diff --git a/core/trie/src/lib.rs b/core/trie/src/lib.rs index ec6f50d6e32cc5ab6bd5a44d6735af5c52cb3aa5..fe45c4aaf1985e08fcd2462f1c0b4836bdee8942 100644 --- a/core/trie/src/lib.rs +++ b/core/trie/src/lib.rs @@ -36,6 +36,8 @@ pub use node_codec::NodeCodec; pub use trie_db::{Trie, TrieMut, DBValue, Recorder, Query}; /// Various re-exports from the `memory-db` crate. pub use memory_db::{KeyFunction, prefixed_key}; +/// Various re-exports from the `hash-db` crate. +pub use hash_db::HashDB as HashDBT; /// As in `trie_db`, but less generic, error type for the crate. pub type TrieError = trie_db::TrieError; diff --git a/core/util/fork-tree/Cargo.toml b/core/utils/fork-tree/Cargo.toml similarity index 68% rename from core/util/fork-tree/Cargo.toml rename to core/utils/fork-tree/Cargo.toml index d65f65d51afbe3bad6a20f8a309a9067fd5e0c55..c41914e07acb408565655a425709c41671a9f68b 100644 --- a/core/util/fork-tree/Cargo.toml +++ b/core/utils/fork-tree/Cargo.toml @@ -5,4 +5,4 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -parity-codec = { version = "3.3", features = ["derive"] } +parity-codec = { version = "4.1.1", features = ["derive"] } diff --git a/core/util/fork-tree/src/lib.rs b/core/utils/fork-tree/src/lib.rs similarity index 100% rename from core/util/fork-tree/src/lib.rs rename to core/utils/fork-tree/src/lib.rs diff --git a/core/utils/wasm-builder-runner/Cargo.toml b/core/utils/wasm-builder-runner/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..4046b7e4e2f2551284fabff97501a3731c204edb --- /dev/null +++ b/core/utils/wasm-builder-runner/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "substrate-wasm-builder-runner" +version = "1.0.2" +authors = ["Parity Technologies "] +description = "Runner for substrate-wasm-builder" +edition = "2018" +readme = "README.md" +repository = "https://github.com/paritytech/substrate" +license = "GPL-3.0" + +[dependencies] diff --git a/core/utils/wasm-builder-runner/README.md b/core/utils/wasm-builder-runner/README.md new file mode 100644 index 0000000000000000000000000000000000000000..1b9e2b08ca44405cf307c559b29b743eb8039b10 --- /dev/null +++ b/core/utils/wasm-builder-runner/README.md @@ -0,0 +1,12 @@ +## WASM builder runner + +Since cargo contains many bugs when it comes to correct dependency and feature +resolution, we need this little tool. See for +more information. + +It will create a project that will call `substrate-wasm-builder` to prevent any dependencies +from `substrate-wasm-builder` influencing the main project's dependencies. + +For more information see + +License: GPL-3.0 diff --git a/core/utils/wasm-builder-runner/src/lib.rs b/core/utils/wasm-builder-runner/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..1558dbf22044f1e2f414a7e8c2ba73546c895cc2 --- /dev/null +++ b/core/utils/wasm-builder-runner/src/lib.rs @@ -0,0 +1,241 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +//! # WASM builder runner +//! +//! Since cargo contains many bugs when it comes to correct dependency and feature +//! resolution, we need this little tool. See for +//! more information. +//! +//! It will create a project that will call `substrate-wasm-builder` to prevent any dependencies +//! from `substrate-wasm-builder` influencing the main project's dependencies. +//! +//! For more information see + +use std::{env, process::{Command, self}, fs, path::{PathBuf, Path}}; + +/// Environment variable that tells us to skip building the WASM binary. +const SKIP_BUILD_ENV: &str = "SKIP_WASM_BUILD"; + +/// Environment variable to extend the `RUSTFLAGS` variable given to the WASM build. +const WASM_BUILD_RUSTFLAGS_ENV: &str = "WASM_BUILD_RUSTFLAGS"; + +/// Environment variable that tells us to create a dummy WASM binary. +/// +/// This is useful for `cargo check` to speed-up the compilation. +/// +/// # Caution +/// +/// Enabling this option will just provide `&[]` as WASM binary. +const DUMMY_WASM_BINARY_ENV: &str = "BUILD_DUMMY_WASM_BINARY"; + +/// Environment variable that makes sure the WASM build is triggered. +const TRIGGER_WASM_BUILD_ENV: &str = "TRIGGER_WASM_BUILD"; + +/// Replace all backslashes with slashes. +fn replace_back_slashes(path: T) -> String { + path.to_string().replace("\\", "/") +} + +/// The `wasm-builder` dependency source. +pub enum WasmBuilderSource { + /// The relative path to the source code from the current manifest dir. + Path(&'static str), + /// The git repository that contains the source code. + Git { + repo: &'static str, + rev: &'static str, + }, + /// Use the given version released on crates.io. + Crates(&'static str), + /// Use the given version released on crates.io or from the given path. + CratesOrPath { + version: &'static str, + path: &'static str, + } +} + +impl WasmBuilderSource { + /// Convert to a valid cargo source declaration. + /// + /// `absolute_path` - The manifest dir. + fn to_cargo_source(&self, manifest_dir: &Path) -> String { + match self { + WasmBuilderSource::Path(path) => { + replace_back_slashes(format!("path = \"{}\"", manifest_dir.join(path).display())) + } + WasmBuilderSource::Git { repo, rev } => { + format!("git = \"{}\", rev=\"{}\"", repo, rev) + } + WasmBuilderSource::Crates(version) => { + format!("version = \"{}\"", version) + } + WasmBuilderSource::CratesOrPath { version, path } => { + replace_back_slashes( + format!( + "path = \"{}\", version = \"{}\"", + manifest_dir.join(path).display(), + version + ) + ) + } + } + } +} + +/// Build the currently built project as WASM binary and extend `RUSTFLAGS` with the given rustflags. +/// +/// For more information, see [`build_current_project`]. +pub fn build_current_project_with_rustflags( + file_name: &str, + wasm_builder_source: WasmBuilderSource, + rustflags: &str, +) { + let given_rustflags = env::var(WASM_BUILD_RUSTFLAGS_ENV).unwrap_or_default(); + env::set_var(WASM_BUILD_RUSTFLAGS_ENV, format!("{} {}", given_rustflags, rustflags)); + + build_current_project(file_name, wasm_builder_source) +} + +/// Build the currently built project as WASM binary. +/// +/// The current project is determined using the `CARGO_MANIFEST_DIR` environment variable. +/// +/// `file_name` - The name of the file being generated in the `OUT_DIR`. The file contains the +/// constant `WASM_BINARY` which contains the build wasm binary. +/// `wasm_builder_path` - Path to the wasm-builder project, relative to `CARGO_MANIFEST_DIR`. +pub fn build_current_project(file_name: &str, wasm_builder_source: WasmBuilderSource) { + if check_skip_build() { + // If we skip the build, we still want to make sure to be called when an env variable changes + generate_rerun_if_changed_instructions(); + return; + } + + let manifest_dir = PathBuf::from( + env::var("CARGO_MANIFEST_DIR").expect( + "`CARGO_MANIFEST_DIR` is always set for `build.rs` files; qed" + ) + ); + + let cargo_toml_path = manifest_dir.join("Cargo.toml"); + let out_dir = PathBuf::from(env::var("OUT_DIR").expect("`OUT_DIR` is set by cargo!")); + let file_path = out_dir.join(file_name); + let project_folder = out_dir.join("wasm_build_runner"); + + if check_provide_dummy_wasm_binary() { + provide_dummy_wasm_binary(&file_path); + } else { + create_project(&project_folder, &file_path, &manifest_dir, wasm_builder_source, &cargo_toml_path); + run_project(&project_folder); + } + + // As last step we need to generate our `rerun-if-changed` stuff. If a build fails, we don't + // want to spam the output! + generate_rerun_if_changed_instructions(); +} + +fn create_project( + project_folder: &Path, + file_path: &Path, + manifest_dir: &Path, + wasm_builder_source: WasmBuilderSource, + cargo_toml_path: &Path, +) { + fs::create_dir_all(project_folder.join("src")) + .expect("WASM build runner dir create can not fail; qed"); + + fs::write( + project_folder.join("Cargo.toml"), + format!( + r#" + [package] + name = "wasm-build-runner-impl" + version = "1.0.0" + edition = "2018" + + [dependencies] + substrate-wasm-builder = {{ {wasm_builder_source} }} + + [workspace] + "#, + wasm_builder_source = wasm_builder_source.to_cargo_source(manifest_dir), + ) + ).expect("WASM build runner `Cargo.toml` writing can not fail; qed"); + + fs::write( + project_folder.join("src/main.rs"), + format!( + r#" + fn main() {{ + substrate_wasm_builder::build_project("{file_path}", "{cargo_toml_path}") + }} + "#, + file_path = replace_back_slashes(file_path.display()), + cargo_toml_path = replace_back_slashes(cargo_toml_path.display()), + ) + ).expect("WASM build runner `main.rs` writing can not fail; qed"); +} + +fn run_project(project_folder: &Path) { + let cargo = env::var("CARGO").expect("`CARGO` env variable is always set when executing `build.rs`."); + let mut cmd = Command::new(cargo); + cmd.arg("run").arg(format!("--manifest-path={}", project_folder.join("Cargo.toml").display())); + + if env::var("DEBUG") != Ok(String::from("true")) { + cmd.arg("--release"); + } + + if !cmd.status().map(|s| s.success()).unwrap_or(false) { + // Don't spam the output with backtraces when a build failed! + process::exit(1); + } +} + +/// Generate the name of the skip build environment variable for the current crate. +fn generate_crate_skip_build_env_name() -> String { + format!( + "SKIP_{}_WASM_BUILD", + env::var("CARGO_PKG_NAME").expect("Package name is set").to_uppercase().replace('-', "_"), + ) +} + +/// Checks if the build of the WASM binary should be skipped. +fn check_skip_build() -> bool { + env::var(SKIP_BUILD_ENV).is_ok() || env::var(generate_crate_skip_build_env_name()).is_ok() +} + +/// Check if we should provide a dummy WASM binary. +fn check_provide_dummy_wasm_binary() -> bool { + env::var(DUMMY_WASM_BINARY_ENV).is_ok() +} + +/// Provide the dummy WASM binary +fn provide_dummy_wasm_binary(file_path: &Path) { + fs::write( + file_path, + "pub const WASM_BINARY: &[u8] = &[]; pub const WASM_BINARY_BLOATY: &[u8] = &[];" + ).expect("Writing dummy WASM binary should not fail"); +} + +/// Generate the `rerun-if-changed` instructions for cargo to make sure that the WASM binary is +/// rebuilt when needed. +fn generate_rerun_if_changed_instructions() { + // Make sure that the `build.rs` is called again if one of the following env variables changes. + println!("cargo:rerun-if-env-changed={}", SKIP_BUILD_ENV); + println!("cargo:rerun-if-env-changed={}", DUMMY_WASM_BINARY_ENV); + println!("cargo:rerun-if-env-changed={}", TRIGGER_WASM_BUILD_ENV); + println!("cargo:rerun-if-env-changed={}", generate_crate_skip_build_env_name()); +} diff --git a/core/utils/wasm-builder/Cargo.toml b/core/utils/wasm-builder/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..44288dbcd268f97844230cc9b9f5a701cfcaac9f --- /dev/null +++ b/core/utils/wasm-builder/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "substrate-wasm-builder" +version = "1.0.4" +authors = ["Parity Technologies "] +description = "Utility for building WASM binaries" +edition = "2018" +readme = "README.md" +repository = "https://github.com/paritytech/substrate" +license = "GPL-3.0" + +[dependencies] +build-helper = "0.1.1" +cargo_metadata = "0.8" +tempfile = "3.1.0" +toml = "0.5.1" +walkdir = "2.2.8" +fs2 = "0.4.3" diff --git a/core/utils/wasm-builder/README.md b/core/utils/wasm-builder/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8a8c67d6a8c1d164e10d1d4f68a714d83086f5d9 --- /dev/null +++ b/core/utils/wasm-builder/README.md @@ -0,0 +1,66 @@ +## WASM builder is a utility for building a project as a WASM binary + +The WASM builder is a tool that integrates the process of building the WASM binary of your project into the main +`cargo` build process. + +### Project setup + +A project that should be compiled as a WASM binary needs to: + +1. Add a `build.rs` file. +2. Add `substrate-wasm-builder-runner` as dependency into `build-dependencies`. +3. Add a feature called `no-std`. + +The `build.rs` file needs to contain the following code: + +```rust +use wasm_builder_runner::{build_current_project, WasmBuilderSource}; + +fn main() { + build_current_project( + // The name of the file being generated in out-dir. + "wasm_binary.rs", + // How to include wasm-builder, in this case from crates.io. + WasmBuilderSource::Crates("1.0.0"), + ); +} +``` + +The `no-std` feature will be enabled by WASM builder while compiling your project to WASM. + +As the final step, you need to add the following to your project: + +```rust +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +``` + +This will include the generated WASM binary as two constants `WASM_BINARY` and `WASM_BINARY_BLOATY`. +The former is a compact WASM binary and the latter is not compacted. + +### Environment variables + +By using environment variables, you can configure which WASM binaries are built and how: + +- `SKIP_WASM_BUILD` - Skips building any WASM binary. This is useful when only native should be recompiled. +- `BUILD_DUMMY_WASM_BINARY` - Builds dummy WASM binaries. These dummy binaries are empty and useful + for `cargo check` runs. +- `WASM_BUILD_TYPE` - Sets the build type for building WASM binaries. Supported values are `release` or `debug`. + By default the build type is equal to the build type used by the main build. +- `TRIGGER_WASM_BUILD` - Can be set to trigger a WASM build. On subsequent calls the value of the variable + needs to change. As WASM builder instructs `cargo` to watch for file changes + this environment variable should only be required in certain circumstances. +- `WASM_BUILD_RUSTFLAGS` - Extend `RUSTFLAGS` given to `cargo build` while building the WASM binary. + +Each project can be skipped individually by using the environment variable `SKIP_PROJECT_NAME_WASM_BUILD`. +Where `PROJECT_NAME` needs to be replaced by the name of the cargo project, e.g. `node-runtime` will +be `NODE_RUNTIME`. + +### Prerequisites: + +WASM builder requires the following prerequisities for building the WASM binary: + +- rust nightly + `wasm32-unknown-unknown` toolchain +- wasm-gc + + +License: GPL-3.0 diff --git a/core/utils/wasm-builder/src/lib.rs b/core/utils/wasm-builder/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..779fa8db095a2a4f381df4cadfe80fc0f8e8e490 --- /dev/null +++ b/core/utils/wasm-builder/src/lib.rs @@ -0,0 +1,168 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +//! # WASM builder is a utility for building a project as a WASM binary +//! +//! The WASM builder is a tool that integrates the process of building the WASM binary of your project into the main +//! `cargo` build process. +//! +//! ## Project setup +//! +//! A project that should be compiled as a WASM binary needs to: +//! +//! 1. Add a `build.rs` file. +//! 2. Add `substrate-wasm-builder-runner` as dependency into `build-dependencies`. +//! 3. Add a feature called `no-std`. +//! +//! The `build.rs` file needs to contain the following code: +//! +//! ```ignore +//! use wasm_builder_runner::{build_current_project, WasmBuilderSource}; +//! +//! fn main() { +//! build_current_project( +//! // The name of the file being generated in out-dir. +//! "wasm_binary.rs", +//! // How to include wasm-builder, in this case from crates.io. +//! WasmBuilderSource::Crates("1.0.0"), +//! ); +//! } +//! ``` +//! +//! The `no-std` feature will be enabled by WASM builder while compiling your project to WASM. +//! +//! As the final step, you need to add the following to your project: +//! +//! ```ignore +//! include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +//! ``` +//! +//! This will include the generated WASM binary as two constants `WASM_BINARY` and `WASM_BINARY_BLOATY`. +//! The former is a compact WASM binary and the latter is not compacted. +//! +//! ## Environment variables +//! +//! By using environment variables, you can configure which WASM binaries are built and how: +//! +//! - `SKIP_WASM_BUILD` - Skips building any WASM binary. This is useful when only native should be recompiled. +//! - `BUILD_DUMMY_WASM_BINARY` - Builds dummy WASM binaries. These dummy binaries are empty and useful +//! for `cargo check` runs. +//! - `WASM_BUILD_TYPE` - Sets the build type for building WASM binaries. Supported values are `release` or `debug`. +//! By default the build type is equal to the build type used by the main build. +//! - `TRIGGER_WASM_BUILD` - Can be set to trigger a WASM build. On subsequent calls the value of the variable +//! needs to change. As WASM builder instructs `cargo` to watch for file changes +//! this environment variable should only be required in certain circumstances. +//! - `WASM_BUILD_RUSTFLAGS` - Extend `RUSTFLAGS` given to `cargo build` while building the WASM binary. +//! +//! Each project can be skipped individually by using the environment variable `SKIP_PROJECT_NAME_WASM_BUILD`. +//! Where `PROJECT_NAME` needs to be replaced by the name of the cargo project, e.g. `node-runtime` will +//! be `NODE_RUNTIME`. +//! +//! ## Prerequisites: +//! +//! WASM builder requires the following prerequisities for building the WASM binary: +//! +//! - rust nightly + `wasm32-unknown-unknown` toolchain +//! - wasm-gc +//! + +use std::{env, fs, path::PathBuf, process::{Command, Stdio, self}}; + +mod prerequisites; +mod wasm_project; + +/// Environment variable that tells us to skip building the WASM binary. +const SKIP_BUILD_ENV: &str = "SKIP_WASM_BUILD"; + +/// Environment variable to force a certain build type when building the WASM binary. +/// Expects "debug" or "release" as value. +/// +/// By default the WASM binary uses the same build type as the main cargo build. +const WASM_BUILD_TYPE_ENV: &str = "WASM_BUILD_TYPE"; + +/// Environment variable to extend the `RUSTFLAGS` variable given to the WASM build. +const WASM_BUILD_RUSTFLAGS_ENV: &str = "WASM_BUILD_RUSTFLAGS"; + +/// Build the currently built project as WASM binary. +/// +/// The current project is determined by using the `CARGO_MANIFEST_DIR` environment variable. +/// +/// `file_name` - The name + path of the file being generated. The file contains the +/// constant `WASM_BINARY`, which contains the built WASM binary. +/// `cargo_manifest` - The path to the `Cargo.toml` of the project that should be built. +pub fn build_project(file_name: &str, cargo_manifest: &str) { + if check_skip_build() { + return; + } + + let cargo_manifest = PathBuf::from(cargo_manifest); + + if !cargo_manifest.exists() { + panic!("'{}' does not exist!", cargo_manifest.display()); + } + + if !cargo_manifest.ends_with("Cargo.toml") { + panic!("'{}' no valid path to a `Cargo.toml`!", cargo_manifest.display()); + } + + if let Some(err_msg) = prerequisites::check() { + eprintln!("{}", err_msg); + process::exit(1); + } + + let (wasm_binary, bloaty) = wasm_project::create_and_compile(&cargo_manifest); + + create_out_file( + file_name, + format!( + r#" + pub const WASM_BINARY: &[u8] = include_bytes!("{wasm_binary}"); + pub const WASM_BINARY_BLOATY: &[u8] = include_bytes!("{wasm_binary_bloaty}"); + "#, + wasm_binary = wasm_binary.wasm_binary_path(), + wasm_binary_bloaty = bloaty.wasm_binary_bloaty_path(), + ), + ); +} + +/// Checks if the build of the WASM binary should be skipped. +fn check_skip_build() -> bool { + env::var(SKIP_BUILD_ENV).is_ok() +} + +fn create_out_file(file_name: &str, content: String) { + fs::write( + file_name, + content + ).expect("Creating and writing can not fail; qed"); +} + +/// Get a cargo command that compiles with nightly +fn get_nightly_cargo() -> Command { + if Command::new("rustup") + .args(&["run", "nightly", "cargo"]) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status() + .map(|s| s.success()).unwrap_or(false) + { + let mut cmd = Command::new("rustup"); + cmd.args(&["run", "nightly", "cargo"]); + cmd + } else { + Command::new("cargo") + } +} diff --git a/core/utils/wasm-builder/src/prerequisites.rs b/core/utils/wasm-builder/src/prerequisites.rs new file mode 100644 index 0000000000000000000000000000000000000000..5835d322b1f15dd1878eb05734c4f0331ec179d0 --- /dev/null +++ b/core/utils/wasm-builder/src/prerequisites.rs @@ -0,0 +1,96 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +use std::{process::{Command, Stdio}, fs}; + +use tempfile::tempdir; + +/// Checks that all prerequisites are installed. +/// +/// # Returns +/// Returns `None` if everything was found and `Some(ERR_MSG)` if something could not be found. +pub fn check() -> Option<&'static str> { + if !check_nightly_installed() { + return Some("Rust nightly not installed, please install it!") + } + + if Command::new("wasm-gc") + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status() + .map(|s| !s.success()).unwrap_or(true) + { + return Some("`wasm-gc` not installed, please install it!") + } + + if !check_wasm_toolchain_installed() { + return Some("Rust WASM toolchain not installed, please install it!") + } + + None +} + +fn check_nightly_installed() -> bool { + let version = Command::new("cargo") + .arg("--version") + .output() + .map_err(|_| ()) + .and_then(|o| String::from_utf8(o.stdout).map_err(|_| ())) + .unwrap_or_default(); + + let version2 = Command::new("rustup") + .args(&["run", "nightly", "cargo", "--version"]) + .output() + .map_err(|_| ()) + .and_then(|o| String::from_utf8(o.stdout).map_err(|_| ())) + .unwrap_or_default(); + + version.contains("-nightly") || version2.contains("-nightly") +} + +fn check_wasm_toolchain_installed() -> bool { + let temp = tempdir().expect("Creating temp dir does not fail; qed"); + fs::create_dir_all(temp.path().join("src")).expect("Creating src dir does not fail; qed"); + + let test_file = temp.path().join("src/lib.rs"); + let manifest_path = temp.path().join("Cargo.toml"); + + fs::write(&manifest_path, + r#" + [package] + name = "wasm-test" + version = "1.0.0" + edition = "2018" + + [lib] + name = "wasm_test" + crate-type = ["cdylib"] + + [workspace] + "#, + ).expect("Writing wasm-test manifest does not fail; qed"); + fs::write(&test_file, "pub fn test() {}") + .expect("Writing to the test file does not fail; qed"); + + let manifest_path = manifest_path.display().to_string(); + crate::get_nightly_cargo() + .args(&["build", "--target=wasm32-unknown-unknown", "--manifest-path", &manifest_path]) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status() + .map(|s| s.success()) + .unwrap_or(false) +} \ No newline at end of file diff --git a/core/utils/wasm-builder/src/wasm_project.rs b/core/utils/wasm-builder/src/wasm_project.rs new file mode 100644 index 0000000000000000000000000000000000000000..0d348a5cf4ed898311d46fbbf338344282f9a36a --- /dev/null +++ b/core/utils/wasm-builder/src/wasm_project.rs @@ -0,0 +1,352 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +use std::{fs, path::{Path, PathBuf}, borrow::ToOwned, process::{Command, self}, env}; + +use toml::value::Table; + +use build_helper::rerun_if_changed; + +use cargo_metadata::MetadataCommand; + +use walkdir::WalkDir; + +use fs2::FileExt; + +/// Holds the path to the bloaty WASM binary. +pub struct WasmBinaryBloaty(PathBuf); + +impl WasmBinaryBloaty { + /// Returns the path to the bloaty wasm binary. + pub fn wasm_binary_bloaty_path(&self) -> String { + self.0.display().to_string().replace('\\', "/") + } +} + +/// Holds the path to the WASM binary. +pub struct WasmBinary(PathBuf); + +impl WasmBinary { + /// Returns the path to the wasm binary. + pub fn wasm_binary_path(&self) -> String { + self.0.display().to_string().replace('\\', "/") + } +} + +/// A lock for the WASM workspace. +struct WorkspaceLock(fs::File); + +impl WorkspaceLock { + /// Create a new lock + fn new(wasm_workspace_root: &Path) -> Self { + let lock = fs::OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(wasm_workspace_root.join("wasm_workspace.lock")) + .expect("Opening the lock file does not fail"); + + lock.lock_exclusive().expect("Locking `wasm_workspace.lock` failed"); + + WorkspaceLock(lock) + } +} + +impl Drop for WorkspaceLock { + fn drop(&mut self) { + let _ = self.0.unlock(); + } +} + +/// Creates the WASM project, compiles the WASM binary and compacts the WASM binary. +/// +/// # Returns +/// The path to the compact WASM binary and the bloaty WASM binary. +pub fn create_and_compile(cargo_manifest: &Path) -> (WasmBinary, WasmBinaryBloaty) { + let wasm_workspace_root = get_wasm_workspace_root(); + let wasm_workspace = wasm_workspace_root.join("wbuild"); + + // Lock the workspace exclusively for us + let _lock = WorkspaceLock::new(&wasm_workspace_root); + + let project = create_project(cargo_manifest, &wasm_workspace); + create_wasm_workspace_project(&wasm_workspace); + + build_project(&project); + let (wasm_binary, bloaty) = compact_wasm_file(&project, cargo_manifest, &wasm_workspace); + + generate_rerun_if_changed_instructions(cargo_manifest, &project, &wasm_workspace); + + (wasm_binary, bloaty) +} + +/// Find the `Cargo.lock` relative to the `OUT_DIR` environment variable. +/// +/// If the `Cargo.lock` cannot be found, we emit a warning and return `None`. +fn find_cargo_lock(cargo_manifest: &Path) -> Option { + fn find_impl(mut path: PathBuf) -> Option { + loop { + if path.join("Cargo.lock").exists() { + return Some(path.join("Cargo.lock")) + } + + if !path.pop() { + return None; + } + } + } + + if let Some(path) = find_impl(build_helper::out_dir()) { + return Some(path); + } + + if let Some(path) = find_impl(cargo_manifest.to_path_buf()) { + return Some(path); + } + + build_helper::warning!( + "Could not find `Cargo.lock` for `{}`, while searching from `{}`.", + cargo_manifest.display(), + build_helper::out_dir().display() + ); + None +} + +/// Extract the crate name from the given `Cargo.toml`. +fn get_crate_name(cargo_manifest: &Path) -> String { + let cargo_toml: Table = toml::from_str( + &fs::read_to_string(cargo_manifest).expect("File exists as checked before; qed") + ).expect("Cargo manifest is a valid toml file; qed"); + + let package = cargo_toml + .get("package") + .and_then(|t| t.as_table()) + .expect("`package` key exists in valid `Cargo.toml`; qed"); + + package.get("name").and_then(|p| p.as_str()).map(ToOwned::to_owned).expect("Package name exists; qed") +} + +/// Returns the name for the wasm binary. +fn get_wasm_binary_name(cargo_manifest: &Path) -> String { + get_crate_name(cargo_manifest).replace('-', "_") +} + +/// Returns the root path of the wasm workspace. +fn get_wasm_workspace_root() -> PathBuf { + let mut out_dir = build_helper::out_dir(); + + loop { + match out_dir.parent() { + Some(parent) if out_dir.ends_with("build") => return parent.to_path_buf(), + _ => if !out_dir.pop() { + break; + } + } + } + + panic!("Could not find target dir in: {}", build_helper::out_dir().display()) +} + +fn create_wasm_workspace_project(wasm_workspace: &Path) { + let members = WalkDir::new(wasm_workspace) + .min_depth(1) + .max_depth(1) + .into_iter() + .filter_map(|p| p.ok()) + .map(|d| d.into_path()) + .filter(|p| p.is_dir() && !p.ends_with("target")) + .filter_map(|p| p.file_name().map(|f| f.to_owned()).and_then(|s| s.into_string().ok())) + .map(|s| format!("\"{}\", ", s)) + .collect::(); + + fs::write( + wasm_workspace.join("Cargo.toml"), + format!( + r#" + [profile.release] + panic = "abort" + lto = true + + [profile.dev] + panic = "abort" + + [workspace] + members = [ {members} ] + "#, + members = members, + ) + ).expect("WASM workspace `Cargo.toml` writing can not fail; qed"); +} + +/// Create the project used to build the wasm binary. +/// +/// # Returns +/// The path to the created project. +fn create_project(cargo_manifest: &Path, wasm_workspace: &Path) -> PathBuf { + let crate_name = get_crate_name(cargo_manifest); + let crate_path = cargo_manifest.parent().expect("Parent path exists; qed"); + let wasm_binary = get_wasm_binary_name(cargo_manifest); + let project_folder = wasm_workspace.join(&crate_name); + + fs::create_dir_all(project_folder.join("src")).expect("Wasm project dir create can not fail; qed"); + + fs::write( + project_folder.join("Cargo.toml"), + format!( + r#" + [package] + name = "{crate_name}-wasm" + version = "1.0.0" + edition = "2018" + + [lib] + name = "{wasm_binary}" + crate-type = ["cdylib"] + + [dependencies] + wasm_project = {{ package = "{crate_name}", path = "{crate_path}", default-features = false, features = [ "no_std" ] }} + "#, + crate_name = crate_name, + crate_path = crate_path.display(), + wasm_binary = wasm_binary, + ) + ).expect("Project `Cargo.toml` writing can not fail; qed"); + + fs::write( + project_folder.join("src/lib.rs"), + "#![no_std] pub use wasm_project::*;", + ).expect("Project `lib.rs` writing can not fail; qed"); + + if let Some(crate_lock_file) = find_cargo_lock(cargo_manifest) { + // Use the `Cargo.lock` of the main project. + fs::copy(crate_lock_file, wasm_workspace.join("Cargo.lock")) + .expect("Copying the `Cargo.lock` can not fail; qed"); + } + + project_folder +} + +/// Returns if the project should be built as a release. +fn is_release_build() -> bool { + if let Ok(var) = env::var(crate::WASM_BUILD_TYPE_ENV) { + match var.as_str() { + "release" => true, + "debug" => false, + var => panic!( + "Unexpected value for `{}` env variable: {}\nOne of the following are expected: `debug` or `release`.", + crate::WASM_BUILD_TYPE_ENV, + var, + ), + } + } else { + !build_helper::debug() + } +} + +/// Build the project to create the WASM binary. +fn build_project(project: &Path) { + let manifest_path = project.join("Cargo.toml"); + let mut build_cmd = crate::get_nightly_cargo(); + + let rustflags = format!( + "-C link-arg=--export-table {}", + env::var(crate::WASM_BUILD_RUSTFLAGS_ENV).unwrap_or_default(), + ); + + build_cmd.args(&["build", "--target=wasm32-unknown-unknown"]) + .arg(format!("--manifest-path={}", manifest_path.display())) + .env("RUSTFLAGS", rustflags) + // We don't want to call ourselves recursively + .env(crate::SKIP_BUILD_ENV, ""); + + if is_release_build() { + build_cmd.arg("--release"); + }; + + println!("Executing build command: {:?}", build_cmd); + + match build_cmd.status().map(|s| s.success()) { + Ok(true) => {}, + // Use `process.exit(1)` to have a clean error output. + _ => process::exit(1), + } +} + +/// Compact the WASM binary using `wasm-gc`. Returns the path to the bloaty WASM binary. +fn compact_wasm_file( + project: &Path, + cargo_manifest: &Path, + wasm_workspace: &Path, +) -> (WasmBinary, WasmBinaryBloaty) { + let target = if is_release_build() { "release" } else { "debug" }; + let wasm_binary = get_wasm_binary_name(cargo_manifest); + let wasm_file = wasm_workspace.join("target/wasm32-unknown-unknown") + .join(target) + .join(format!("{}.wasm", wasm_binary)); + let wasm_compact_file = project.join(format!("{}.compact.wasm", wasm_binary)); + + let res = Command::new("wasm-gc") + .arg(&wasm_file) + .arg(&wasm_compact_file) + .status() + .map(|s| s.success()); + + if !res.unwrap_or(false) { + panic!("Failed to compact generated WASM binary."); + } + + (WasmBinary(wasm_compact_file), WasmBinaryBloaty(wasm_file)) +} + +/// Generate the `rerun-if-changed` instructions for cargo to make sure that the WASM binary is +/// rebuilt when needed. +fn generate_rerun_if_changed_instructions( + cargo_manifest: &Path, + project_folder: &Path, + wasm_workspace: &Path, +) { + // Rerun `build.rs` if the `Cargo.lock` changes + if let Some(cargo_lock) = find_cargo_lock(cargo_manifest) { + rerun_if_changed(cargo_lock); + } + + let metadata = MetadataCommand::new() + .manifest_path(project_folder.join("Cargo.toml")) + .exec() + .expect("`cargo metadata` can not fail!"); + + // Make sure that if any file/folder of a depedency change, we need to rerun the `build.rs` + metadata.packages.into_iter() + .filter(|package| !package.manifest_path.starts_with(wasm_workspace)) + .for_each(|package| { + let mut manifest_path = package.manifest_path; + if manifest_path.ends_with("Cargo.toml") { + manifest_path.pop(); + } + + rerun_if_changed(&manifest_path); + + WalkDir::new(manifest_path) + .into_iter() + .filter_map(|p| p.ok()) + .for_each(|p| rerun_if_changed(p.path())); + }); + + // Register our env variables + println!("cargo:rerun-if-env-changed={}", crate::SKIP_BUILD_ENV); + println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_TYPE_ENV); + println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_RUSTFLAGS_ENV); +} diff --git a/node-template/Cargo.toml b/node-template/Cargo.toml index e78bb2d27e4447142823e27a7c90eda5cea80d44..4c85ef38174cad7a05336c8a5d37de1f053dda87 100644 --- a/node-template/Cargo.toml +++ b/node-template/Cargo.toml @@ -17,8 +17,8 @@ log = "0.4" tokio = "0.1" exit-future = "0.1" parking_lot = "0.8.0" -parity-codec = "3.3" -trie-root = "0.12.2" +parity-codec = "4.1.1" +trie-root = "0.14.0" sr-io = { path = "../core/sr-io" } substrate-cli = { path = "../core/cli" } primitives = { package = "substrate-primitives", path = "../core/primitives" } diff --git a/node-template/README.md b/node-template/README.md index 6924fa55762b2b4b0d284d7afd2de771d77c7cc0..497ed84a52bcd33920af114154ed34e17d5cde3d 100644 --- a/node-template/README.md +++ b/node-template/README.md @@ -16,12 +16,6 @@ Install required tools: ./scripts/init.sh ``` -Build the WebAssembly binary: - -```bash -./scripts/build.sh -``` - Build all native code: ```bash diff --git a/node-template/build.rs b/node-template/build.rs index afc39d3b63c5eab92b362d436f3f2b4786088ed0..bab46f579d06830f81a91607841bdd64e03e1eb8 100644 --- a/node-template/build.rs +++ b/node-template/build.rs @@ -1,8 +1,24 @@ +use std::{env, path::PathBuf}; + use vergen::{ConstantsFlags, generate_cargo_keys}; const ERROR_MSG: &str = "Failed to generate metadata files"; fn main() { - generate_cargo_keys(ConstantsFlags::all()).expect(ERROR_MSG); - println!("cargo:rerun-if-changed=.git/HEAD"); + generate_cargo_keys(ConstantsFlags::SHA_SHORT).expect(ERROR_MSG); + + let mut manifest_dir = PathBuf::from( + env::var("CARGO_MANIFEST_DIR").expect("`CARGO_MANIFEST_DIR` is always set by cargo.") + ); + + while manifest_dir.parent().is_some() { + if manifest_dir.join(".git/HEAD").exists() { + println!("cargo:rerun-if-changed={}", manifest_dir.join(".git/HEAD").display()); + return + } + + manifest_dir.pop(); + } + + println!("cargo:warning=Could not find `.git/HEAD` from manifest dir!"); } diff --git a/node-template/runtime/Cargo.toml b/node-template/runtime/Cargo.toml index 90cc85317adb287a0a50c3c9c5722c7f0630efce..375a0ad64eb0df7f9d99d5b8a621b818493a2aad 100644 --- a/node-template/runtime/Cargo.toml +++ b/node-template/runtime/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] serde = { version = "1.0", optional = true, features = ["derive"] } safe-mix = { version = "1.0", default-features = false } -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } rstd = { package = "sr-std", path = "../../core/sr-std", default_features = false } runtime-io = { package = "sr-io", path = "../../core/sr-io", default_features = false } version = { package = "sr-version", path = "../../core/sr-version", default_features = false } @@ -25,6 +25,9 @@ client = { package = "substrate-client", path = "../../core/client", default_fea consensus-aura = { package = "substrate-consensus-aura-primitives", path = "../../core/consensus/aura/primitives", default_features = false } offchain-primitives = { package = "substrate-offchain-primitives", path = "../../core/offchain/primitives", default-features = false } +[build-dependencies] +wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.2" } + [features] default = ["std"] std = [ @@ -48,3 +51,4 @@ std = [ "consensus-aura/std", "offchain-primitives/std", ] +no_std = [] diff --git a/core/test-runtime/wasm/src/lib.rs b/node-template/runtime/build.rs similarity index 76% rename from core/test-runtime/wasm/src/lib.rs rename to node-template/runtime/build.rs index 6620f276d0397fbd44840aef3f1500b2877798cb..ccf58b138f0799ca2cfacc70988c173b096012f1 100644 --- a/core/test-runtime/wasm/src/lib.rs +++ b/node-template/runtime/build.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// Copyright 2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -14,8 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! The Substrate test runtime reexported for WebAssembly compile. +use wasm_builder_runner::{build_current_project, WasmBuilderSource}; -#![cfg_attr(not(feature = "std"), no_std)] - -pub use substrate_test_runtime::*; +fn main() { + build_current_project("wasm_binary.rs", WasmBuilderSource::Crates("1.0.4")); +} diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index 9b99e7f08f49594952bec0b8f3f0f8754bc1b574..865299285af520ec26611533602a108719463a18 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -4,6 +4,10 @@ // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. #![recursion_limit="256"] +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + #[cfg(feature = "std")] use serde::{Serialize, Deserialize}; use parity_codec::{Encode, Decode}; @@ -29,8 +33,7 @@ pub use runtime_primitives::BuildStorage; pub use timestamp::Call as TimestampCall; pub use balances::Call as BalancesCall; pub use runtime_primitives::{Permill, Perbill}; -pub use timestamp::BlockPeriod; -pub use support::{StorageValue, construct_runtime}; +pub use support::{StorageValue, construct_runtime, parameter_types}; /// Alias to the signature scheme used for Aura authority signatures. pub type AuraSignature = ed25519::Signature; @@ -107,6 +110,10 @@ pub fn native_version() -> NativeVersion { } } +parameter_types! { + pub const BlockHashCount: BlockNumber = 250; +} + impl system::Trait for Runtime { /// The identifier used to distinguish between accounts. type AccountId = AccountId; @@ -126,6 +133,8 @@ impl system::Trait for Runtime { type Event = Event; /// The ubiquitous origin type. type Origin = Origin; + /// Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount = BlockHashCount; } impl aura::Trait for Runtime { @@ -145,10 +154,22 @@ impl indices::Trait for Runtime { type Event = Event; } +parameter_types! { + pub const MinimumPeriod: u64 = 5; +} impl timestamp::Trait for Runtime { /// A timestamp: seconds since the unix epoch. type Moment = u64; type OnTimestampSet = Aura; + type MinimumPeriod = MinimumPeriod; +} + +parameter_types! { + pub const ExistentialDeposit: u128 = 500; + pub const TransferFee: u128 = 0; + pub const CreationFee: u128 = 0; + pub const TransactionBaseFee: u128 = 1; + pub const TransactionByteFee: u128 = 0; } impl balances::Trait for Runtime { @@ -164,6 +185,11 @@ impl balances::Trait for Runtime { type TransactionPayment = (); type DustRemoval = (); type TransferPayment = (); + type ExistentialDeposit = ExistentialDeposit; + type TransferFee = TransferFee; + type CreationFee = CreationFee; + type TransactionBaseFee = TransactionBaseFee; + type TransactionByteFee = TransactionByteFee; } impl sudo::Trait for Runtime { @@ -183,8 +209,8 @@ construct_runtime!( NodeBlock = opaque::Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: system::{default, Config}, - Timestamp: timestamp::{Module, Call, Storage, Config, Inherent}, + System: system::{Module, Call, Storage, Config, Event}, + Timestamp: timestamp::{Module, Call, Storage, Inherent}, Aura: aura::{Module, Config, Inherent(Timestamp)}, Indices: indices::{default, Config}, Balances: balances, diff --git a/node-template/runtime/src/template.rs b/node-template/runtime/src/template.rs index c8b75f43f5f5b5f75b34cad4391cdb68ea5307ee..05257d2a53341d73face18856c724059d6b60947 100644 --- a/node-template/runtime/src/template.rs +++ b/node-template/runtime/src/template.rs @@ -46,7 +46,7 @@ decl_module! { // TODO: Code to execute when something calls this. // For example: the following line stores the passed in u32 in the storage - >::put(something); + Something::put(something); // here we are raising the Something event Self::deposit_event(RawEvent::SomethingStored(something, who)); @@ -71,12 +71,8 @@ mod tests { use runtime_io::with_externalities; use primitives::{H256, Blake2Hasher}; - use support::{impl_outer_origin, assert_ok}; - use runtime_primitives::{ - BuildStorage, - traits::{BlakeTwo256, IdentityLookup}, - testing::Header, - }; + use support::{impl_outer_origin, assert_ok, parameter_types}; + use runtime_primitives::{traits::{BlakeTwo256, IdentityLookup}, testing::Header}; impl_outer_origin! { pub enum Origin for Test {} @@ -87,6 +83,9 @@ mod tests { // configuration traits of modules we want to use. #[derive(Clone, Eq, PartialEq)] pub struct Test; + parameter_types! { + pub const BlockHashCount: u64 = 250; + } impl system::Trait for Test { type Origin = Origin; type Index = u64; @@ -97,6 +96,7 @@ mod tests { type Lookup = IdentityLookup; type Header = Header; type Event = (); + type BlockHashCount = BlockHashCount; } impl Trait for Test { type Event = (); @@ -106,7 +106,7 @@ mod tests { // This function basically just builds a genesis storage key/value store according to // our desired mockup. fn new_test_ext() -> runtime_io::TestExternalities { - system::GenesisConfig::::default().build_storage().unwrap().0.into() + system::GenesisConfig::default().build_storage::().unwrap().0.into() } #[test] diff --git a/node-template/runtime/wasm/Cargo.lock b/node-template/runtime/wasm/Cargo.lock deleted file mode 100644 index ae323203f61f9269b61e49962d70148a39a4e063..0000000000000000000000000000000000000000 --- a/node-template/runtime/wasm/Cargo.lock +++ /dev/null @@ -1,3816 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "adler32" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "aes-ctr" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aes-soft" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aesni" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aho-corasick" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aio-limited" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "arrayref" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "arrayvec" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "asn1_der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "asn1_der_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "asn1_der_derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "atty" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "autocfg" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "backtrace" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "backtrace-sys" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "base58" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "base64" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bigint" -version = "4.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bitflags" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitmask" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "blake2" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "blake2-rfc" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "block-buffer" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "block-cipher-trait" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "block-padding" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bs58" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "build_const" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bumpalo" -version = "2.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byte-tools" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byteorder" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byteorder" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bytes" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "c_linked_list" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cc" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cfg-if" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "chrono" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "clear_on_drop" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "constant_time_eq" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "crc" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crc32fast" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-channel" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-deque" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-deque" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-deque" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-queue" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-utils" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-utils" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crunchy" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "crypto-mac" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crypto-mac" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ctr" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cuckoofilter" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "curve25519-dalek" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "data-encoding" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "derive_more" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "digest" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "digest" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "dns-parser" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ed25519-dalek" -version = "1.0.0-pre.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "curve25519-dalek 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "either" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "elastic-array" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "env_logger" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "environmental" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "erased-serde" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "failure" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "failure_derive" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fixed-hash" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "flate2" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fnv" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "futures" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "futures-cpupool" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "gcc" -version = "0.3.55" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "generic-array" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "generic-array" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "get_if_addrs" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "c_linked_list 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "get_if_addrs-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "get_if_addrs-sys" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hash-db" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "hash256-std-hasher" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hashbrown" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hashmap_core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "heapsize" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "heck" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hex" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "hex-literal" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "hex-literal-impl 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hex-literal-impl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hmac" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crypto-mac 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hmac" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hmac-drbg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "http" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "httparse" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "humantime" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "idna" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "impl-codec" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "impl-serde" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "impl-serde" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "integer-sqrt" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "iovec" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ipnet" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "itoa" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "js-sys" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "keccak" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kvdb" -version = "0.1.0" -source = "git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d#b0317f649ab2c665b7987b8475878fc4d2e1f81d" -dependencies = [ - "elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)", -] - -[[package]] -name = "lazy_static" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.55" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libp2p" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core-derive 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-deflate 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-dns 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-floodsub 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-identify 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-kad 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-mdns 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-mplex 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-noise 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-ping 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-plaintext 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-ratelimit 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-secio 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-tcp 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-uds 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-wasm-ext 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-websocket 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-yamux 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multihash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-core" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "asn1_der 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "multistream-select 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multihash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rw-stream-sink 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-core-derive" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-deflate" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-dns" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-dns-unofficial 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-floodsub" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "cuckoofilter 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-identify" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-kad" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multihash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-mdns" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "dns-parser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-mplex" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-noise" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "curve25519-dalek 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "snow 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "x25519-dalek 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-ping" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-plaintext" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-ratelimit" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aio-limited 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-secio" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "asn1_der 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rw-stream-sink 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "twofish 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-futures 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-tcp" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "get_if_addrs 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ipnet 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tk-listen 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-uds" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-wasm-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-futures 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-websocket" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rw-stream-sink 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "soketto 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-rustls 0.10.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki-roots 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-yamux" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "yamux 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libsecp256k1" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac-drbg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lock_api" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lock_api" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "log" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "matches" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "memchr" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "memoffset" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "memory-db" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hashmap_core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "memory_units" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "merlin" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miniz-sys" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miniz_oxide" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miniz_oxide_c_api" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mio" -version = "0.6.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mio-uds" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miow" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (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 = "multistream-select" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "net2" -version = "0.2.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "node-template-runtime" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "sr-version 2.0.0", - "srml-aura 2.0.0", - "srml-balances 2.0.0", - "srml-executive 2.0.0", - "srml-indices 2.0.0", - "srml-sudo 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", - "srml-timestamp 2.0.0", - "substrate-client 2.0.0", - "substrate-consensus-aura-primitives 2.0.0", - "substrate-offchain-primitives 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "node-template-runtime-wasm" -version = "2.0.0" -dependencies = [ - "node-template-runtime 2.0.0", -] - -[[package]] -name = "nodrop" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "nohash-hasher" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "nom" -version = "4.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-integer" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-traits" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num_cpus" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "numtoa" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "once_cell" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "opaque-debug" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "owning_ref" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "owning_ref" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-bytes" -version = "0.1.0" -source = "git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d#b0317f649ab2c665b7987b8475878fc4d2e1f81d" - -[[package]] -name = "parity-codec" -version = "3.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-codec-derive" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-multiaddr" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multihash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-multihash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "blake2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-send-wrapper" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "parity-wasm" -version = "0.31.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot_core" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot_core" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "paste" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "paste-impl" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-hack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "pbkdf2" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "percent-encoding" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "primitive-types" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fixed-hash 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-codec 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "uint 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro-crate" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro-hack" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro-hack-impl" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "protobuf" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quick-error" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quick-error" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quote" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rayon" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rayon-core" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "redox_syscall" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_termios" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex-syntax" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ring" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rustc-hex" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustls" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "sct 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rw-stream-sink" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ryu" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "safe-mix" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "schnorrkel" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "curve25519-dalek 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "merlin 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "scopeguard" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "scopeguard" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "sct" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "send_wrapper" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "serde" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_derive" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_json" -version = "1.0.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sha-1" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sha1" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "sha2" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sha2" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sha3" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "slab" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "slog" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "slog-json" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "slog-scope" -version = "4.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "smallvec" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "snow" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "static_slice 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "soketto" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sourcefile" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "spin" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "sr-api-macros" -version = "2.0.0" -dependencies = [ - "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sr-io" -version = "2.0.0" -dependencies = [ - "environmental 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-std 2.0.0", - "substrate-primitives 2.0.0", - "substrate-state-machine 2.0.0", - "substrate-trie 2.0.0", - "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sr-primitives" -version = "2.0.0" -dependencies = [ - "integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-std 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "sr-std" -version = "2.0.0" -dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sr-version" -version = "2.0.0" -dependencies = [ - "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", -] - -[[package]] -name = "srml-aura" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-session 2.0.0", - "srml-staking 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", - "srml-timestamp 2.0.0", - "substrate-consensus-aura-primitives 2.0.0", - "substrate-inherents 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "srml-balances" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", - "substrate-keyring 2.0.0", -] - -[[package]] -name = "srml-executive" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", -] - -[[package]] -name = "srml-indices" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", - "substrate-keyring 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "srml-metadata" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-std 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "srml-session" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", - "srml-timestamp 2.0.0", -] - -[[package]] -name = "srml-staking" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-session 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", - "substrate-keyring 2.0.0", -] - -[[package]] -name = "srml-sudo" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-support 2.0.0", - "srml-support-procedural 2.0.0", - "srml-system 2.0.0", -] - -[[package]] -name = "srml-support" -version = "2.0.0" -dependencies = [ - "bitmask 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-metadata 2.0.0", - "srml-support-procedural 2.0.0", - "substrate-inherents 2.0.0", -] - -[[package]] -name = "srml-support-procedural" -version = "2.0.0" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-api-macros 2.0.0", - "srml-support-procedural-tools 2.0.0", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "srml-support-procedural-tools" -version = "2.0.0" -dependencies = [ - "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "srml-support-procedural-tools-derive 2.0.0", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "srml-support-procedural-tools-derive" -version = "2.0.0" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "srml-system" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-support 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "srml-timestamp" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", - "substrate-inherents 2.0.0", -] - -[[package]] -name = "stable_deref_trait" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "static_assertions" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "static_slice" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "stream-cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "strum" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "strum_macros" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-bip39" -version = "0.2.1" -source = "git+https://github.com/paritytech/substrate-bip39#44307fda4ea17fe97aeb93af317fbc8f6ed34193" -dependencies = [ - "hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-client" -version = "2.0.0" -dependencies = [ - "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "kvdb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-api-macros 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "sr-version 2.0.0", - "substrate-consensus-common 2.0.0", - "substrate-executor 2.0.0", - "substrate-inherents 2.0.0", - "substrate-keyring 2.0.0", - "substrate-primitives 2.0.0", - "substrate-state-machine 2.0.0", - "substrate-telemetry 2.0.0", - "substrate-trie 2.0.0", -] - -[[package]] -name = "substrate-consensus-aura-primitives" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "substrate-client 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "substrate-consensus-common" -version = "2.0.0" -dependencies = [ - "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "sr-version 2.0.0", - "substrate-inherents 2.0.0", - "substrate-primitives 2.0.0", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-executor" -version = "2.0.0" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-version 2.0.0", - "substrate-panic-handler 2.0.0", - "substrate-primitives 2.0.0", - "substrate-serializer 2.0.0", - "substrate-state-machine 2.0.0", - "substrate-trie 2.0.0", - "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-inherents" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", -] - -[[package]] -name = "substrate-keyring" -version = "2.0.0" -dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "strum 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "strum_macros 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "substrate-offchain-primitives" -version = "2.0.0" -dependencies = [ - "sr-primitives 2.0.0", - "substrate-client 2.0.0", -] - -[[package]] -name = "substrate-panic-handler" -version = "2.0.0" -dependencies = [ - "backtrace 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-primitives" -version = "2.0.0" -dependencies = [ - "base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hash256-std-hasher 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "primitive-types 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-std 2.0.0", - "substrate-bip39 0.2.1 (git+https://github.com/paritytech/substrate-bip39)", - "tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "twox-hash 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-serializer" -version = "2.0.0" -dependencies = [ - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-state-machine" -version = "2.0.0" -dependencies = [ - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "substrate-panic-handler 2.0.0", - "substrate-primitives 2.0.0", - "substrate-trie 2.0.0", - "trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-telemetry" -version = "2.0.0" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-scope 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-trie" -version = "2.0.0" -dependencies = [ - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "memory-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-std 2.0.0", - "substrate-primitives 2.0.0", - "trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "subtle" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "subtle" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "syn" -version = "0.15.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "synstructure" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "termcolor" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "termion" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread_local" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "time" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tiny-bip39" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tiny-keccak" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tk-listen" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-trace-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-codec" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-current-thread" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-dns-unofficial" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-executor" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-fs" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-io" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-reactor" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-rustls" -version = "0.10.0-alpha.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustls 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-sync" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-tcp" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-threadpool" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-timer" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-trace-core" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-udp" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-uds" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "toml" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "trie-db" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hashmap_core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "trie-root" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "twofish" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "twox-hash" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "typenum" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "ucd-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "uint" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-segmentation" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unsigned-varint" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "untrusted" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "url" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "utf8-ranges" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "wasm-bindgen" -version = "0.2.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "wasm-bindgen-macro 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bumpalo 2.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro-support 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-backend 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.45" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "wasm-bindgen-webidl" -version = "0.2.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-backend 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "weedle 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasm-timer" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "send_wrapper 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasmi" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmi-validation 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasmi-validation" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "web-sys" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-webidl 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "webpki" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "webpki-roots" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "weedle" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-util" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "wincolor" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "x25519-dalek" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "curve25519-dalek 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "yamux" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "nohash-hasher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zeroize" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "zeroize" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "zeroize_derive 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zeroize_derive" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[metadata] -"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" -"checksum aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2e5b0458ea3beae0d1d8c0f3946564f8e10f90646cf78c06b4351052058d1ee" -"checksum aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" -"checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" -"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" -"checksum aio-limited 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f10b352bc3fc08ae24dc5d2d3ddcac153678533986122dc283d747b12071000" -"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" -"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" -"checksum asn1_der 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9893d63fc3b1c44231e667da6836a33f27d8b6b3bdc82f83da5dfd579d1b6528" -"checksum asn1_der_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e7f92edafad155aff997fa5b727c6429b91e996b5a5d62a2b0adbae1306b5fe" -"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" -"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" -"checksum backtrace 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)" = "1a13fc43f04daf08ab4f71e3d27e1fc27fc437d3e95ac0063a796d92fb40f39b" -"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" -"checksum base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" -"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" -"checksum bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebecac13b3c745150d7b6c3ea7572d372f09d627c2077e893bf26c5c7f70d282" -"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum bitmask 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5da9b3d9f6f585199287a473f4f8dfab6566cf827d15c00c219f53c645687ead" -"checksum blake2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91721a6330935673395a0607df4d49a9cb90ae12d259f1b3e0a3f6e1d486872e" -"checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" -"checksum block-buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1339a1042f5d9f295737ad4d9a6ab6bf81c84a933dba110b9200cd6d1448b814" -"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" -"checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" -"checksum bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0de79cfb98e7aa9988188784d8664b4b5dad6eaaa0863b91d9a4ed871d4f7a42" -"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" -"checksum bumpalo 2.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "84dca3afd8e01b9526818b7963e5b4916063b3cdf9f10cf6b73ef0bd0ec37aa5" -"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" -"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" -"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" -"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" -"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -"checksum c_linked_list 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4964518bd3b4a8190e832886cdc0da9794f12e8e6c1613a9e90ff331c4c8724b" -"checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d" -"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" -"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" -"checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" -"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" -"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" -"checksum crossbeam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad4c7ea749d9fb09e23c5cb17e3b70650860553a0e2744e38446b1803bf7db94" -"checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" -"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" -"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" -"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" -"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" -"checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" -"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" -"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" -"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" -"checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" -"checksum crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -"checksum crypto-mac 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "779015233ac67d65098614aec748ac1c756ab6677fa2e14cf8b37c08dfed1198" -"checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" -"checksum ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "022cd691704491df67d25d006fe8eca083098253c4d43516c2206479c58c6736" -"checksum cuckoofilter 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd43f7cfaffe0a386636a10baea2ee05cc50df3b77bea4a456c9572a939bf1f" -"checksum curve25519-dalek 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "750226d75fc2f5a8daec6e7477624e258674023eb73d8d647f63b943ca182a4a" -"checksum data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f47ca1860a761136924ddd2422ba77b2ea54fe8cc75b9040804a0d9d32ad97" -"checksum derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6d944ac6003ed268757ef1ee686753b57efc5fcf0ebe7b64c9fc81e7e32ff839" -"checksum digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5b29bf156f3f4b3c4f610a25ff69370616ae6e0657d416de22645483e72af0a" -"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" -"checksum dns-parser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea" -"checksum ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81956bcf7ef761fb4e1d88de3fa181358a0d26cbcb9755b587a08f9119824b86" -"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" -"checksum elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "073be79b6538296faf81c631872676600616073817dd9a440c477ad09b408983" -"checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a" -"checksum environmental 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c7464757b80de8930c91c9afe77ddce501826bf9d134a87db2c67d9dc177e2c" -"checksum erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3beee4bc16478a1b26f2e80ad819a52d24745e292f521a63c16eea5f74b7eb60" -"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" -"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" -"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" -"checksum fixed-hash 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d1a683d1234507e4f3bf2736eeddf0de1dc65996dc0164d57eba0a74bcf29489" -"checksum flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f87e68aa82b2de08a6e037f1385455759df6e445a8df5e005b4297191dbf18aa" -"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)" = "a2037ec1c6c1c4f79557762eab1f7eae1f64f6cb418ace90fae88f0942b60139" -"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" -"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" -"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" -"checksum generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fceb69994e330afed50c93524be68c42fa898c2d9fd4ee8da03bd7363acd26f2" -"checksum get_if_addrs 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "abddb55a898d32925f3148bd281174a68eeb68bbfd9a5938a57b18f506ee4ef7" -"checksum get_if_addrs-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0d04f9fb746cf36b191c00f3ede8bde9c8e64f9f4b05ae2694a9ccf5e3f5ab48" -"checksum hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ba7fb417e5c470acdd61068c79767d0e65962e70836cf6c9dfd2409f06345ce0" -"checksum hash256-std-hasher 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b2027c19ec91eb304999abae7307d225cf93be42af53b0039f76e98ed5af86" -"checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da" -"checksum hashmap_core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8e04cb7a5051270ef3fa79f8c7604d581ecfa73d520e74f554e45541c4b5881a" -"checksum heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461" -"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" -"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" -"checksum hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ddc2928beef125e519d69ae1baa8c37ea2e0d3848545217f6db0179c5eb1d639" -"checksum hex-literal-impl 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "520870c3213943eb8d7803e80180d12a6c7ceb4ae74602544529d1643dc4ddda" -"checksum hmac 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a13f4163aa0c5ca1be584aace0e2212b2e41be5478218d4f657f5f778b2ae2a" -"checksum hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f127a908633569f208325f86f71255d3363c79721d7f9fe31cd5569908819771" -"checksum hmac-drbg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fe727d41d2eec0a6574d887914347e5ff96a3b87177817e2a9820c5c87fecc2" -"checksum http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "eed324f0f0daf6ec10c474f150505af2c143f251722bf9dbd1261bd1f2ee2c1a" -"checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" -"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" -"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -"checksum impl-codec 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2050d823639fbeae26b2b5ba09aca8907793117324858070ade0673c49f793b" -"checksum impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5158079de9d4158e0ce1de3ae0bd7be03904efc40b3d7dd8b8c301cbf6b52b56" -"checksum impl-serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d26be4b97d738552ea423f76c4f681012ff06c3fa36fa968656b3679f60b4a1" -"checksum integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ea155abb3ba6f382a75f1418988c05fe82959ed9ce727de427f9cfd425b0c903" -"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" -"checksum ipnet 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e61c2da0d0f700c77d2d313dbf4f93e41d235fa12c6681fee06621036df4c2af" -"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" -"checksum js-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "9987e7c13a91d9cf0efe59cca48a3a7a70e2b11695d5a4640f85ae71e28f5e73" -"checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum kvdb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" -"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "42914d39aad277d9e176efbdad68acb1d5443ab65afe0e0e4f0d49352a950880" -"checksum libp2p 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6abde4e6fc777dc06ae2a15202ddedb1a38d7c71ed16bc10fa704b03f73aec37" -"checksum libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b4ceb4791289534d4c1ad8e4bd3c6f06d3670efa55ce71482951a287df93ddd1" -"checksum libp2p-core-derive 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "851a59dcaab66c96777ae0cace96de88a700243c3b8360ab51c7e093f3727066" -"checksum libp2p-deflate 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "902b44e92e1f8b7e697b3a186d15c841e0e38037f14286513207a5407650a635" -"checksum libp2p-dns 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71a6630a84552b39e5f752e1f6a951d31f3211079465d2e7af73491b6f48fc3f" -"checksum libp2p-floodsub 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9fced4da0c31e0dc8a759472c65fab41db40c01de2d93bc45e1431c13f0564f0" -"checksum libp2p-identify 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1ba5e882d72c71cdf77f45ab68dd715451d3b78a23085f8d385c7a31ec1b4272" -"checksum libp2p-kad 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d71966dbbb4cedcfcdb1d4c87d5dbb6f3f07b465d1ca74f2624256669997d1f2" -"checksum libp2p-mdns 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdbdaea6f0049cc09ba5db00308f5b93105a8a33b65ba2e36bd35da707850ea2" -"checksum libp2p-mplex 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b351bfd67e97154e7b60f62402237671486c8a89f83eabdb6838f37d4d5f006" -"checksum libp2p-noise 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44324032b2f9260d2b862c741d79d250dc02298dbba56354a992528a826ee2d5" -"checksum libp2p-ping 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1ac43ffd01de4210cf1b969bbb55a008c77f9ec22b74df26a6590bb6bd4c93f" -"checksum libp2p-plaintext 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0506e10770bcbcb59f2a6154ce93c8fd5cb9730b6ceb5aa1463164af1fd0b9c6" -"checksum libp2p-ratelimit 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3886b79a35c0348497bab763517a9a2b4965173f4b4c7438d59f1e4dcf5122ff" -"checksum libp2p-secio 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b811272e5cd86d39bd71fb94687025d9802b13daf0998ebe0d3f2885c636c51a" -"checksum libp2p-tcp 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b2c54cb75f17557de6ce0149aa03e729455e2d240f84d854272bc4b11012a324" -"checksum libp2p-uds 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fbedf4a1e72a5f67523915414e9e12d71d128731873f0f24d8b878398fb47aa4" -"checksum libp2p-wasm-ext 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c1f615b56aa2a6f4ec07bf9667be9fff8877b9c5bd5335601af47490eda341" -"checksum libp2p-websocket 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a0d1bfe60577558f48a9fdf9f35c0ee2dc5baa01f685ff847d3b5cf4f12ee135" -"checksum libp2p-yamux 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bf4bfc7ff127cd622502dbe56f10513dd6776b970e33d8ebb6e367f0752324f6" -"checksum libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "688e8d65e495567c2c35ea0001b26b9debf0b4ea11f8cccc954233b75fc3428a" -"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" -"checksum lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed946d4529956a20f2d63ebe1b69996d5a2137c91913fe3ebbeff957f5bca7ff" -"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" -"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" -"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum memory-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7623b01a4f1b7acb7cf8e3f678f05e15e6ae26cb0b738dfeb5cc186fd6b82ef4" -"checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" -"checksum merlin 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8c39467de91b004f5b9c06fac5bbc8e7d28309a205ee66905166b70804a71fea" -"checksum miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9e3ae51cea1576ceba0dde3d484d30e6e5b86dee0b2d412fe3a16a15c98202" -"checksum miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c468f2369f07d651a5d0bb2c9079f8488a66d5466efe42d0c5c6466edcb7f71e" -"checksum miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7fe927a42e3807ef71defb191dc87d4e24479b221e67015fe38ae2b7b447bab" -"checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" -"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" -"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum multistream-select 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f989d40aab0ed0d83c1cdb4856b5790e980b96548d1a921f280e985eb049f38d" -"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" -"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" -"checksum nohash-hasher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0d138afcce92d219ccb6eb53d9b1e8a96ac0d633cfd3c53cd9856d96d1741bb8" -"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" -"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" -"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" -"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" -"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" -"checksum once_cell 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "532c29a261168a45ce28948f9537ddd7a5dd272cc513b3017b1e82a88f962c37" -"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" -"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" -"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" -"checksum parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" -"checksum parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dcb43c05fb71c03b4ea7327bf15694da1e0f23f19d5b1e95bab6c6d74097e336" -"checksum parity-codec-derive 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "00a486fd383382ddcb2de928364b1f82571c1e48274fc43b7667a4738ee4056c" -"checksum parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "045b3c7af871285146300da35b1932bb6e4639b66c7c98e85d06a32cbc4e8fa7" -"checksum parity-multihash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05d6a68e07ab34a9e87bd8dd4936f6bb5be21e4f6dbcdbaf04d8e854eba0af01" -"checksum parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f" -"checksum parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)" = "511379a8194230c2395d2f5fa627a5a7e108a9f976656ce723ae68fca4097bfc" -"checksum parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4d05f1349491390b1730afba60bb20d55761bef489a954546b58b4b34e1e2ac" -"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" -"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" -"checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7" -"checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" -"checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c" -"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" -"checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c" -"checksum paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4a4a1c555c6505821f9d58b8779d0f630a6b7e4e1be24ba718610acf01fa79" -"checksum paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "26e796e623b8b257215f27e6c80a5478856cae305f5b59810ff9acdaa34570e6" -"checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" -"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" -"checksum primitive-types 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6e8612a8dc70f26276fed6131c153ca277cf275ee0a5e2a50cd8a69c697beb8f" -"checksum proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e" -"checksum proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c725b36c99df7af7bf9324e9c999b9e37d92c8f8caf106d82e1d7953218d2d8" -"checksum proc-macro-hack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0c1dd4172a1e1f96f709341418f49b11ea6c2d95d53dca08c0f74cbd332d9cf3" -"checksum proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b753ad9ed99dd8efeaa7d2fb8453c8f6bc3e54b97966d35f1bc77ca6865254a" -"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a151c11a92df0059d6ab446fafa3b21a1210aad4bc2293e1c946e8132b10db01" -"checksum quick-error 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5fb6ccf8db7bbcb9c2eae558db5ab4f3da1c2a87e4e597ed394726bc8ea6ca1d" -"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" -"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" -"checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" -"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -"checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473" -"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" -"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58" -"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" -"checksum ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)" = "426bc186e3e95cac1e4a4be125a4aca7e84c2d616ffc02244eef36e2a60a093c" -"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" -"checksum rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "403bb3a286107a04825a5f82e1270acc1e14028d3d554d7a1e08914549575ab8" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rustls 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f271e3552cd835fa28c541c34a7e8fdd8cdff09d77fe4eb8f6c42e87a11b096e" -"checksum rw-stream-sink 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9cbe61c20455d3015b2bb7be39e1872310283b8e5a52f5b242b0ac7581fe78" -"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f" -"checksum safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7bf422d23a88c16d5090d455f182bc99c60af4df6a345c63428acf5129e347" -"checksum schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5eff518f9bed3d803a0d002af0ab96339b0ebbedde3bec98a684986134b7a39" -"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" -"checksum sct 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f5adf8fbd58e1b1b52699dc8bed2630faecb6d8c7bee77d009d6bbe4af569b9" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum send_wrapper 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0eddf2e8f50ced781f288c19f18621fa72a3779e3cb58dbf23b07469b0abeb4" -"checksum serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)" = "a72e9b96fa45ce22a4bc23da3858dfccfd60acd28a25bcd328a98fdd6bea43fd" -"checksum serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)" = "101b495b109a3e3ca8c4cbe44cf62391527cdfb6ba15821c5ce80bcd5ea23f9f" -"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" -"checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68" -"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" -"checksum sha2 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d963c78ce367df26d7ea8b8cc655c651b42e8a1e584e869c1e17dae3ccb116a" -"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" -"checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" -"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1e1a2eec401952cd7b12a84ea120e2d57281329940c3f93c2bf04f462539508e" -"checksum slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddc0d2aff1f8f325ef660d9a0eb6e6dcd20b30b3f581a5897f58bf42d061c37a" -"checksum slog-scope 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "60c04b4726fa04595ccf2c2dad7bcd15474242c4c5e109a8a376e8a2c9b1539a" -"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" -"checksum snow 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5a64f02fd208ef15bd2d1a65861df4707e416151e1272d02c8faafad1c138100" -"checksum soketto 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8cf3ae22c0bce5437c7dce6a2b00e492c19da1feb21ad64a7b6fd7058438c3f2" -"checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3" -"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" -"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" -"checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" -"checksum static_slice 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "92a7e0c5e3dfb52e8fbe0e63a1b947bbb17b4036408b151353c4491374931362" -"checksum stream-cipher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8861bc80f649f5b4c9bd38b696ae9af74499d479dbfb327f0607de6b326a36bc" -"checksum strum 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1810e25f576e7ffce1ff5243b37066da5ded0310b3274c20baaeccb1145b2806" -"checksum strum_macros 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "572a2f4e53dd4c3483fd79e5cc10ddd773a3acb1169bbfe8762365e107110579" -"checksum substrate-bip39 0.2.1 (git+https://github.com/paritytech/substrate-bip39)" = "" -"checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" -"checksum subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "01dca13cf6c3b179864ab3292bd794e757618d35a7766b7c46050c614ba00829" -"checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe" -"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" -"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" -"checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea" -"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" -"checksum tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c1c5676413eaeb1ea35300a0224416f57abc3bd251657e0fafc12c47ff98c060" -"checksum tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e9175261fbdb60781fcd388a4d6cc7e14764a2b629a7ad94abb439aed223a44f" -"checksum tk-listen 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5462b0f968c0457efe38fcd2df7e487096b992419e4f5337b06775a614bbda4b" -"checksum tokio 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "94a1f9396aec29d31bb16c24d155cfa144d1af91c40740125db3131bdaf76da8" -"checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" -"checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443" -"checksum tokio-dns-unofficial 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82c65483db54eb91b4ef3a9389a3364558590faf30ce473141707c0e16fda975" -"checksum tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "83ea44c6c0773cc034771693711c35c677b4b5a4b21b9e7071704c54de7d555e" -"checksum tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe6dc22b08d6993916647d108a1a7d15b9cd29c4f4496c62b92c45b5041b7af" -"checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926" -"checksum tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6af16bfac7e112bea8b0442542161bfc41cbfa4466b580bdda7d18cb88b911ce" -"checksum tokio-rustls 0.10.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)" = "316fdbc899efec48b3b492bd0f339e6d81c4ee96a409257572147ec341943452" -"checksum tokio-sync 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "5b2f843ffdf8d6e1f90bddd48da43f99ab071660cd92b7ec560ef3cdfd7a409a" -"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" -"checksum tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72558af20be886ea124595ea0f806dd5703b8958e4705429dd58b3d8231f72f2" -"checksum tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f2106812d500ed25a4f38235b9cae8f78a09edf43203e16e59c3b769a342a60e" -"checksum tokio-trace-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "350c9edade9830dc185ae48ba45667a445ab59f6167ef6d0254ec9d2430d9dd3" -"checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92" -"checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" -"checksum toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8c96d7873fa7ef8bdeb3a9cda3ac48389b4154f32b9803b4bc26220b677b039" -"checksum trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1ba73747fd3a64ab531274c04cb588dfa9d30d972d62990831e63fbce2cfec59" -"checksum trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfa2e20c4f1418ac2e71ddc418e35e1b56e34022e2146209ffdbf1b2de8b1bd9" -"checksum twofish 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d261e83e727c8e2dbb75dacac67c36e35db36a958ee504f2164fc052434e1" -"checksum twox-hash 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6c7bcecad121018bdcd6b709fa2325b004878fcb3d3067934ce90749f0faff9a" -"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" -"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" -"checksum uint 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2143cded94692b156c356508d92888acc824db5bffc0b4089732264c6fcf86d4" -"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" -"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2c64cdf40b4a9645534a943668681bcb219faf51874d4b65d2e0abda1b10a2ab" -"checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" -"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" -"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "b7ccc7b93cfd13e26700a9e2e41e6305f1951b87e166599069f77d10358100e6" -"checksum wasm-bindgen-backend 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "1953f91b1608eb1522513623c7739f047bb0fed4128ce51a93f08e12cc314645" -"checksum wasm-bindgen-futures 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "fa1af11c73eca3dc8c51c76ea475a4416e912da6402064a49fc6c0214701866d" -"checksum wasm-bindgen-macro 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "0f69da5696545d7ca6607a2e4b1a0edf5a6b36b2c49dbb0f1df6ad1d92884047" -"checksum wasm-bindgen-macro-support 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d4246f3bc73223bbb846f4f2430a60725826a96c9389adf715ed1d5af46dec6" -"checksum wasm-bindgen-shared 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "c08381e07e7a79e5e229ad7c60d15833d19033542cc5dd91d085df59d235f4a6" -"checksum wasm-bindgen-webidl 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "1f42ff7adb8102bf5ad8adbc45b1635c520c8175f9fdf6eb2c54479d485d435a" -"checksum wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad9ac33c834103916e373d648adf65f58c83fb3d8a0f3e6b9a64bca7253a4dca" -"checksum wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aebbaef470840d157a5c47c8c49f024da7b1b80e90ff729ca982b2b80447e78b" -"checksum wasmi-validation 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab380192444b3e8522ae79c0a1976e42a82920916ccdfbce3def89f456ea33f3" -"checksum web-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "540b8259eb242ff3a566fa0140bda03a4ece4e5c226e1284b5c95dddcd4341f6" -"checksum webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4f7e1cd7900a3a6b65a3e8780c51a3e6b59c0e2c55c6dc69578c288d69f7d082" -"checksum webpki-roots 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c10fa4212003ba19a564f25cd8ab572c6791f99a03cc219c13ed35ccab00de0e" -"checksum weedle 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc44aa200daee8b1f3a004beaf16554369746f1b4486f0cf93b0caf8a3c2d1e" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" -"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -"checksum x25519-dalek 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7ee1585dc1484373cbc1cee7aafda26634665cf449436fd6e24bfd1fad230538" -"checksum yamux 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "01bd67889938c48f0049fc60a77341039e6c3eaf16cb7693e6ead7c0ba701295" -"checksum zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8ddfeb6eee2fb3b262ef6e0898a52b7563bb8e0d5955a313b3cf2f808246ea14" -"checksum zeroize 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b60a6c572b91d8ecb0a460950d84fe5b40699edd07d65f73789b31237afc8f66" -"checksum zeroize_derive 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9dac4b660d969bff9c3fe1847a891cacaa8b21dd5f2aae6e0a3e0975aea96431" diff --git a/node-template/runtime/wasm/Cargo.toml b/node-template/runtime/wasm/Cargo.toml deleted file mode 100644 index 2b89c6e4db807296e0bb58655f0587ccfbb5f34c..0000000000000000000000000000000000000000 --- a/node-template/runtime/wasm/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "node-template-runtime-wasm" -version = "2.0.0" -authors = ["Anonymous"] -edition = "2018" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -node-template-runtime = { path = "..", default-features = false } - -[features] -default = [] -std = [ - "node-template-runtime/std", -] - -[profile.release] -panic = "abort" -lto = true - -[workspace] -members = [] diff --git a/node-template/runtime/wasm/build.sh b/node-template/runtime/wasm/build.sh deleted file mode 100755 index a549eeb50a5f14168ff41313b61c98edc381bd87..0000000000000000000000000000000000000000 --- a/node-template/runtime/wasm/build.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -set -e - -if cargo --version | grep -q "nightly"; then - CARGO_CMD="cargo" -else - CARGO_CMD="cargo +nightly" -fi -CARGO_INCREMENTAL=0 RUSTFLAGS="-C link-arg=--export-table" $CARGO_CMD build --target=wasm32-unknown-unknown --release "$@" -for i in node_template_runtime_wasm -do - wasm-gc target/wasm32-unknown-unknown/release/$i.wasm target/wasm32-unknown-unknown/release/$i.compact.wasm -done diff --git a/node-template/runtime/wasm/src/lib.rs b/node-template/runtime/wasm/src/lib.rs deleted file mode 100644 index 224f854812b9fd9f7a875770bc4421b4d8fa277d..0000000000000000000000000000000000000000 --- a/node-template/runtime/wasm/src/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! The Substrate node template runtime reexported for WebAssembly compile. - -#![cfg_attr(not(feature = "std"), no_std)] - -pub use node_template_runtime::*; diff --git a/node-template/scripts/build.sh b/node-template/scripts/build.sh deleted file mode 100755 index 980a8fa802d02f9f66f58ec8aebea522d690f19a..0000000000000000000000000000000000000000 --- a/node-template/scripts/build.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -set -e - -PROJECT_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." >/dev/null && pwd )" - -export CARGO_INCREMENTAL=0 - -bold=$(tput bold) -normal=$(tput sgr0) - -# Save current directory. -pushd . >/dev/null - -for SRC in runtime/wasm -do - echo "${bold}Building webassembly binary in $SRC...${normal}" - cd "$PROJECT_ROOT/$SRC" - - ./build.sh "$@" - - cd - >> /dev/null -done - -# Restore initial directory. -popd >/dev/null diff --git a/node-template/src/chain_spec.rs b/node-template/src/chain_spec.rs index f14cf41464a1b8e9b14641e3d4dc39ffb892a3d0..3970522b37ab5c2c2a4227e7c52c06a9a4645974 100644 --- a/node-template/src/chain_spec.rs +++ b/node-template/src/chain_spec.rs @@ -1,7 +1,7 @@ use primitives::{ed25519, sr25519, Pair}; use node_template_runtime::{ - AccountId, AuraId as AuthorityId, GenesisConfig, AuraConfig, TimestampConfig, BalancesConfig, - SudoConfig, IndicesConfig, SystemConfig + AccountId, GenesisConfig, AuraConfig, BalancesConfig, + SudoConfig, IndicesConfig, SystemConfig, WASM_BINARY, AuraId }; use substrate_service; @@ -22,7 +22,7 @@ pub enum Alternative { LocalTestnet, } -fn authority_key(s: &str) -> AuthorityId { +fn authority_key(s: &str) -> AuraId { ed25519::Pair::from_string(&format!("//{}", s), None) .expect("static values are valid; qed") .public() @@ -88,28 +88,19 @@ impl Alternative { } } -fn testnet_genesis(initial_authorities: Vec, endowed_accounts: Vec, root_key: AccountId) -> GenesisConfig { +fn testnet_genesis(initial_authorities: Vec, endowed_accounts: Vec, root_key: AccountId) -> GenesisConfig { GenesisConfig { system: Some(SystemConfig { - code: include_bytes!("../runtime/wasm/target/wasm32-unknown-unknown/release/node_template_runtime_wasm.compact.wasm").to_vec(), + code: WASM_BINARY.to_vec(), changes_trie_config: Default::default(), - _genesis_phantom_data: Default::default(), }), aura: Some(AuraConfig { authorities: initial_authorities.clone(), }), - timestamp: Some(TimestampConfig { - minimum_period: 5, // 10 second block time. - }), indices: Some(IndicesConfig { ids: endowed_accounts.clone(), }), balances: Some(BalancesConfig { - transaction_base_fee: 1, - transaction_byte_fee: 0, - existential_deposit: 500, - transfer_fee: 0, - creation_fee: 0, balances: endowed_accounts.iter().cloned().map(|k|(k, 1 << 60)).collect(), vesting: vec![], }), diff --git a/node-template/src/cli.rs b/node-template/src/cli.rs index cd148f3462dce8cac7ffa981d37439967954ba3c..b799a5d9aee4233988302bb22fcd706eda724f79 100644 --- a/node-template/src/cli.rs +++ b/node-template/src/cli.rs @@ -25,16 +25,15 @@ pub fn run(args: I, exit: E, version: VersionInfo) -> error::Result<()> info!("Node name: {}", config.name); info!("Roles: {:?}", config.roles); let runtime = Runtime::new().map_err(|e| format!("{:?}", e))?; - let executor = runtime.executor(); match config.roles { ServiceRoles::LIGHT => run_until_exit( runtime, - service::Factory::new_light(config, executor).map_err(|e| format!("{:?}", e))?, + service::Factory::new_light(config).map_err(|e| format!("{:?}", e))?, exit ), _ => run_until_exit( runtime, - service::Factory::new_full(config, executor).map_err(|e| format!("{:?}", e))?, + service::Factory::new_full(config).map_err(|e| format!("{:?}", e))?, exit ), }.map_err(|e| format!("{:?}", e)) @@ -55,7 +54,7 @@ fn run_until_exit( e: E, ) -> error::Result<()> where - T: Deref>, + T: Deref> + Future + Send + 'static, C: substrate_service::Components, E: IntoExit, { @@ -64,13 +63,13 @@ fn run_until_exit( let informant = informant::build(&service); runtime.executor().spawn(exit.until(informant).map(|_| ())); - let _ = runtime.block_on(e.into_exit()); - exit_send.fire(); - // we eagerly drop the service so that the internal exit future is fired, // but we need to keep holding a reference to the global telemetry guard let _telemetry = service.telemetry(); - drop(service); + + let _ = runtime.block_on(service.select(e.into_exit())); + exit_send.fire(); + Ok(()) } diff --git a/node-template/src/service.rs b/node-template/src/service.rs index 5a17574f6d1206bf76941bddce66f7c2fbe97ebd..ccb7c18679f460f26b5e51d81b24008bc8a71325 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -5,11 +5,10 @@ use std::sync::Arc; use log::info; use transaction_pool::{self, txpool::{Pool as TransactionPool}}; -use node_template_runtime::{self, GenesisConfig, opaque::Block, RuntimeApi}; +use node_template_runtime::{self, GenesisConfig, opaque::Block, RuntimeApi, WASM_BINARY}; use substrate_service::{ FactoryFullConfiguration, LightComponents, FullComponents, FullBackend, FullClient, LightClient, LightBackend, FullExecutor, LightExecutor, - TaskExecutor, error::{Error as ServiceError}, }; use basic_authorship::ProposerFactory; @@ -18,7 +17,7 @@ use futures::prelude::*; use substrate_client::{self as client, LongestChain}; use primitives::{ed25519::Pair, Pair as PairT}; use inherents::InherentDataProviders; -use network::construct_simple_protocol; +use network::{config::DummyFinalityProofRequestBuilder, construct_simple_protocol}; use substrate_executor::native_executor_instance; use substrate_service::construct_service_factory; @@ -28,7 +27,7 @@ native_executor_instance!( pub Executor, node_template_runtime::api::dispatch, node_template_runtime::native_version, - include_bytes!("../runtime/wasm/target/wasm32-unknown-unknown/release/node_template_runtime_wasm.compact.wasm") + WASM_BINARY ); #[derive(Default)] @@ -63,12 +62,12 @@ construct_service_factory! { SetupState = SetupState, Configuration = (), FullService = FullComponents - { |config: FactoryFullConfiguration, executor: TaskExecutor| - FullComponents::::new(config, executor) + { |config: FactoryFullConfiguration| + FullComponents::::new(config) }, AuthoritySetup = { - |service: Self::FullService, executor: TaskExecutor, key: Option>| { - if let Some(key) = key { + |service: Self::FullService| { + if let Some(key) = service.authority_key::() { info!("Using authority key {}", key.public()); let proposer = Arc::new(ProposerFactory { client: service.client(), @@ -79,7 +78,7 @@ construct_service_factory! { .ok_or_else(|| ServiceError::SelectChainRequired)?; let aura = start_aura( SlotDuration::get_or_compute(&*client)?, - key.clone(), + Arc::new(key), client.clone(), select_chain, client, @@ -88,22 +87,21 @@ construct_service_factory! { service.config.custom.inherent_data_providers.clone(), service.config.force_authoring, )?; - executor.spawn(aura.select(service.on_exit()).then(|_| Ok(()))); + service.spawn_task(Box::new(aura.select(service.on_exit()).then(|_| Ok(())))); } Ok(service) } }, LightService = LightComponents - { |config, executor| >::new(config, executor) }, + { |config| >::new(config) }, FullImportQueue = AuraImportQueue< Self::Block, > { |config: &mut FactoryFullConfiguration , client: Arc>, _select_chain: Self::SelectChain| { import_queue::<_, _, Pair>( SlotDuration::get_or_compute(&*client)?, - client.clone(), - None, + Box::new(client.clone()), None, None, client, @@ -115,15 +113,15 @@ construct_service_factory! { Self::Block, > { |config: &mut FactoryFullConfiguration, client: Arc>| { + let fprb = Box::new(DummyFinalityProofRequestBuilder::default()) as Box<_>; import_queue::<_, _, Pair>( SlotDuration::get_or_compute(&*client)?, - client.clone(), - None, + Box::new(client.clone()), None, None, client, config.custom.inherent_data_providers.clone(), - ).map_err(Into::into) + ).map(|q| (q, fprb)).map_err(Into::into) } }, SelectChain = LongestChain, Self::Block> diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index 14a5b5c32d10bdb5254243d5ae1b50b6eaceca81..ad49cbe36cd900f6a9e0d0cea6d04fe38f518415 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -12,7 +12,7 @@ tokio = "0.1.7" futures = "0.1" exit-future = "0.1" cli = { package = "substrate-cli", path = "../../core/cli" } -parity-codec = { version = "3.3" } +parity-codec = { version = "4.1.1" } sr-io = { path = "../../core/sr-io" } client = { package = "substrate-client", path = "../../core/client" } primitives = { package = "substrate-primitives", path = "../../core/primitives" } @@ -24,10 +24,11 @@ substrate-basic-authorship = { path = "../../core/basic-authorship" } substrate-service = { path = "../../core/service" } transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" } network = { package = "substrate-network", path = "../../core/network" } -consensus = { package = "substrate-consensus-aura", path = "../../core/consensus/aura" } +aura = { package = "substrate-consensus-aura", path = "../../core/consensus/aura" } +aura_primitives = { package = "substrate-consensus-aura-primitives", path = "../../core/consensus/aura/primitives" } grandpa = { package = "substrate-finality-grandpa", path = "../../core/finality-grandpa" } +grandpa_primitives = { package = "substrate-finality-grandpa-primitives", path = "../../core/finality-grandpa/primitives" } sr-primitives = { path = "../../core/sr-primitives" } -aura_primitives = { package = "substrate-consensus-aura-primitives", path = "../../core/consensus/aura/primitives" } node-executor = { path = "../executor" } substrate-keystore = { path = "../../core/keystore" } substrate-telemetry = { package = "substrate-telemetry", path = "../../core/telemetry" } @@ -38,6 +39,7 @@ indices = { package = "srml-indices", path = "../../srml/indices" } timestamp = { package = "srml-timestamp", path = "../../srml/timestamp", default-features = false } rand = "0.6" finality_tracker = { package = "srml-finality-tracker", path = "../../srml/finality-tracker", default-features = false } +contracts = { package = "srml-contracts", path = "../../srml/contracts" } [dev-dependencies] consensus-common = { package = "substrate-consensus-common", path = "../../core/consensus/common" } diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index 672c75b1a94c6b0438784a06be83fdb6b7c59a72..857eba782a27870621f15ac8ed5b02cca3809d09 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -17,10 +17,13 @@ //! Substrate chain configurations. use primitives::{ed25519, sr25519, Pair, crypto::UncheckedInto}; -use node_primitives::{AccountId, AuraId}; -use node_runtime::{CouncilSeatsConfig, AuraConfig, DemocracyConfig, SystemConfig, - SessionConfig, StakingConfig, StakerStatus, TimestampConfig, BalancesConfig, TreasuryConfig, - SudoConfig, ContractsConfig, GrandpaConfig, IndicesConfig, Permill, Perbill, SessionKeys}; +use node_primitives::{AccountId, AuraId, Balance}; +use node_runtime::{ + GrandpaConfig, BalancesConfig, ContractsConfig, ElectionsConfig, DemocracyConfig, CouncilConfig, + AuraConfig, IndicesConfig, SessionConfig, StakingConfig, SudoConfig, TechnicalCommitteeConfig, + SystemConfig, WASM_BINARY, Perbill, SessionKeys, StakerStatus, DAYS, DOLLARS, + MILLICENTS, +}; pub use node_runtime::GenesisConfig; use substrate_service; use hex_literal::hex; @@ -37,6 +40,10 @@ pub fn flaming_fir_config() -> Result { ChainSpec::from_embedded(include_bytes!("../res/flaming-fir.json")) } +fn session_keys(key: ed25519::Public) -> SessionKeys { + SessionKeys { ed25519: key } +} + fn staging_testnet_config_genesis() -> GenesisConfig { // stash, controller, session-key // generated with secret: @@ -88,34 +95,19 @@ fn staging_testnet_config_genesis() -> GenesisConfig { hex!["9ee5e5bdc0ec239eb164f865ecc345ce4c88e76ee002e0f7e318097347471809"].unchecked_into(), ]; - const MILLICENTS: u128 = 1_000_000_000; - const CENTS: u128 = 1_000 * MILLICENTS; // assume this is worth about a cent. - const DOLLARS: u128 = 100 * CENTS; - - const SECS_PER_BLOCK: u64 = 6; - const MINUTES: u64 = 60 / SECS_PER_BLOCK; - const HOURS: u64 = MINUTES * 60; - const DAYS: u64 = HOURS * 24; - - const ENDOWMENT: u128 = 10_000_000 * DOLLARS; - const STASH: u128 = 100 * DOLLARS; + const ENDOWMENT: Balance = 10_000_000 * DOLLARS; + const STASH: Balance = 100 * DOLLARS; GenesisConfig { system: Some(SystemConfig { - code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm").to_vec(), // FIXME change once we have #1252 - _genesis_phantom_data: Default::default(), + code: WASM_BINARY.to_vec(), changes_trie_config: Default::default(), }), balances: Some(BalancesConfig { - transaction_base_fee: 1 * CENTS, - transaction_byte_fee: 10 * MILLICENTS, balances: endowed_accounts.iter().cloned() .map(|k| (k, ENDOWMENT)) .chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH))) .collect(), - existential_deposit: 1 * DOLLARS, - transfer_fee: 1 * CENTS, - creation_fee: 1 * CENTS, vesting: vec![], }), indices: Some(IndicesConfig { @@ -124,8 +116,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig { .collect::>(), }), session: Some(SessionConfig { - validators: initial_authorities.iter().map(|x| x.1.clone()).collect(), - keys: initial_authorities.iter().map(|x| (x.1.clone(), SessionKeys(x.2.clone(),x.2.clone()))).collect::>(), + keys: initial_authorities.iter().map(|x| (x.0.clone(), session_keys(x.2.clone()))).collect::>(), }), staking: Some(StakingConfig { current_era: 0, @@ -136,50 +127,26 @@ fn staging_testnet_config_genesis() -> GenesisConfig { offline_slash_grace: 4, minimum_validator_count: 4, stakers: initial_authorities.iter().map(|x| (x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator)).collect(), - invulnerables: initial_authorities.iter().map(|x| x.1.clone()).collect(), + invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(), }), democracy: Some(DemocracyConfig::default()), - council_seats: Some(CouncilSeatsConfig { - active_council: vec![], - candidacy_bond: 10 * DOLLARS, - voter_bond: 1 * DOLLARS, - voting_fee: 2 * DOLLARS, - present_slash_per_voter: 1 * CENTS, - carry_count: 6, + collective_Instance1: Some(CouncilConfig { + members: vec![], + phantom: Default::default(), + }), + collective_Instance2: Some(TechnicalCommitteeConfig { + members: vec![], + phantom: Default::default(), + }), + elections: Some(ElectionsConfig { + members: vec![], presentation_duration: 1 * DAYS, - approval_voting_period: 2 * DAYS, term_duration: 28 * DAYS, desired_seats: 0, - decay_ratio: 0, - inactive_grace_period: 1, // one additional vote should go by before an inactive voter can be reaped. - }), - timestamp: Some(TimestampConfig { - minimum_period: SECS_PER_BLOCK / 2, // due to the nature of aura the slots are 2*period - }), - treasury: Some(TreasuryConfig { - proposal_bond: Permill::from_percent(5), - proposal_bond_minimum: 1 * DOLLARS, - spend_period: 1 * DAYS, - burn: Permill::from_percent(50), }), contracts: Some(ContractsConfig { - signed_claim_handicap: 2, - rent_byte_price: 4, - rent_deposit_offset: 1000, - storage_size_offset: 8, - surcharge_reward: 150, - tombstone_deposit: 16, - transaction_base_fee: 1 * CENTS, - transaction_byte_fee: 10 * MILLICENTS, - transfer_fee: 1 * CENTS, - creation_fee: 1 * CENTS, - contract_fee: 1 * CENTS, - call_base_fee: 1000, - create_base_fee: 1000, - gas_price: 1 * MILLICENTS, - max_depth: 1024, - block_gas_limit: 10_000_000, current_schedule: Default::default(), + gas_price: 1 * MILLICENTS, }), sudo: Some(SudoConfig { key: endowed_accounts[0].clone(), @@ -189,7 +156,6 @@ fn staging_testnet_config_genesis() -> GenesisConfig { }), grandpa: Some(GrandpaConfig { authorities: initial_authorities.iter().map(|x| (x.3.clone(), 1)).collect(), - _genesis_phantom_data: Default::default(), }), } } @@ -264,53 +230,25 @@ pub fn testnet_genesis( ] }); - const STASH: u128 = 1 << 20; - const ENDOWMENT: u128 = 1 << 20; - - let council_desired_seats = (endowed_accounts.len() / 2 - initial_authorities.len()) as u32; - let mut contracts_config = ContractsConfig { - signed_claim_handicap: 2, - rent_byte_price: 4, - rent_deposit_offset: 1000, - storage_size_offset: 8, - surcharge_reward: 150, - tombstone_deposit: 16, - transaction_base_fee: 1, - transaction_byte_fee: 0, - transfer_fee: 0, - creation_fee: 0, - contract_fee: 21, - call_base_fee: 135, - create_base_fee: 175, - gas_price: 1, - max_depth: 1024, - block_gas_limit: 10_000_000, - current_schedule: Default::default(), - }; - // this should only be enabled on development chains - contracts_config.current_schedule.enable_println = enable_println; + const ENDOWMENT: Balance = 10_000_000 * DOLLARS; + const STASH: Balance = 100 * DOLLARS; + + let desired_seats = (endowed_accounts.len() / 2 - initial_authorities.len()) as u32; GenesisConfig { system: Some(SystemConfig { - code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm").to_vec(), - _genesis_phantom_data: Default::default(), + code: WASM_BINARY.to_vec(), changes_trie_config: Default::default(), }), indices: Some(IndicesConfig { ids: endowed_accounts.clone(), }), balances: Some(BalancesConfig { - transaction_base_fee: 1, - transaction_byte_fee: 0, - existential_deposit: 500, - transfer_fee: 0, - creation_fee: 0, balances: endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect(), vesting: vec![], }), session: Some(SessionConfig { - validators: initial_authorities.iter().map(|x| x.1.clone()).collect(), - keys: initial_authorities.iter().map(|x| (x.1.clone(), SessionKeys(x.2.clone(), x.2.clone()))).collect::>(), + keys: initial_authorities.iter().map(|x| (x.0.clone(), session_keys(x.2.clone()))).collect::>(), }), staking: Some(StakingConfig { current_era: 0, @@ -321,35 +259,32 @@ pub fn testnet_genesis( current_session_reward: 0, offline_slash_grace: 0, stakers: initial_authorities.iter().map(|x| (x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator)).collect(), - invulnerables: initial_authorities.iter().map(|x| x.1.clone()).collect(), + invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(), }), democracy: Some(DemocracyConfig::default()), - council_seats: Some(CouncilSeatsConfig { - active_council: endowed_accounts.iter() + collective_Instance1: Some(CouncilConfig { + members: vec![], + phantom: Default::default(), + }), + collective_Instance2: Some(TechnicalCommitteeConfig { + members: vec![], + phantom: Default::default(), + }), + elections: Some(ElectionsConfig { + members: endowed_accounts.iter() .filter(|&endowed| initial_authorities.iter().find(|&(_, controller, ..)| controller == endowed).is_none()) .map(|a| (a.clone(), 1000000)).collect(), - candidacy_bond: 10, - voter_bond: 2, - voting_fee: 5, - present_slash_per_voter: 1, - carry_count: 4, presentation_duration: 10, - approval_voting_period: 20, term_duration: 1000000, - desired_seats: council_desired_seats, - decay_ratio: council_desired_seats / 3, - inactive_grace_period: 1, + desired_seats: desired_seats, }), - timestamp: Some(TimestampConfig { - minimum_period: 2, // 2*2=4 second block time. - }), - treasury: Some(TreasuryConfig { - proposal_bond: Permill::from_percent(5), - proposal_bond_minimum: 1_000_000, - spend_period: 12 * 60 * 24, - burn: Permill::from_percent(50), + contracts: Some(ContractsConfig { + current_schedule: contracts::Schedule { + enable_println, // this should only be enabled on development chains + ..Default::default() + }, + gas_price: 1 * MILLICENTS, }), - contracts: Some(contracts_config), sudo: Some(SudoConfig { key: root_key, }), @@ -358,7 +293,6 @@ pub fn testnet_genesis( }), grandpa: Some(GrandpaConfig { authorities: initial_authorities.iter().map(|x| (x.3.clone(), 1)).collect(), - _genesis_phantom_data: Default::default(), }), } } @@ -402,23 +336,15 @@ pub(crate) mod tests { use service_test; use crate::service::Factory; - fn local_testnet_genesis_instant() -> GenesisConfig { - let mut genesis = local_testnet_genesis(); - genesis.timestamp = Some(TimestampConfig { minimum_period: 1 }); - genesis - } - fn local_testnet_genesis_instant_single() -> GenesisConfig { - let mut genesis = testnet_genesis( + testnet_genesis( vec![ get_authority_keys_from_seed("Alice"), ], get_account_id_from_seed("Alice"), None, false, - ); - genesis.timestamp = Some(TimestampConfig { minimum_period: 1 }); - genesis + ) } /// Local testnet config (single validator - Alice) @@ -437,7 +363,7 @@ pub(crate) mod tests { /// Local testnet config (multivalidator Alice + Bob) pub fn integration_test_config_with_two_authorities() -> ChainSpec { - ChainSpec::from_genesis("Integration Test", "test", local_testnet_genesis_instant, vec![], None, None, None, None) + ChainSpec::from_genesis("Integration Test", "test", local_testnet_genesis, vec![], None, None, None, None) } #[test] diff --git a/node/cli/src/factory_impl.rs b/node/cli/src/factory_impl.rs index 0d94610362fdc84b3d9f1e2aa81ba477bc312f25..211d16f148cc9b87e95749b0b5217b1ecb8891a2 100644 --- a/node/cli/src/factory_impl.rs +++ b/node/cli/src/factory_impl.rs @@ -38,7 +38,7 @@ use inherents::InherentData; use timestamp; use finality_tracker; -// TODO get via api: >::minimum_period(). See #2587. +// TODO get via api: ::MinimumPeriod::get(). See #2587. const MINIMUM_PERIOD: u64 = 99; pub struct FactoryState { diff --git a/node/cli/src/lib.rs b/node/cli/src/lib.rs index ab1fd03ae7b24eb7afc4a4ba44a710f143bc09c9..b18fa57411ce5bdd04b971dbcbf7e0ab4c2b275a 100644 --- a/node/cli/src/lib.rs +++ b/node/cli/src/lib.rs @@ -156,16 +156,15 @@ pub fn run(args: I, exit: E, version: cli::VersionInfo) -> error::Resul info!("Roles: {:?}", config.roles); let runtime = RuntimeBuilder::new().name_prefix("main-tokio-").build() .map_err(|e| format!("{:?}", e))?; - let executor = runtime.executor(); match config.roles { ServiceRoles::LIGHT => run_until_exit( runtime, - service::Factory::new_light(config, executor).map_err(|e| format!("{:?}", e))?, + service::Factory::new_light(config).map_err(|e| format!("{:?}", e))?, exit ), _ => run_until_exit( runtime, - service::Factory::new_full(config, executor).map_err(|e| format!("{:?}", e))?, + service::Factory::new_full(config).map_err(|e| format!("{:?}", e))?, exit ), }.map_err(|e| format!("{:?}", e)) @@ -207,7 +206,7 @@ fn run_until_exit( e: E, ) -> error::Result<()> where - T: Deref>, + T: Deref> + Future + Send + 'static, C: substrate_service::Components, E: IntoExit, { @@ -216,13 +215,12 @@ fn run_until_exit( let informant = cli::informant::build(&service); runtime.executor().spawn(exit.until(informant).map(|_| ())); - let _ = runtime.block_on(e.into_exit()); - exit_send.fire(); - // we eagerly drop the service so that the internal exit future is fired, // but we need to keep holding a reference to the global telemetry guard let _telemetry = service.telemetry(); - drop(service); + + let _ = runtime.block_on(service.select(e.into_exit())); + exit_send.fire(); // TODO [andre]: timeout this future #1318 let _ = runtime.shutdown_on_idle().wait(); diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index a41f34902ac285ddbc68c72f15eea8b45027cad9..d5741b2f05c9ec8c6a9e9294a6366ee369b2d1d2 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -21,17 +21,17 @@ use std::sync::Arc; use std::time::Duration; +use aura::{import_queue, start_aura, AuraImportQueue, SlotDuration}; use client::{self, LongestChain}; -use consensus::{import_queue, start_aura, AuraImportQueue, SlotDuration}; use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider}; use node_executor; -use primitives::{Pair as PairT, ed25519}; +use primitives::Pair; use futures::prelude::*; -use node_primitives::Block; +use node_primitives::{AuraPair, Block}; use node_runtime::{GenesisConfig, RuntimeApi}; use substrate_service::{ FactoryFullConfiguration, LightComponents, FullComponents, FullBackend, - FullClient, LightClient, LightBackend, FullExecutor, LightExecutor, TaskExecutor, + FullClient, LightClient, LightBackend, FullExecutor, LightExecutor, FullComponentsSetupState, LightComponentsSetupState, error::{Error as ServiceError}, }; use transaction_pool::{self, txpool::{Pool as TransactionPool}}; @@ -50,7 +50,7 @@ construct_simple_protocol! { pub struct NodeSetupState { /// grandpa connection to import block // FIXME #1134 rather than putting this on the config, let's have an actual intermediate setup state - pub grandpa_import_setup: Option<(Arc>, grandpa::LinkHalfForService)>, + pub grandpa_import_setup: Option<(grandpa::BlockImportForService, grandpa::LinkHalfForService)>, inherent_data_providers: InherentDataProviders, } @@ -77,15 +77,16 @@ construct_service_factory! { SetupState = NodeSetupState, Configuration = (), FullService = FullComponents - { |config: FactoryFullConfiguration, executor: TaskExecutor| - FullComponents::::new(config, executor) }, + { |config: FactoryFullConfiguration| + FullComponents::::new(config) }, AuthoritySetup = { - |service: Self::FullService, mut state: FullComponentsSetupState, executor: TaskExecutor, local_key: Option>| { - let (block_import, link_half) = state.custom.grandpa_import_setup.take() + |mut service: Self::FullService, mut state: FullComponentsSetupState| { + let (block_import, link_half) = state.config.custom.grandpa_import_setup.take() .expect("Link Half and Block Import are present for Full Services or setup failed before. qed"); - if let Some(ref key) = local_key { - info!("Using authority key {}", key.public()); + if let Some(aura_key) = service.authority_key::() { + info!("Using aura key {}", aura_key.public()); + let proposer = Arc::new(substrate_basic_authorship::ProposerFactory { client: service.client(), transaction_pool: service.transaction_pool(), @@ -94,30 +95,30 @@ construct_service_factory! { let client = service.client(); let select_chain = service.select_chain() .ok_or(ServiceError::SelectChainRequired)?; + let aura = start_aura( SlotDuration::get_or_compute(&*client)?, - key.clone(), + Arc::new(aura_key), client, select_chain, - block_import.clone(), + block_import, proposer, service.network(), state.custom.inherent_data_providers.clone(), state.config.force_authoring, )?; - executor.spawn(aura.select(service.on_exit()).then(|_| Ok(()))); - - info!("Running Grandpa session as Authority {}", key.public()); + let select = aura.select(service.on_exit()).then(|_| Ok(())); + service.spawn_task(Box::new(select)); } - let local_key = if state.config.disable_grandpa { + let grandpa_key = if state.config.disable_grandpa { None } else { - local_key + service.authority_key::() }; let config = grandpa::Config { - local_key, + local_key: grandpa_key.map(Arc::new), // FIXME #1578 make this available through chainspec gossip_duration: Duration::from_millis(333), justification_period: 4096, @@ -125,19 +126,18 @@ construct_service_factory! { }; match config.local_key { - None => { - executor.spawn(grandpa::run_grandpa_observer( + None if !service.config.grandpa_voter => { + service.spawn_task(Box::new(grandpa::run_grandpa_observer( config, link_half, service.network(), service.on_exit(), - )?); + )?)); }, - Some(_) => { + // Either config.local_key is set, or user forced voter service via `--grandpa-voter` flag. + _ => { let telemetry_on_connect = TelemetryOnConnect { - on_exit: Box::new(service.on_exit()), telemetry_connection_sinks: service.telemetry_on_connect_stream(), - executor: &executor, }; let grandpa_config = grandpa::GrandpaParams { config: config, @@ -147,7 +147,7 @@ construct_service_factory! { on_exit: service.on_exit(), telemetry_on_connect: Some(telemetry_on_connect), }; - executor.spawn(grandpa::run_grandpa_voter(grandpa_config)?); + service.spawn_task(Box::new(grandpa::run_grandpa_voter(grandpa_config)?)); }, } @@ -155,7 +155,7 @@ construct_service_factory! { } }, LightService = LightComponents - { |config, executor| >::new(config, executor) }, + { |config| >::new(config) }, FullImportQueue = AuraImportQueue { |state: &mut FullComponentsSetupState , client: Arc>, select_chain: Self::SelectChain| { let slot_duration = SlotDuration::get_or_compute(&*client)?; @@ -163,16 +163,14 @@ construct_service_factory! { grandpa::block_import::<_, _, _, RuntimeApi, FullClient, _>( client.clone(), client.clone(), select_chain )?; - let block_import = Arc::new(block_import); let justification_import = block_import.clone(); state.custom.grandpa_import_setup = Some((block_import.clone(), link_half)); - import_queue::<_, _, ed25519::Pair>( + import_queue::<_, _, AuraPair>( slot_duration, - block_import, - Some(justification_import), - None, + Box::new(block_import), + Some(Box::new(justification_import)), None, client, state.custom.inherent_data_providers.clone(), @@ -187,19 +185,17 @@ construct_service_factory! { let block_import = grandpa::light_block_import::<_, _, _, RuntimeApi, LightClient>( client.clone(), Arc::new(fetch_checker), client.clone() )?; - let block_import = Arc::new(block_import); let finality_proof_import = block_import.clone(); let finality_proof_request_builder = finality_proof_import.create_finality_proof_request_builder(); - import_queue::<_, _, ed25519::Pair>( + import_queue::<_, _, AuraPair>( SlotDuration::get_or_compute(&*client)?, - block_import, + Box::new(block_import), None, - Some(finality_proof_import), - Some(finality_proof_request_builder), + Some(Box::new(finality_proof_import)), client, state.custom.inherent_data_providers.clone(), - ).map_err(Into::into) + ).map(|q| (q, finality_proof_request_builder)).map_err(Into::into) }}, SelectChain = LongestChain, Self::Block> { |state: &FullComponentsSetupState, client: Arc>| { @@ -216,10 +212,10 @@ construct_service_factory! { #[cfg(test)] mod tests { use std::sync::Arc; - use consensus::CompatibleDigestItem; + use aura::CompatibleDigestItem; use consensus_common::{Environment, Proposer, ImportBlock, BlockOrigin, ForkChoiceStrategy}; use node_primitives::DigestItem; - use node_runtime::{Call, BalancesCall, UncheckedExtrinsic}; + use node_runtime::{BalancesCall, Call, CENTS, SECS_PER_BLOCK, UncheckedExtrinsic}; use parity_codec::{Compact, Encode, Decode}; use primitives::{ crypto::Pair as CryptoPair, ed25519::Pair, blake2_256, @@ -230,6 +226,7 @@ mod tests { use finality_tracker; use keyring::{ed25519::Keyring as AuthorityKeyring, sr25519::Keyring as AccountKeyring}; use substrate_service::ServiceFactory; + use service_test::SyncService; use crate::service::Factory; #[cfg(feature = "rhd")] @@ -265,8 +262,13 @@ mod tests { auxiliary: Vec::new(), } }; - let extrinsic_factory = |service: &::FullService| { - let payload = (0, Call::Balances(BalancesCall::transfer(RawAddress::Id(bob.public().0.into()), 69.into())), Era::immortal(), service.client().genesis_hash()); + let extrinsic_factory = |service: &SyncService<::FullService>| { + let payload = ( + 0, + Call::Balances(BalancesCall::transfer(RawAddress::Id(bob.public().0.into()), 69.into())), + Era::immortal(), + service.client().genesis_hash() + ); let signature = alice.sign(&payload.encode()).into(); let id = alice.public().0.into(); let xt = UncheckedExtrinsic { @@ -276,7 +278,11 @@ mod tests { let v: Vec = Decode::decode(&mut xt.as_slice()).unwrap(); OpaqueExtrinsic(v) }; - service_test::sync::(chain_spec::integration_test_config(), block_factory, extrinsic_factory); + service_test::sync::( + chain_spec::integration_test_config(), + block_factory, + extrinsic_factory, + ); } #[test] @@ -286,11 +292,15 @@ mod tests { let alice = Arc::new(AuthorityKeyring::Alice.pair()); let mut slot_num = 1u64; - let block_factory = |service: &::FullService| { - let mut inherent_data = state.custom.inherent_data_providers - .create_inherent_data().unwrap(); + let block_factory = |service: &SyncService<::FullService>| { + let service = service.get(); + let mut inherent_data = state + .custom + .inherent_data_providers + .create_inherent_data() + .expect("Creates inherent data."); inherent_data.replace_data(finality_tracker::INHERENT_IDENTIFIER, &1u64); - inherent_data.replace_data(timestamp::INHERENT_IDENTIFIER, &(slot_num * 10)); + inherent_data.replace_data(timestamp::INHERENT_IDENTIFIER, &(slot_num * SECS_PER_BLOCK)); let parent_id = BlockId::number(service.client().info().chain.best_number); let parent_header = service.client().header(&parent_id).unwrap().unwrap(); @@ -298,13 +308,14 @@ mod tests { client: service.client(), transaction_pool: service.transaction_pool(), }); + let mut digest = Digest::::default(); - digest.push(>::aura_pre_digest(slot_num * 10 / 2)); + digest.push(>::aura_pre_digest(slot_num)); let proposer = proposer_factory.init(&parent_header).unwrap(); let new_block = proposer.propose( inherent_data, digest, - ::std::time::Duration::from_secs(1), + std::time::Duration::from_secs(1), ).expect("Error making test block"); let (new_header, new_body) = new_block.deconstruct(); @@ -334,11 +345,11 @@ mod tests { let charlie = Arc::new(AccountKeyring::Charlie.pair()); let mut index = 0; - let extrinsic_factory = |service: &::FullService| { - let amount = 1000; + let extrinsic_factory = |service: &SyncService<::FullService>| { + let amount = 5 * CENTS; let to = AddressPublic::from_raw(bob.public().0); let from = AddressPublic::from_raw(charlie.public().0); - let genesis_hash = service.client().block_hash(0).unwrap().unwrap(); + let genesis_hash = service.get().client().block_hash(0).unwrap().unwrap(); let signer = charlie.clone(); let function = Call::Balances(BalancesCall::transfer(to.into(), amount)); diff --git a/node/executor/Cargo.toml b/node/executor/Cargo.toml index a5e5958f6a67ec3490109ebee243acd0639d0167..345401141913c781e8970f136a9ff7fecbc12c96 100644 --- a/node/executor/Cargo.toml +++ b/node/executor/Cargo.toml @@ -6,8 +6,8 @@ description = "Substrate node implementation in Rust." edition = "2018" [dependencies] -trie-root = "0.12" -parity-codec = "3.3" +trie-root = "0.14.0" +parity-codec = "4.1.1" runtime_io = { package = "sr-io", path = "../../core/sr-io" } state_machine = { package = "substrate-state-machine", path = "../../core/state-machine" } substrate-executor = { path = "../../core/executor" } diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 1622e92c6d31e01f2becb01709308a128f1bc6a9..fbd537f4752e7a2cc62b234653a2fb87f68218ee 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -30,9 +30,7 @@ native_executor_instance!( pub Executor, node_runtime::api::dispatch, node_runtime::native_version, - include_bytes!( - "../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm" - ) + node_runtime::WASM_BINARY ); #[cfg(test)] @@ -44,17 +42,22 @@ mod tests { use keyring::{AuthorityKeyring, AccountKeyring}; use runtime_support::{Hashable, StorageValue, StorageMap, traits::Currency}; use state_machine::{CodeExecutor, Externalities, TestExternalities as CoreTestExternalities}; - use primitives::{twox_128, blake2_256, Blake2Hasher, ChangesTrieConfiguration, NeverNativeValue, - NativeOrEncoded}; + use primitives::{ + twox_128, blake2_256, Blake2Hasher, ChangesTrieConfiguration, NeverNativeValue, + NativeOrEncoded + }; use node_primitives::{Hash, BlockNumber, AccountId}; use runtime_primitives::traits::{Header as HeaderT, Hash as HashT}; use runtime_primitives::{generic::Era, ApplyOutcome, ApplyError, ApplyResult, Perbill}; - use {balances, indices, system, staking, timestamp, treasury, contracts}; + use {balances, contracts, indices, staking, system, timestamp}; use contracts::ContractAddressFor; use system::{EventRecord, Phase}; - use node_runtime::{Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Call, Runtime, Balances, - BuildStorage, GenesisConfig, BalancesConfig, SessionConfig, StakingConfig, System, - SystemConfig, GrandpaConfig, IndicesConfig, Event, SessionKeys}; + use node_runtime::{ + Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Call, Runtime, Balances, BuildStorage, + GenesisConfig, BalancesConfig, SessionConfig, StakingConfig, System, SystemConfig, + GrandpaConfig, IndicesConfig, ContractsConfig, Event, SessionKeys, + CENTS, DOLLARS, MILLICENTS, + }; use wabt; use primitives::map; @@ -64,19 +67,19 @@ mod tests { /// making the binary slimmer. There is a convention to use compact version of the runtime /// as canonical. This is why `native_executor_instance` also uses the compact version of the /// runtime. - const COMPACT_CODE: &[u8] = - include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm"); + const COMPACT_CODE: &[u8] = node_runtime::WASM_BINARY; /// The wasm runtime binary which hasn't undergone the compacting process. /// /// The idea here is to pass it as the current runtime code to the executor so the executor will /// have to execute provided wasm code instead of the native equivalent. This trick is used to /// test code paths that differ between native and wasm versions. - const BLOATY_CODE: &[u8] = - include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.wasm"); + const BLOATY_CODE: &[u8] = node_runtime::WASM_BINARY_BLOATY; const GENESIS_HASH: [u8; 32] = [69u8; 32]; + const TX_FEE: u128 = 3 * CENTS + 460 * MILLICENTS; + type TestExternalities = CoreTestExternalities; fn alice() -> AccountId { @@ -131,7 +134,7 @@ mod tests { fn xt() -> UncheckedExtrinsic { sign(CheckedExtrinsic { signed: Some((alice(), 0)), - function: Call::Balances(balances::Call::transfer::(bob().into(), 69)), + function: Call::Balances(balances::Call::transfer::(bob().into(), 69 * DOLLARS)), }) } @@ -140,25 +143,16 @@ mod tests { } fn executor() -> ::substrate_executor::NativeExecutor { - ::substrate_executor::NativeExecutor::new(None) + substrate_executor::NativeExecutor::new(None) } #[test] fn panic_execution_with_foreign_code_gives_error() { let mut t = TestExternalities::::new_with_code(BLOATY_CODE, map![ blake2_256(&>::key_for(alice())).to_vec() => { - vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - }, - twox_128(>::key()).to_vec() => { - vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - }, - twox_128(>::key()).to_vec() => { vec![0u8; 16] }, - twox_128(>::key()).to_vec() => { - vec![0u8; 16] - }, - twox_128(>::key()).to_vec() => { + twox_128(>::key()).to_vec() => { vec![0u8; 16] }, twox_128(>::key()).to_vec() => { @@ -166,12 +160,6 @@ mod tests { }, blake2_256(&>::key_for(0)).to_vec() => { vec![0u8; 32] - }, - twox_128(>::key()).to_vec() => { - vec![70u8; 16] - }, - twox_128(>::key()).to_vec() => { - vec![0u8; 16] } ]); @@ -198,18 +186,9 @@ mod tests { fn bad_extrinsic_with_native_equivalent_code_gives_error() { let mut t = TestExternalities::::new_with_code(COMPACT_CODE, map![ blake2_256(&>::key_for(alice())).to_vec() => { - vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - }, - twox_128(>::key()).to_vec() => { - vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - }, - twox_128(>::key()).to_vec() => { vec![0u8; 16] }, - twox_128(>::key()).to_vec() => { - vec![0u8; 16] - }, - twox_128(>::key()).to_vec() => { + twox_128(>::key()).to_vec() => { vec![0u8; 16] }, twox_128(>::key()).to_vec() => { @@ -217,12 +196,6 @@ mod tests { }, blake2_256(&>::key_for(0)).to_vec() => { vec![0u8; 32] - }, - twox_128(>::key()).to_vec() => { - vec![70u8; 16] - }, - twox_128(>::key()).to_vec() => { - vec![0u8; 16] } ]); @@ -249,18 +222,13 @@ mod tests { fn successful_execution_with_native_equivalent_code_gives_ok() { let mut t = TestExternalities::::new_with_code(COMPACT_CODE, map![ blake2_256(&>::key_for(alice())).to_vec() => { - vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + (111 * DOLLARS).encode() }, twox_128(>::key()).to_vec() => { - vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + (111 * DOLLARS).encode() }, - twox_128(>::key()).to_vec() => vec![0u8; 16], - twox_128(>::key()).to_vec() => vec![0u8; 16], - twox_128(>::key()).to_vec() => vec![0u8; 16], twox_128(>::key()).to_vec() => vec![0u8; 16], - blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32], - twox_128(>::key()).to_vec() => vec![0u8; 16], - twox_128(>::key()).to_vec() => vec![0u8; 16] + blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32] ]); let r = executor().call::<_, NeverNativeValue, fn() -> _>( @@ -281,8 +249,8 @@ mod tests { assert!(r.is_ok()); runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 42); - assert_eq!(Balances::total_balance(&bob()), 69); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * TX_FEE); + assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } @@ -290,18 +258,13 @@ mod tests { fn successful_execution_with_foreign_code_gives_ok() { let mut t = TestExternalities::::new_with_code(BLOATY_CODE, map![ blake2_256(&>::key_for(alice())).to_vec() => { - vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + (111 * DOLLARS).encode() }, twox_128(>::key()).to_vec() => { - vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + (111 * DOLLARS).encode() }, - twox_128(>::key()).to_vec() => vec![0u8; 16], - twox_128(>::key()).to_vec() => vec![0u8; 16], - twox_128(>::key()).to_vec() => vec![0u8; 16], twox_128(>::key()).to_vec() => vec![0u8; 16], - blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32], - twox_128(>::key()).to_vec() => vec![0u8; 16], - twox_128(>::key()).to_vec() => vec![0u8; 16] + blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32] ]); let r = executor().call::<_, NeverNativeValue, fn() -> _>( @@ -322,18 +285,19 @@ mod tests { assert!(r.is_ok()); runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 42); - assert_eq!(Balances::total_balance(&bob()), 69); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * TX_FEE); + assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } fn to_session_keys(ring: &AuthorityKeyring) -> SessionKeys { - SessionKeys(ring.to_owned().into(), ring.to_owned().into()) + SessionKeys { + ed25519: ring.to_owned().into(), + } } fn new_test_ext(code: &[u8], support_changes_trie: bool) -> TestExternalities { - let three = AccountId::from_raw([3u8; 32]); - let mut ext = TestExternalities::new_with_code(code, GenesisConfig { + let mut ext = TestExternalities::new_with_code_with_children(code, GenesisConfig { aura: Some(Default::default()), system: Some(SystemConfig { changes_trie_config: if support_changes_trie { Some(ChangesTrieConfiguration { @@ -346,23 +310,17 @@ mod tests { ids: vec![alice(), bob(), charlie(), dave(), eve(), ferdie()], }), balances: Some(BalancesConfig { - transaction_base_fee: 1, - transaction_byte_fee: 0, balances: vec![ - (alice(), 111), - (bob(), 100), - (charlie(), 100_000_000), - (dave(), 111), - (eve(), 101), - (ferdie(), 100), + (alice(), 111 * DOLLARS), + (bob(), 100 * DOLLARS), + (charlie(), 100_000_000 * DOLLARS), + (dave(), 111 * DOLLARS), + (eve(), 101 * DOLLARS), + (ferdie(), 100 * DOLLARS), ], - existential_deposit: 0, - transfer_fee: 0, - creation_fee: 0, vesting: vec![], }), session: Some(SessionConfig { - validators: vec![AccountKeyring::One.into(), AccountKeyring::Two.into(), three], keys: vec![ (alice(), to_session_keys(&AuthorityKeyring::Alice)), (bob(), to_session_keys(&AuthorityKeyring::Bob)), @@ -372,9 +330,9 @@ mod tests { staking: Some(StakingConfig { current_era: 0, stakers: vec![ - (dave(), alice(), 111, staking::StakerStatus::Validator), - (eve(), bob(), 100, staking::StakerStatus::Validator), - (ferdie(), charlie(), 100, staking::StakerStatus::Validator) + (dave(), alice(), 111 * DOLLARS, staking::StakerStatus::Validator), + (eve(), bob(), 100 * DOLLARS, staking::StakerStatus::Validator), + (ferdie(), charlie(), 100 * DOLLARS, staking::StakerStatus::Validator) ], validator_count: 3, minimum_validator_count: 0, @@ -385,16 +343,18 @@ mod tests { invulnerables: vec![alice(), bob(), charlie()], }), democracy: Some(Default::default()), - council_seats: Some(Default::default()), - timestamp: Some(Default::default()), - treasury: Some(Default::default()), - contracts: Some(Default::default()), + collective_Instance1: Some(Default::default()), + collective_Instance2: Some(Default::default()), + elections: Some(Default::default()), + contracts: Some(ContractsConfig { + current_schedule: Default::default(), + gas_price: 1 * MILLICENTS, + }), sudo: Some(Default::default()), grandpa: Some(GrandpaConfig { - _genesis_phantom_data: Default::default(), authorities: vec![], }), - }.build_storage().unwrap().0); + }.build_storage().unwrap()); ext.changes_trie_storage().insert(0, GENESIS_HASH.into(), Default::default()); ext } @@ -470,7 +430,7 @@ mod tests { }, CheckedExtrinsic { signed: Some((alice(), 0)), - function: Call::Balances(balances::Call::transfer(bob().into(), 69)), + function: Call::Balances(balances::Call::transfer(bob().into(), 69 * DOLLARS)), }, ] ) @@ -492,7 +452,7 @@ mod tests { }, CheckedExtrinsic { signed: Some((alice(), 0)), - function: Call::Balances(balances::Call::transfer(bob().into(), 69)), + function: Call::Balances(balances::Call::transfer(bob().into(), 69 * DOLLARS)), }, ] ); @@ -507,11 +467,11 @@ mod tests { }, CheckedExtrinsic { signed: Some((bob(), 0)), - function: Call::Balances(balances::Call::transfer(alice().into(), 5)), + function: Call::Balances(balances::Call::transfer(alice().into(), 5 * DOLLARS)), }, CheckedExtrinsic { signed: Some((alice(), 1)), - function: Call::Balances(balances::Call::transfer(bob().into(), 15)), + function: Call::Balances(balances::Call::transfer(bob().into(), 15 * DOLLARS)), } ] ); @@ -559,9 +519,9 @@ mod tests { runtime_io::with_externalities(&mut t, || { // block1 transfers from alice 69 to bob. // -1 is the default fee - assert_eq!(Balances::total_balance(&alice()), 111 - 69 - 1); - assert_eq!(Balances::total_balance(&bob()), 100 + 69); - assert_eq!(System::events(), vec![ + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * TX_FEE); + assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS); + let events = vec![ EventRecord { phase: Phase::ApplyExtrinsic(0), event: Event::system(system::Event::ExtrinsicSuccess), @@ -572,8 +532,8 @@ mod tests { event: Event::balances(balances::RawEvent::Transfer( alice().into(), bob().into(), - 69, - 0 + 69 * DOLLARS, + 1 * CENTS )), topics: vec![], }, @@ -582,22 +542,8 @@ mod tests { event: Event::system(system::Event::ExtrinsicSuccess), topics: vec![], }, - EventRecord { - phase: Phase::Finalization, - event: Event::treasury(treasury::RawEvent::Spending(0)), - topics: vec![], - }, - EventRecord { - phase: Phase::Finalization, - event: Event::treasury(treasury::RawEvent::Burnt(0)), - topics: vec![], - }, - EventRecord { - phase: Phase::Finalization, - event: Event::treasury(treasury::RawEvent::Rollover(0)), - topics: vec![], - }, - ]); + ]; + assert_eq!(System::events(), events); }); executor().call::<_, NeverNativeValue, fn() -> _>( @@ -610,11 +556,11 @@ mod tests { runtime_io::with_externalities(&mut t, || { // bob sends 5, alice sends 15 | bob += 10, alice -= 10 - // 111 - 69 - 1 - 10 - 1 = 30 - assert_eq!(Balances::total_balance(&alice()), 111 - 69 - 1 - 10 - 1); - // 100 + 69 + 10 - 1 = 178 - assert_eq!(Balances::total_balance(&bob()), 100 + 69 + 10 - 1); - assert_eq!(System::events(), vec![ + // 111 - 69 - 10 = 32 + assert_eq!(Balances::total_balance(&alice()), 32 * DOLLARS - 2 * TX_FEE); + // 100 + 69 + 10 = 179 + assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - 1 * TX_FEE); + let events = vec![ EventRecord { phase: Phase::ApplyExtrinsic(0), event: Event::system(system::Event::ExtrinsicSuccess), @@ -626,8 +572,8 @@ mod tests { balances::RawEvent::Transfer( bob().into(), alice().into(), - 5, - 0 + 5 * DOLLARS, + 1 * CENTS, ) ), topics: vec![], @@ -643,8 +589,8 @@ mod tests { balances::RawEvent::Transfer( alice().into(), bob().into(), - 15, - 0 + 15 * DOLLARS, + 1 * CENTS, ) ), topics: vec![], @@ -654,22 +600,8 @@ mod tests { event: Event::system(system::Event::ExtrinsicSuccess), topics: vec![], }, - EventRecord { - phase: Phase::Finalization, - event: Event::treasury(treasury::RawEvent::Spending(0)), - topics: vec![], - }, - EventRecord { - phase: Phase::Finalization, - event: Event::treasury(treasury::RawEvent::Burnt(0)), - topics: vec![], - }, - EventRecord { - phase: Phase::Finalization, - event: Event::treasury(treasury::RawEvent::Rollover(0)), - topics: vec![], - }, - ]); + ]; + assert_eq!(System::events(), events); }); } @@ -683,19 +615,18 @@ mod tests { runtime_io::with_externalities(&mut t, || { // block1 transfers from alice 69 to bob. - // -1 is the default fee - assert_eq!(Balances::total_balance(&alice()), 111 - 69 - 1); - assert_eq!(Balances::total_balance(&bob()), 100 + 69); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * TX_FEE); + assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS); }); WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block2.0).unwrap(); runtime_io::with_externalities(&mut t, || { // bob sends 5, alice sends 15 | bob += 10, alice -= 10 - // 111 - 69 - 1 - 10 - 1 = 30 - assert_eq!(Balances::total_balance(&alice()), 111 - 69 - 1 - 10 - 1); - // 100 + 69 + 10 - 1 = 178 - assert_eq!(Balances::total_balance(&bob()), 100 + 69 + 10 - 1); + // 111 - 69 - 10 = 32 + assert_eq!(Balances::total_balance(&alice()), 32 * DOLLARS - 2 * TX_FEE); + // 100 + 69 + 10 = 179 + assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - 1 * TX_FEE); }); } @@ -711,22 +642,23 @@ mod tests { ;; input_data_len: u32 ;; ) -> u32 (import "env" "ext_call" (func $ext_call (param i32 i32 i64 i32 i32 i32 i32) (result i32))) - (import "env" "ext_input_size" (func $ext_input_size (result i32))) - (import "env" "ext_input_copy" (func $ext_input_copy (param i32 i32 i32))) + (import "env" "ext_scratch_size" (func $ext_scratch_size (result i32))) + (import "env" "ext_scratch_copy" (func $ext_scratch_copy (param i32 i32 i32))) (import "env" "memory" (memory 1 1)) (func (export "deploy") ) (func (export "call") (block $fail - ;; fail if ext_input_size != 4 + ;; load and check the input data (which is stored in the scratch buffer). + ;; fail if the input size is not != 4 (br_if $fail (i32.ne (i32.const 4) - (call $ext_input_size) + (call $ext_scratch_size) ) ) - (call $ext_input_copy + (call $ext_scratch_copy (i32.const 0) (i32.const 0) (i32.const 4) @@ -820,7 +752,7 @@ mod tests { CheckedExtrinsic { signed: Some((charlie(), 1)), function: Call::Contracts( - contracts::Call::create::(10, 10_000, transfer_ch, Vec::new()) + contracts::Call::create::(1 * DOLLARS, 10_000, transfer_ch, Vec::new()) ), }, CheckedExtrinsic { @@ -900,18 +832,13 @@ mod tests { fn panic_execution_gives_error() { let mut t = TestExternalities::::new_with_code(BLOATY_CODE, map![ blake2_256(&>::key_for(alice())).to_vec() => { - vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + vec![0u8; 16] }, twox_128(>::key()).to_vec() => { - vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + vec![0u8; 16] }, - twox_128(>::key()).to_vec() => vec![0u8; 16], - twox_128(>::key()).to_vec() => vec![0u8; 16], - twox_128(>::key()).to_vec() => vec![0u8; 16], twox_128(>::key()).to_vec() => vec![0u8; 16], - blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32], - twox_128(>::key()).to_vec() => vec![70u8; 16], - twox_128(>::key()).to_vec() => vec![0u8; 16] + blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32] ]); let r = WasmExecutor::new() @@ -927,18 +854,13 @@ mod tests { fn successful_execution_gives_ok() { let mut t = TestExternalities::::new_with_code(COMPACT_CODE, map![ blake2_256(&>::key_for(alice())).to_vec() => { - vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + (111 * DOLLARS).encode() }, twox_128(>::key()).to_vec() => { - vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + (111 * DOLLARS).encode() }, - twox_128(>::key()).to_vec() => vec![0u8; 16], - twox_128(>::key()).to_vec() => vec![0u8; 16], - twox_128(>::key()).to_vec() => vec![0u8; 16], twox_128(>::key()).to_vec() => vec![0u8; 16], - blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32], - twox_128(>::key()).to_vec() => vec![0u8; 16], - twox_128(>::key()).to_vec() => vec![0u8; 16] + blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32] ]); let r = WasmExecutor::new() @@ -950,8 +872,8 @@ mod tests { assert_eq!(r, Ok(ApplyOutcome::Success)); runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 42); - assert_eq!(Balances::total_balance(&bob()), 69); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * TX_FEE); + assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } diff --git a/node/primitives/Cargo.toml b/node/primitives/Cargo.toml index db40d91346ec10b344d7083800598f99bf6742a0..c4be1ef6f22e780ebd507b4cbecdb15af345844a 100644 --- a/node/primitives/Cargo.toml +++ b/node/primitives/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] serde = { version = "1.0", optional = true, features = ["derive"] } -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } primitives = { package = "substrate-primitives", path = "../../core/primitives", default-features = false } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } runtime_primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } diff --git a/node/primitives/src/lib.rs b/node/primitives/src/lib.rs index 8b7b2521e4000fc4c912023026dcc86d7f9b49e3..351bb4fa12ed5607c75c22018fb7076bc88cc991 100644 --- a/node/primitives/src/lib.rs +++ b/node/primitives/src/lib.rs @@ -41,12 +41,19 @@ pub type AccountIndex = u32; /// Balance of an account. pub type Balance = u128; -/// Alias to the signature scheme used for Aura authority signatures. -pub type AuraSignature = primitives::ed25519::Signature; +/// Type used for expressing timestamp. +pub type Moment = u64; + +/// The aura crypto scheme defined via the keypair type. +#[cfg(feature = "std")] +pub type AuraPair = primitives::ed25519::Pair; -/// The Ed25519 pub key of an session that belongs to an Aura authority of the chain. +/// Identity of an Aura authority. pub type AuraId = primitives::ed25519::Public; +/// Signature for an Aura authority. +pub type AuraSignature = primitives::ed25519::Signature; + /// Index of a transaction in the chain. pub type Index = u64; diff --git a/node/runtime/Cargo.toml b/node/runtime/Cargo.toml index f1981a585221eee50bc1f8e03e9551deade49546..3bf28f7df2a2e6b030eed7a337a1e7f4bb2c8d45 100644 --- a/node/runtime/Cargo.toml +++ b/node/runtime/Cargo.toml @@ -3,11 +3,12 @@ name = "node-runtime" version = "2.0.0" authors = ["Parity Technologies "] edition = "2018" +build = "build.rs" [dependencies] integer-sqrt = { version = "0.1.2" } safe-mix = { version = "1.0", default-features = false } -parity-codec = { version = "3.5.1", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } substrate-primitives = { path = "../../core/primitives", default-features = false } client = { package = "substrate-client", path = "../../core/client", default-features = false } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } @@ -16,15 +17,17 @@ offchain-primitives = { package = "substrate-offchain-primitives", path = "../.. version = { package = "sr-version", path = "../../core/sr-version", default-features = false } support = { package = "srml-support", path = "../../srml/support", default-features = false } aura = { package = "srml-aura", path = "../../srml/aura", default-features = false } +authorship = { package = "srml-authorship", path = "../../srml/authorship", default-features = false } balances = { package = "srml-balances", path = "../../srml/balances", default-features = false } contracts = { package = "srml-contracts", path = "../../srml/contracts", default-features = false } -council = { package = "srml-council", path = "../../srml/council", default-features = false } +collective = { package = "srml-collective", path = "../../srml/collective", default-features = false } democracy = { package = "srml-democracy", path = "../../srml/democracy", default-features = false } +elections = { package = "srml-elections", path = "../../srml/elections", default-features = false } executive = { package = "srml-executive", path = "../../srml/executive", default-features = false } finality-tracker = { package = "srml-finality-tracker", path = "../../srml/finality-tracker", default-features = false } grandpa = { package = "srml-grandpa", path = "../../srml/grandpa", default-features = false } indices = { package = "srml-indices", path = "../../srml/indices", default-features = false } -session = { package = "srml-session", path = "../../srml/session", default-features = false } +session = { package = "srml-session", path = "../../srml/session", default-features = false, features = ["historical"] } staking = { package = "srml-staking", path = "../../srml/staking", default-features = false } system = { package = "srml-system", path = "../../srml/system", default-features = false } timestamp = { package = "srml-timestamp", path = "../../srml/timestamp", default-features = false } @@ -36,9 +39,12 @@ rustc-hex = { version = "2.0", optional = true } serde = { version = "1.0", optional = true } substrate-keyring = { path = "../../core/keyring", optional = true } +[build-dependencies] +wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.2", path = "../../core/utils/wasm-builder-runner" } + [features] default = ["std"] -core = [ +no_std = [ "contracts/core", ] std = [ @@ -48,10 +54,12 @@ std = [ "runtime_primitives/std", "support/std", "aura/std", + "authorship/std", "balances/std", "contracts/std", - "council/std", + "collective/std", "democracy/std", + "elections/std", "executive/std", "finality-tracker/std", "grandpa/std", diff --git a/node/runtime/build.rs b/node/runtime/build.rs new file mode 100644 index 0000000000000000000000000000000000000000..39aecacb20e0fcbe4d5c6ee639e531a6734b1eeb --- /dev/null +++ b/node/runtime/build.rs @@ -0,0 +1,27 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +use wasm_builder_runner::{build_current_project, WasmBuilderSource}; + +fn main() { + build_current_project( + "wasm_binary.rs", + WasmBuilderSource::CratesOrPath { + path: "../../core/utils/wasm-builder", + version: "1.0.4", + }, + ); +} diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index ec529696a8e0636acd014d922e724bdb92cc4637..601f49566b34140c0909dbf58939dd92aa715e88 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -21,45 +21,56 @@ #![recursion_limit="256"] use rstd::prelude::*; -use support::{construct_runtime, parameter_types}; +use support::{ + construct_runtime, parameter_types, traits::{SplitTwoWays, Currency, OnUnbalanced} +}; use substrate_primitives::u32_trait::{_1, _2, _3, _4}; use node_primitives::{ - AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, Signature, AuraId + AccountId, AccountIndex, AuraId, Balance, BlockNumber, Hash, Index, + Moment, Signature, }; use grandpa::fg_primitives::{self, ScheduledChange}; use client::{ block_builder::api::{self as block_builder_api, InherentData, CheckInherentsResult}, runtime_api as client_api, impl_runtime_apis }; -use runtime_primitives::{ApplyResult, generic, create_runtime_str}; +use runtime_primitives::{ApplyResult, impl_opaque_keys, generic, create_runtime_str, key_types}; use runtime_primitives::transaction_validity::TransactionValidity; use runtime_primitives::traits::{ BlakeTwo256, Block as BlockT, DigestFor, NumberFor, StaticLookup, Convert, }; use version::RuntimeVersion; -use council::{motions as council_motions}; -#[cfg(feature = "std")] -use council::seats as council_seats; +use elections::VoteIndex; #[cfg(any(feature = "std", test))] use version::NativeVersion; use substrate_primitives::OpaqueMetadata; use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight}; +use finality_tracker::{DEFAULT_REPORT_LATENCY, DEFAULT_WINDOW_SIZE}; #[cfg(any(feature = "std", test))] pub use runtime_primitives::BuildStorage; pub use timestamp::Call as TimestampCall; pub use balances::Call as BalancesCall; -pub use runtime_primitives::{Permill, Perbill, impl_opaque_keys}; +pub use contracts::Gas; +pub use runtime_primitives::{Permill, Perbill}; pub use support::StorageValue; pub use staking::StakerStatus; +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + /// Runtime version. pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("node"), impl_name: create_runtime_str!("substrate-node"), authoring_version: 10, - spec_version: 96, - impl_version: 96, + // Per convention: if the runtime behavior changes, increment spec_version + // and set impl_version to equal spec_version. If only runtime + // implementation changes and behavior does not, then leave spec_version as + // is and increment impl_version. + spec_version: 111, + impl_version: 111, apis: RUNTIME_API_VERSIONS, }; @@ -72,18 +83,34 @@ pub fn native_version() -> NativeVersion { } } -pub struct CurrencyToVoteHandler; +pub const MILLICENTS: Balance = 1_000_000_000; +pub const CENTS: Balance = 1_000 * MILLICENTS; // assume this is worth about a cent. +pub const DOLLARS: Balance = 100 * CENTS; -impl CurrencyToVoteHandler { - fn factor() -> u128 { (Balances::total_issuance() / u64::max_value() as u128).max(1) } -} +type NegativeImbalance = >::NegativeImbalance; -impl Convert for CurrencyToVoteHandler { - fn convert(x: u128) -> u64 { (x / Self::factor()) as u64 } +pub struct Author; + +impl OnUnbalanced for Author { + fn on_unbalanced(amount: NegativeImbalance) { + Balances::resolve_creating(&Authorship::author(), amount); + } } -impl Convert for CurrencyToVoteHandler { - fn convert(x: u128) -> u128 { x * Self::factor() } +pub type DealWithFees = SplitTwoWays< + Balance, + NegativeImbalance, + _4, Treasury, // 4 parts (80%) goes to the treasury. + _1, Author, // 1 part (20%) goes to the block author. +>; + +pub const SECS_PER_BLOCK: Moment = 6; +pub const MINUTES: Moment = 60 / SECS_PER_BLOCK; +pub const HOURS: Moment = MINUTES * 60; +pub const DAYS: Moment = HOURS * 24; + +parameter_types! { + pub const BlockHashCount: BlockNumber = 250; } impl system::Trait for Runtime { @@ -96,6 +123,7 @@ impl system::Trait for Runtime { type Lookup = Indices; type Header = generic::Header; type Event = Event; + type BlockHashCount = BlockHashCount; } impl aura::Trait for Runtime { @@ -110,19 +138,48 @@ impl indices::Trait for Runtime { type Event = Event; } +parameter_types! { + pub const ExistentialDeposit: Balance = 1 * DOLLARS; + pub const TransferFee: Balance = 1 * CENTS; + pub const CreationFee: Balance = 1 * CENTS; + pub const TransactionBaseFee: Balance = 1 * CENTS; + pub const TransactionByteFee: Balance = 10 * MILLICENTS; +} + impl balances::Trait for Runtime { type Balance = Balance; type OnFreeBalanceZero = ((Staking, Contracts), Session); type OnNewAccount = Indices; type Event = Event; - type TransactionPayment = (); + type TransactionPayment = DealWithFees; type DustRemoval = (); type TransferPayment = (); + type ExistentialDeposit = ExistentialDeposit; + type TransferFee = TransferFee; + type CreationFee = CreationFee; + type TransactionBaseFee = TransactionBaseFee; + type TransactionByteFee = TransactionByteFee; } +parameter_types! { + pub const MinimumPeriod: u64 = SECS_PER_BLOCK / 2; +} impl timestamp::Trait for Runtime { - type Moment = u64; + type Moment = Moment; type OnTimestampSet = Aura; + type MinimumPeriod = MinimumPeriod; +} + +parameter_types! { + pub const UncleGenerations: u64 = 0; +} + +// TODO: #2986 implement this properly +impl authorship::Trait for Runtime { + type FindAuthor = (); + type UncleGenerations = UncleGenerations; + type FilterUncle = (); + type EventHandler = (); } parameter_types! { @@ -131,8 +188,12 @@ parameter_types! { } type SessionHandlers = (Grandpa, Aura); + impl_opaque_keys! { - pub struct SessionKeys(grandpa::AuthorityId, AuraId); + pub struct SessionKeys { + #[id(key_types::ED25519)] + pub ed25519: GrandpaId, + } } // NOTE: `SessionHandler` and `SessionKeys` are co-dependent: One key will be used for each handler. @@ -147,6 +208,14 @@ impl session::Trait for Runtime { type ShouldEndSession = session::PeriodicSessions; type Event = Event; type Keys = SessionKeys; + type ValidatorId = AccountId; + type ValidatorIdOf = staking::StashOf; + type SelectInitialValidators = Staking; +} + +impl session::historical::Trait for Runtime { + type FullIdentification = staking::Exposure; + type FullIdentificationOf = staking::ExposureOf; } parameter_types! { @@ -154,6 +223,20 @@ parameter_types! { pub const BondingDuration: staking::EraIndex = 24 * 28; } +pub struct CurrencyToVoteHandler; + +impl CurrencyToVoteHandler { + fn factor() -> u128 { (Balances::total_issuance() / u64::max_value() as u128).max(1) } +} + +impl Convert for CurrencyToVoteHandler { + fn convert(x: u128) -> u64 { (x / Self::factor()) as u64 } +} + +impl Convert for CurrencyToVoteHandler { + fn convert(x: u128) -> u128 { x * Self::factor() } +} + impl staking::Trait for Runtime { type Currency = Balances; type CurrencyToVote = CurrencyToVoteHandler; @@ -163,19 +246,18 @@ impl staking::Trait for Runtime { type Reward = (); type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; + type SessionInterface = Self; } -const MINUTES: BlockNumber = 6; -const BUCKS: Balance = 1_000_000_000_000; - parameter_types! { pub const LaunchPeriod: BlockNumber = 28 * 24 * 60 * MINUTES; pub const VotingPeriod: BlockNumber = 28 * 24 * 60 * MINUTES; pub const EmergencyVotingPeriod: BlockNumber = 3 * 24 * 60 * MINUTES; - pub const MinimumDeposit: Balance = 100 * BUCKS; + pub const MinimumDeposit: Balance = 100 * DOLLARS; pub const EnactmentPeriod: BlockNumber = 30 * 24 * 60 * MINUTES; pub const CooloffPeriod: BlockNumber = 30 * 24 * 60 * MINUTES; } + impl democracy::Trait for Runtime { type Proposal = Call; type Event = Event; @@ -185,47 +267,110 @@ impl democracy::Trait for Runtime { type VotingPeriod = VotingPeriod; type EmergencyVotingPeriod = EmergencyVotingPeriod; type MinimumDeposit = MinimumDeposit; - type ExternalOrigin = council_motions::EnsureProportionAtLeast<_1, _2, AccountId>; - type ExternalMajorityOrigin = council_motions::EnsureProportionAtLeast<_2, _3, AccountId>; - type EmergencyOrigin = council_motions::EnsureProportionAtLeast<_1, _1, AccountId>; - type CancellationOrigin = council_motions::EnsureProportionAtLeast<_2, _3, AccountId>; - type VetoOrigin = council_motions::EnsureMember; + type ExternalOrigin = collective::EnsureProportionAtLeast<_1, _2, AccountId, CouncilInstance>; + type ExternalMajorityOrigin = collective::EnsureProportionAtLeast<_2, _3, AccountId, CouncilInstance>; + type ExternalPushOrigin = collective::EnsureProportionAtLeast<_2, _3, AccountId, TechnicalInstance>; + type EmergencyOrigin = collective::EnsureProportionAtLeast<_1, _1, AccountId, CouncilInstance>; + type CancellationOrigin = collective::EnsureProportionAtLeast<_2, _3, AccountId, CouncilInstance>; + type VetoOrigin = collective::EnsureMember; type CooloffPeriod = CooloffPeriod; } -impl council::Trait for Runtime { +type CouncilInstance = collective::Instance1; +impl collective::Trait for Runtime { + type Origin = Origin; + type Proposal = Call; type Event = Event; +} + +parameter_types! { + pub const CandidacyBond: Balance = 10 * DOLLARS; + pub const VotingBond: Balance = 1 * DOLLARS; + pub const VotingFee: Balance = 2 * DOLLARS; + pub const PresentSlashPerVoter: Balance = 1 * CENTS; + pub const CarryCount: u32 = 6; + // one additional vote should go by before an inactive voter can be reaped. + pub const InactiveGracePeriod: VoteIndex = 1; + pub const ElectionsVotingPeriod: BlockNumber = 2 * DAYS; + pub const DecayRatio: u32 = 0; +} + +impl elections::Trait for Runtime { + type Event = Event; + type Currency = Balances; type BadPresentation = (); type BadReaper = (); type BadVoterIndex = (); type LoserCandidate = (); - type OnMembersChanged = CouncilMotions; + type ChangeMembers = Council; + type CandidacyBond = CandidacyBond; + type VotingBond = VotingBond; + type VotingFee = VotingFee; + type PresentSlashPerVoter = PresentSlashPerVoter; + type CarryCount = CarryCount; + type InactiveGracePeriod = InactiveGracePeriod; + type VotingPeriod = ElectionsVotingPeriod; + type DecayRatio = DecayRatio; } -impl council::motions::Trait for Runtime { +type TechnicalInstance = collective::Instance2; +impl collective::Trait for Runtime { type Origin = Origin; type Proposal = Call; type Event = Event; } +parameter_types! { + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const ProposalBondMinimum: Balance = 1 * DOLLARS; + pub const SpendPeriod: BlockNumber = 1 * DAYS; + pub const Burn: Permill = Permill::from_percent(50); +} + impl treasury::Trait for Runtime { type Currency = Balances; - type ApproveOrigin = council_motions::EnsureMembers<_4, AccountId>; - type RejectOrigin = council_motions::EnsureMembers<_2, AccountId>; + type ApproveOrigin = collective::EnsureMembers<_4, AccountId, CouncilInstance>; + type RejectOrigin = collective::EnsureMembers<_2, AccountId, CouncilInstance>; type Event = Event; type MintedForSpending = (); type ProposalRejection = (); + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ProposalBondMinimum; + type SpendPeriod = SpendPeriod; + type Burn = Burn; +} + +parameter_types! { + pub const ContractTransferFee: Balance = 1 * CENTS; + pub const ContractCreationFee: Balance = 1 * CENTS; + pub const ContractTransactionBaseFee: Balance = 1 * CENTS; + pub const ContractTransactionByteFee: Balance = 10 * MILLICENTS; + pub const ContractFee: Balance = 1 * CENTS; } impl contracts::Trait for Runtime { type Currency = Balances; type Call = Call; type Event = Event; - type Gas = u64; type DetermineContractAddress = contracts::SimpleAddressDeterminator; type ComputeDispatchFee = contracts::DefaultDispatchFeeComputor; type TrieIdGenerator = contracts::TrieIdFromParentCounter; type GasPayment = (); + type SignedClaimHandicap = contracts::DefaultSignedClaimHandicap; + type TombstoneDeposit = contracts::DefaultTombstoneDeposit; + type StorageSizeOffset = contracts::DefaultStorageSizeOffset; + type RentByteFee = contracts::DefaultRentByteFee; + type RentDepositOffset = contracts::DefaultRentDepositOffset; + type SurchargeReward = contracts::DefaultSurchargeReward; + type TransferFee = ContractTransferFee; + type CreationFee = ContractCreationFee; + type TransactionBaseFee = ContractTransactionBaseFee; + type TransactionByteFee = ContractTransactionByteFee; + type ContractFee = ContractFee; + type CallBaseFee = contracts::DefaultCallBaseFee; + type CreateBaseFee = contracts::DefaultCreateBaseFee; + type MaxDepth = contracts::DefaultMaxDepth; + type BlockGasLimit = contracts::DefaultBlockGasLimit; } impl sudo::Trait for Runtime { @@ -237,8 +382,15 @@ impl grandpa::Trait for Runtime { type Event = Event; } +parameter_types! { + pub const WindowSize: BlockNumber = DEFAULT_WINDOW_SIZE.into(); + pub const ReportLatency: BlockNumber = DEFAULT_REPORT_LATENCY.into(); +} + impl finality_tracker::Trait for Runtime { type OnFinalizationStalled = Grandpa; + type WindowSize = WindowSize; + type ReportLatency = ReportLatency; } construct_runtime!( @@ -247,20 +399,21 @@ construct_runtime!( NodeBlock = node_primitives::Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: system, - Aura: aura::{Module, Config, Inherent(Timestamp)}, - Timestamp: timestamp::{Module, Call, Storage, Config, Inherent}, + System: system::{Module, Call, Storage, Config, Event}, + Aura: aura::{Module, Call, Storage, Config, Inherent(Timestamp)}, + Timestamp: timestamp::{Module, Call, Storage, Inherent}, + Authorship: authorship::{Module, Call, Storage}, Indices: indices, Balances: balances, - Session: session::{Module, Call, Storage, Event, Config}, Staking: staking::{default, OfflineWorker}, - Democracy: democracy, - Council: council::{Module, Call, Storage, Event}, - CouncilMotions: council_motions::{Module, Call, Storage, Event, Origin}, - CouncilSeats: council_seats::{Config}, + Session: session::{Module, Call, Storage, Event, Config}, + Democracy: democracy::{Module, Call, Storage, Config, Event}, + Council: collective::::{Module, Call, Storage, Origin, Event, Config}, + TechnicalCommittee: collective::::{Module, Call, Storage, Origin, Event, Config}, + Elections: elections::{Module, Call, Storage, Event, Config}, FinalityTracker: finality_tracker::{Module, Call, Inherent}, - Grandpa: grandpa::{Module, Call, Storage, Config, Event}, - Treasury: treasury, + Grandpa: grandpa::{Module, Call, Storage, Config, Event}, + Treasury: treasury::{Module, Call, Storage, Event}, Contracts: contracts, Sudo: sudo, } diff --git a/node/runtime/wasm/Cargo.lock b/node/runtime/wasm/Cargo.lock deleted file mode 100644 index 89c1bf93034c6519fe7ceb422c23f73e003ed67b..0000000000000000000000000000000000000000 --- a/node/runtime/wasm/Cargo.lock +++ /dev/null @@ -1,3964 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "adler32" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "aes-ctr" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aes-soft" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aesni" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aho-corasick" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aio-limited" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "arrayref" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "arrayvec" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "asn1_der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "asn1_der_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "asn1_der_derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "atty" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "autocfg" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "backtrace" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "backtrace-sys" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "base58" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "base64" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bigint" -version = "4.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bitflags" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitmask" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "blake2" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "blake2-rfc" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "block-buffer" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "block-cipher-trait" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "block-padding" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bs58" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "build_const" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bumpalo" -version = "2.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byte-tools" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byteorder" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byteorder" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bytes" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "c_linked_list" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cc" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cfg-if" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "chrono" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "clear_on_drop" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "constant_time_eq" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "crc" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crc32fast" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-channel" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-deque" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-deque" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-deque" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-queue" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-utils" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-utils" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crunchy" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "crypto-mac" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crypto-mac" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ctr" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cuckoofilter" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "curve25519-dalek" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "data-encoding" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "derive_more" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "digest" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "digest" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "dns-parser" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ed25519-dalek" -version = "1.0.0-pre.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "curve25519-dalek 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "either" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "elastic-array" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "env_logger" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "environmental" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "erased-serde" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "failure" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "failure_derive" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fixed-hash" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "flate2" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fnv" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "futures" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "futures-cpupool" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "gcc" -version = "0.3.55" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "generic-array" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "generic-array" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "get_if_addrs" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "c_linked_list 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "get_if_addrs-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "get_if_addrs-sys" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hash-db" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "hash256-std-hasher" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hashbrown" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hashmap_core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "heapsize" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "heck" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hex" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "hex-literal" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "hex-literal-impl 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hex-literal-impl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hmac" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crypto-mac 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hmac" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hmac-drbg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "http" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "httparse" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "humantime" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "idna" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "impl-codec" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "impl-serde" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "impl-serde" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "integer-sqrt" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "iovec" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ipnet" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "itoa" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "js-sys" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "keccak" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kvdb" -version = "0.1.0" -source = "git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d#b0317f649ab2c665b7987b8475878fc4d2e1f81d" -dependencies = [ - "elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)", -] - -[[package]] -name = "lazy_static" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.55" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libp2p" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core-derive 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-deflate 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-dns 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-floodsub 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-identify 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-kad 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-mdns 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-mplex 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-noise 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-ping 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-plaintext 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-ratelimit 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-secio 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-tcp 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-uds 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-wasm-ext 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-websocket 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-yamux 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multihash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-core" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "asn1_der 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "multistream-select 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multihash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rw-stream-sink 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-core-derive" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-deflate" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-dns" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-dns-unofficial 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-floodsub" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "cuckoofilter 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-identify" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-kad" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multihash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-mdns" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "dns-parser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-mplex" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-noise" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "curve25519-dalek 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "snow 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "x25519-dalek 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-ping" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-plaintext" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-ratelimit" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aio-limited 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-secio" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "asn1_der 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rw-stream-sink 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "twofish 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-futures 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-tcp" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "get_if_addrs 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ipnet 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tk-listen 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-uds" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-wasm-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-futures 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-websocket" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rw-stream-sink 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "soketto 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-rustls 0.10.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki-roots 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libp2p-yamux" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "yamux 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libsecp256k1" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac-drbg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lock_api" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lock_api" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "log" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "matches" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "memchr" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "memoffset" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "memory-db" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hashmap_core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "memory_units" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "merlin" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miniz-sys" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miniz_oxide" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miniz_oxide_c_api" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mio" -version = "0.6.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mio-uds" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miow" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (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 = "multistream-select" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "net2" -version = "0.2.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "node-primitives" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "node-runtime" -version = "2.0.0" -dependencies = [ - "integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "node-primitives 2.0.0", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "sr-version 2.0.0", - "srml-aura 2.0.0", - "srml-balances 2.0.0", - "srml-contracts 2.0.0", - "srml-council 2.0.0", - "srml-democracy 2.0.0", - "srml-executive 2.0.0", - "srml-finality-tracker 2.0.0", - "srml-grandpa 2.0.0", - "srml-indices 2.0.0", - "srml-session 2.0.0", - "srml-staking 2.0.0", - "srml-sudo 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", - "srml-timestamp 2.0.0", - "srml-treasury 2.0.0", - "substrate-client 2.0.0", - "substrate-consensus-aura-primitives 2.0.0", - "substrate-keyring 2.0.0", - "substrate-offchain-primitives 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "node-runtime-wasm" -version = "2.0.0" -dependencies = [ - "node-runtime 2.0.0", -] - -[[package]] -name = "nodrop" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "nohash-hasher" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "nom" -version = "4.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-integer" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-traits" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num_cpus" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "numtoa" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "once_cell" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "opaque-debug" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "owning_ref" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "owning_ref" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-bytes" -version = "0.1.0" -source = "git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d#b0317f649ab2c665b7987b8475878fc4d2e1f81d" - -[[package]] -name = "parity-codec" -version = "3.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-codec-derive" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-multiaddr" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multihash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-multihash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "blake2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-send-wrapper" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "parity-wasm" -version = "0.31.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot_core" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot_core" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "paste" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "paste-impl" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-hack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "pbkdf2" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "percent-encoding" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "primitive-types" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fixed-hash 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-codec 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "uint 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro-crate" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro-hack" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro-hack-impl" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "protobuf" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "pwasm-utils" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quick-error" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quick-error" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quote" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rayon" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rayon-core" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "redox_syscall" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_termios" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex-syntax" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ring" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rustc-hex" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustls" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "sct 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rw-stream-sink" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ryu" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "safe-mix" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "schnorrkel" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "curve25519-dalek 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "merlin 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "scopeguard" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "scopeguard" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "sct" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "send_wrapper" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "serde" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_derive" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_json" -version = "1.0.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sha-1" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sha1" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "sha2" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sha2" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sha3" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "slab" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "slog" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "slog-json" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "slog-scope" -version = "4.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "smallvec" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "snow" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "static_slice 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "soketto" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sourcefile" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "spin" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "sr-api-macros" -version = "2.0.0" -dependencies = [ - "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sr-io" -version = "2.0.0" -dependencies = [ - "environmental 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-std 2.0.0", - "substrate-primitives 2.0.0", - "substrate-state-machine 2.0.0", - "substrate-trie 2.0.0", - "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sr-primitives" -version = "2.0.0" -dependencies = [ - "integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-std 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "sr-sandbox" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-std 2.0.0", - "substrate-primitives 2.0.0", - "wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sr-std" -version = "2.0.0" -dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sr-version" -version = "2.0.0" -dependencies = [ - "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", -] - -[[package]] -name = "srml-aura" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-session 2.0.0", - "srml-staking 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", - "srml-timestamp 2.0.0", - "substrate-consensus-aura-primitives 2.0.0", - "substrate-inherents 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "srml-balances" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", - "substrate-keyring 2.0.0", -] - -[[package]] -name = "srml-contracts" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)", - "pwasm-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-sandbox 2.0.0", - "sr-std 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", - "srml-timestamp 2.0.0", - "substrate-primitives 2.0.0", - "wasmi-validation 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "srml-council" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-democracy 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "srml-democracy" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", -] - -[[package]] -name = "srml-executive" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", -] - -[[package]] -name = "srml-finality-tracker" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", - "substrate-inherents 2.0.0", -] - -[[package]] -name = "srml-grandpa" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-finality-tracker 2.0.0", - "srml-session 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", - "substrate-finality-grandpa-primitives 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "srml-indices" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", - "substrate-keyring 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "srml-metadata" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-std 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "srml-session" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", - "srml-timestamp 2.0.0", -] - -[[package]] -name = "srml-staking" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-session 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", - "substrate-keyring 2.0.0", -] - -[[package]] -name = "srml-sudo" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-support 2.0.0", - "srml-support-procedural 2.0.0", - "srml-system 2.0.0", -] - -[[package]] -name = "srml-support" -version = "2.0.0" -dependencies = [ - "bitmask 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-metadata 2.0.0", - "srml-support-procedural 2.0.0", - "substrate-inherents 2.0.0", -] - -[[package]] -name = "srml-support-procedural" -version = "2.0.0" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-api-macros 2.0.0", - "srml-support-procedural-tools 2.0.0", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "srml-support-procedural-tools" -version = "2.0.0" -dependencies = [ - "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "srml-support-procedural-tools-derive 2.0.0", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "srml-support-procedural-tools-derive" -version = "2.0.0" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "srml-system" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-support 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "srml-timestamp" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", - "substrate-inherents 2.0.0", -] - -[[package]] -name = "srml-treasury" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "srml-balances 2.0.0", - "srml-support 2.0.0", - "srml-system 2.0.0", -] - -[[package]] -name = "stable_deref_trait" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "static_assertions" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "static_slice" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "stream-cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "strum" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "strum_macros" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-bip39" -version = "0.2.1" -source = "git+https://github.com/paritytech/substrate-bip39#44307fda4ea17fe97aeb93af317fbc8f6ed34193" -dependencies = [ - "hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-client" -version = "2.0.0" -dependencies = [ - "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "kvdb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-api-macros 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "sr-version 2.0.0", - "substrate-consensus-common 2.0.0", - "substrate-executor 2.0.0", - "substrate-inherents 2.0.0", - "substrate-keyring 2.0.0", - "substrate-primitives 2.0.0", - "substrate-state-machine 2.0.0", - "substrate-telemetry 2.0.0", - "substrate-trie 2.0.0", -] - -[[package]] -name = "substrate-consensus-aura-primitives" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "substrate-client 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "substrate-consensus-common" -version = "2.0.0" -dependencies = [ - "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "sr-version 2.0.0", - "substrate-inherents 2.0.0", - "substrate-primitives 2.0.0", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-executor" -version = "2.0.0" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-version 2.0.0", - "substrate-panic-handler 2.0.0", - "substrate-primitives 2.0.0", - "substrate-serializer 2.0.0", - "substrate-state-machine 2.0.0", - "substrate-trie 2.0.0", - "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-finality-grandpa-primitives" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "substrate-client 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "substrate-inherents" -version = "2.0.0" -dependencies = [ - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "sr-std 2.0.0", -] - -[[package]] -name = "substrate-keyring" -version = "2.0.0" -dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "strum 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "strum_macros 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "substrate-offchain-primitives" -version = "2.0.0" -dependencies = [ - "sr-primitives 2.0.0", - "substrate-client 2.0.0", -] - -[[package]] -name = "substrate-panic-handler" -version = "2.0.0" -dependencies = [ - "backtrace 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-primitives" -version = "2.0.0" -dependencies = [ - "base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hash256-std-hasher 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "primitive-types 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-std 2.0.0", - "substrate-bip39 0.2.1 (git+https://github.com/paritytech/substrate-bip39)", - "tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "twox-hash 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-serializer" -version = "2.0.0" -dependencies = [ - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-state-machine" -version = "2.0.0" -dependencies = [ - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "substrate-panic-handler 2.0.0", - "substrate-primitives 2.0.0", - "substrate-trie 2.0.0", - "trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-telemetry" -version = "2.0.0" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-scope 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "substrate-trie" -version = "2.0.0" -dependencies = [ - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "memory-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-std 2.0.0", - "substrate-primitives 2.0.0", - "trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "subtle" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "subtle" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "syn" -version = "0.15.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "synstructure" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "termcolor" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "termion" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread_local" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "time" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tiny-bip39" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tiny-keccak" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tk-listen" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-trace-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-codec" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-current-thread" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-dns-unofficial" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-executor" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-fs" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-io" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-reactor" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-rustls" -version = "0.10.0-alpha.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustls 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-sync" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-tcp" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-threadpool" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-timer" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-trace-core" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-udp" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-uds" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "toml" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "trie-db" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hashmap_core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "trie-root" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "twofish" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "twox-hash" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "typenum" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "ucd-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "uint" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-segmentation" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unsigned-varint" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "untrusted" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "url" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "utf8-ranges" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "wasm-bindgen" -version = "0.2.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "wasm-bindgen-macro 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bumpalo 2.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro-support 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-backend 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.45" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "wasm-bindgen-webidl" -version = "0.2.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-backend 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "weedle 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasm-timer" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "send_wrapper 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasmi" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmi-validation 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasmi-validation" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "web-sys" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-webidl 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "webpki" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "webpki-roots" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "weedle" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-util" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "wincolor" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "x25519-dalek" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "curve25519-dalek 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "yamux" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "nohash-hasher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zeroize" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "zeroize" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "zeroize_derive 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zeroize_derive" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[metadata] -"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" -"checksum aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2e5b0458ea3beae0d1d8c0f3946564f8e10f90646cf78c06b4351052058d1ee" -"checksum aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" -"checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" -"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" -"checksum aio-limited 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f10b352bc3fc08ae24dc5d2d3ddcac153678533986122dc283d747b12071000" -"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" -"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" -"checksum asn1_der 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9893d63fc3b1c44231e667da6836a33f27d8b6b3bdc82f83da5dfd579d1b6528" -"checksum asn1_der_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e7f92edafad155aff997fa5b727c6429b91e996b5a5d62a2b0adbae1306b5fe" -"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" -"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" -"checksum backtrace 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)" = "1a13fc43f04daf08ab4f71e3d27e1fc27fc437d3e95ac0063a796d92fb40f39b" -"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" -"checksum base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" -"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" -"checksum bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebecac13b3c745150d7b6c3ea7572d372f09d627c2077e893bf26c5c7f70d282" -"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum bitmask 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5da9b3d9f6f585199287a473f4f8dfab6566cf827d15c00c219f53c645687ead" -"checksum blake2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91721a6330935673395a0607df4d49a9cb90ae12d259f1b3e0a3f6e1d486872e" -"checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" -"checksum block-buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1339a1042f5d9f295737ad4d9a6ab6bf81c84a933dba110b9200cd6d1448b814" -"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" -"checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" -"checksum bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0de79cfb98e7aa9988188784d8664b4b5dad6eaaa0863b91d9a4ed871d4f7a42" -"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" -"checksum bumpalo 2.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "84dca3afd8e01b9526818b7963e5b4916063b3cdf9f10cf6b73ef0bd0ec37aa5" -"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" -"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" -"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" -"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" -"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -"checksum c_linked_list 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4964518bd3b4a8190e832886cdc0da9794f12e8e6c1613a9e90ff331c4c8724b" -"checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d" -"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" -"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" -"checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" -"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" -"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" -"checksum crossbeam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad4c7ea749d9fb09e23c5cb17e3b70650860553a0e2744e38446b1803bf7db94" -"checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" -"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" -"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" -"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" -"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" -"checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" -"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" -"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" -"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" -"checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" -"checksum crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -"checksum crypto-mac 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "779015233ac67d65098614aec748ac1c756ab6677fa2e14cf8b37c08dfed1198" -"checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" -"checksum ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "022cd691704491df67d25d006fe8eca083098253c4d43516c2206479c58c6736" -"checksum cuckoofilter 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd43f7cfaffe0a386636a10baea2ee05cc50df3b77bea4a456c9572a939bf1f" -"checksum curve25519-dalek 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "750226d75fc2f5a8daec6e7477624e258674023eb73d8d647f63b943ca182a4a" -"checksum data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f47ca1860a761136924ddd2422ba77b2ea54fe8cc75b9040804a0d9d32ad97" -"checksum derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6d944ac6003ed268757ef1ee686753b57efc5fcf0ebe7b64c9fc81e7e32ff839" -"checksum digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5b29bf156f3f4b3c4f610a25ff69370616ae6e0657d416de22645483e72af0a" -"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" -"checksum dns-parser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea" -"checksum ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81956bcf7ef761fb4e1d88de3fa181358a0d26cbcb9755b587a08f9119824b86" -"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" -"checksum elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "073be79b6538296faf81c631872676600616073817dd9a440c477ad09b408983" -"checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a" -"checksum environmental 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c7464757b80de8930c91c9afe77ddce501826bf9d134a87db2c67d9dc177e2c" -"checksum erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3beee4bc16478a1b26f2e80ad819a52d24745e292f521a63c16eea5f74b7eb60" -"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" -"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" -"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" -"checksum fixed-hash 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d1a683d1234507e4f3bf2736eeddf0de1dc65996dc0164d57eba0a74bcf29489" -"checksum flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f87e68aa82b2de08a6e037f1385455759df6e445a8df5e005b4297191dbf18aa" -"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)" = "a2037ec1c6c1c4f79557762eab1f7eae1f64f6cb418ace90fae88f0942b60139" -"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" -"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" -"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" -"checksum generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fceb69994e330afed50c93524be68c42fa898c2d9fd4ee8da03bd7363acd26f2" -"checksum get_if_addrs 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "abddb55a898d32925f3148bd281174a68eeb68bbfd9a5938a57b18f506ee4ef7" -"checksum get_if_addrs-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0d04f9fb746cf36b191c00f3ede8bde9c8e64f9f4b05ae2694a9ccf5e3f5ab48" -"checksum hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ba7fb417e5c470acdd61068c79767d0e65962e70836cf6c9dfd2409f06345ce0" -"checksum hash256-std-hasher 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b2027c19ec91eb304999abae7307d225cf93be42af53b0039f76e98ed5af86" -"checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da" -"checksum hashmap_core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8e04cb7a5051270ef3fa79f8c7604d581ecfa73d520e74f554e45541c4b5881a" -"checksum heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461" -"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" -"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" -"checksum hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ddc2928beef125e519d69ae1baa8c37ea2e0d3848545217f6db0179c5eb1d639" -"checksum hex-literal-impl 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "520870c3213943eb8d7803e80180d12a6c7ceb4ae74602544529d1643dc4ddda" -"checksum hmac 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a13f4163aa0c5ca1be584aace0e2212b2e41be5478218d4f657f5f778b2ae2a" -"checksum hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f127a908633569f208325f86f71255d3363c79721d7f9fe31cd5569908819771" -"checksum hmac-drbg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fe727d41d2eec0a6574d887914347e5ff96a3b87177817e2a9820c5c87fecc2" -"checksum http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "eed324f0f0daf6ec10c474f150505af2c143f251722bf9dbd1261bd1f2ee2c1a" -"checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" -"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" -"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -"checksum impl-codec 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2050d823639fbeae26b2b5ba09aca8907793117324858070ade0673c49f793b" -"checksum impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5158079de9d4158e0ce1de3ae0bd7be03904efc40b3d7dd8b8c301cbf6b52b56" -"checksum impl-serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d26be4b97d738552ea423f76c4f681012ff06c3fa36fa968656b3679f60b4a1" -"checksum integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ea155abb3ba6f382a75f1418988c05fe82959ed9ce727de427f9cfd425b0c903" -"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" -"checksum ipnet 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e61c2da0d0f700c77d2d313dbf4f93e41d235fa12c6681fee06621036df4c2af" -"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" -"checksum js-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "9987e7c13a91d9cf0efe59cca48a3a7a70e2b11695d5a4640f85ae71e28f5e73" -"checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum kvdb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" -"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "42914d39aad277d9e176efbdad68acb1d5443ab65afe0e0e4f0d49352a950880" -"checksum libp2p 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6abde4e6fc777dc06ae2a15202ddedb1a38d7c71ed16bc10fa704b03f73aec37" -"checksum libp2p-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b4ceb4791289534d4c1ad8e4bd3c6f06d3670efa55ce71482951a287df93ddd1" -"checksum libp2p-core-derive 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "851a59dcaab66c96777ae0cace96de88a700243c3b8360ab51c7e093f3727066" -"checksum libp2p-deflate 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "902b44e92e1f8b7e697b3a186d15c841e0e38037f14286513207a5407650a635" -"checksum libp2p-dns 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71a6630a84552b39e5f752e1f6a951d31f3211079465d2e7af73491b6f48fc3f" -"checksum libp2p-floodsub 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9fced4da0c31e0dc8a759472c65fab41db40c01de2d93bc45e1431c13f0564f0" -"checksum libp2p-identify 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1ba5e882d72c71cdf77f45ab68dd715451d3b78a23085f8d385c7a31ec1b4272" -"checksum libp2p-kad 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d71966dbbb4cedcfcdb1d4c87d5dbb6f3f07b465d1ca74f2624256669997d1f2" -"checksum libp2p-mdns 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdbdaea6f0049cc09ba5db00308f5b93105a8a33b65ba2e36bd35da707850ea2" -"checksum libp2p-mplex 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b351bfd67e97154e7b60f62402237671486c8a89f83eabdb6838f37d4d5f006" -"checksum libp2p-noise 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44324032b2f9260d2b862c741d79d250dc02298dbba56354a992528a826ee2d5" -"checksum libp2p-ping 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1ac43ffd01de4210cf1b969bbb55a008c77f9ec22b74df26a6590bb6bd4c93f" -"checksum libp2p-plaintext 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0506e10770bcbcb59f2a6154ce93c8fd5cb9730b6ceb5aa1463164af1fd0b9c6" -"checksum libp2p-ratelimit 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3886b79a35c0348497bab763517a9a2b4965173f4b4c7438d59f1e4dcf5122ff" -"checksum libp2p-secio 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b811272e5cd86d39bd71fb94687025d9802b13daf0998ebe0d3f2885c636c51a" -"checksum libp2p-tcp 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b2c54cb75f17557de6ce0149aa03e729455e2d240f84d854272bc4b11012a324" -"checksum libp2p-uds 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fbedf4a1e72a5f67523915414e9e12d71d128731873f0f24d8b878398fb47aa4" -"checksum libp2p-wasm-ext 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c1f615b56aa2a6f4ec07bf9667be9fff8877b9c5bd5335601af47490eda341" -"checksum libp2p-websocket 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a0d1bfe60577558f48a9fdf9f35c0ee2dc5baa01f685ff847d3b5cf4f12ee135" -"checksum libp2p-yamux 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bf4bfc7ff127cd622502dbe56f10513dd6776b970e33d8ebb6e367f0752324f6" -"checksum libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "688e8d65e495567c2c35ea0001b26b9debf0b4ea11f8cccc954233b75fc3428a" -"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" -"checksum lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed946d4529956a20f2d63ebe1b69996d5a2137c91913fe3ebbeff957f5bca7ff" -"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" -"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" -"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum memory-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7623b01a4f1b7acb7cf8e3f678f05e15e6ae26cb0b738dfeb5cc186fd6b82ef4" -"checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" -"checksum merlin 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8c39467de91b004f5b9c06fac5bbc8e7d28309a205ee66905166b70804a71fea" -"checksum miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9e3ae51cea1576ceba0dde3d484d30e6e5b86dee0b2d412fe3a16a15c98202" -"checksum miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c468f2369f07d651a5d0bb2c9079f8488a66d5466efe42d0c5c6466edcb7f71e" -"checksum miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7fe927a42e3807ef71defb191dc87d4e24479b221e67015fe38ae2b7b447bab" -"checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" -"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" -"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum multistream-select 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f989d40aab0ed0d83c1cdb4856b5790e980b96548d1a921f280e985eb049f38d" -"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" -"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" -"checksum nohash-hasher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0d138afcce92d219ccb6eb53d9b1e8a96ac0d633cfd3c53cd9856d96d1741bb8" -"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" -"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" -"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" -"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" -"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" -"checksum once_cell 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "532c29a261168a45ce28948f9537ddd7a5dd272cc513b3017b1e82a88f962c37" -"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" -"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" -"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" -"checksum parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" -"checksum parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dcb43c05fb71c03b4ea7327bf15694da1e0f23f19d5b1e95bab6c6d74097e336" -"checksum parity-codec-derive 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "00a486fd383382ddcb2de928364b1f82571c1e48274fc43b7667a4738ee4056c" -"checksum parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "045b3c7af871285146300da35b1932bb6e4639b66c7c98e85d06a32cbc4e8fa7" -"checksum parity-multihash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05d6a68e07ab34a9e87bd8dd4936f6bb5be21e4f6dbcdbaf04d8e854eba0af01" -"checksum parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f" -"checksum parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)" = "511379a8194230c2395d2f5fa627a5a7e108a9f976656ce723ae68fca4097bfc" -"checksum parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4d05f1349491390b1730afba60bb20d55761bef489a954546b58b4b34e1e2ac" -"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" -"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" -"checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7" -"checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" -"checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c" -"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" -"checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c" -"checksum paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4a4a1c555c6505821f9d58b8779d0f630a6b7e4e1be24ba718610acf01fa79" -"checksum paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "26e796e623b8b257215f27e6c80a5478856cae305f5b59810ff9acdaa34570e6" -"checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" -"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" -"checksum primitive-types 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6e8612a8dc70f26276fed6131c153ca277cf275ee0a5e2a50cd8a69c697beb8f" -"checksum proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e" -"checksum proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c725b36c99df7af7bf9324e9c999b9e37d92c8f8caf106d82e1d7953218d2d8" -"checksum proc-macro-hack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0c1dd4172a1e1f96f709341418f49b11ea6c2d95d53dca08c0f74cbd332d9cf3" -"checksum proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b753ad9ed99dd8efeaa7d2fb8453c8f6bc3e54b97966d35f1bc77ca6865254a" -"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum protobuf 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a151c11a92df0059d6ab446fafa3b21a1210aad4bc2293e1c946e8132b10db01" -"checksum pwasm-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "efb0dcbddbb600f47a7098d33762a00552c671992171637f5bb310b37fe1f0e4" -"checksum quick-error 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5fb6ccf8db7bbcb9c2eae558db5ab4f3da1c2a87e4e597ed394726bc8ea6ca1d" -"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" -"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" -"checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" -"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -"checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473" -"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" -"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58" -"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" -"checksum ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)" = "426bc186e3e95cac1e4a4be125a4aca7e84c2d616ffc02244eef36e2a60a093c" -"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" -"checksum rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "403bb3a286107a04825a5f82e1270acc1e14028d3d554d7a1e08914549575ab8" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rustls 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f271e3552cd835fa28c541c34a7e8fdd8cdff09d77fe4eb8f6c42e87a11b096e" -"checksum rw-stream-sink 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9cbe61c20455d3015b2bb7be39e1872310283b8e5a52f5b242b0ac7581fe78" -"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f" -"checksum safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7bf422d23a88c16d5090d455f182bc99c60af4df6a345c63428acf5129e347" -"checksum schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5eff518f9bed3d803a0d002af0ab96339b0ebbedde3bec98a684986134b7a39" -"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" -"checksum sct 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f5adf8fbd58e1b1b52699dc8bed2630faecb6d8c7bee77d009d6bbe4af569b9" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum send_wrapper 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0eddf2e8f50ced781f288c19f18621fa72a3779e3cb58dbf23b07469b0abeb4" -"checksum serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)" = "a72e9b96fa45ce22a4bc23da3858dfccfd60acd28a25bcd328a98fdd6bea43fd" -"checksum serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)" = "101b495b109a3e3ca8c4cbe44cf62391527cdfb6ba15821c5ce80bcd5ea23f9f" -"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" -"checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68" -"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" -"checksum sha2 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d963c78ce367df26d7ea8b8cc655c651b42e8a1e584e869c1e17dae3ccb116a" -"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" -"checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" -"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1e1a2eec401952cd7b12a84ea120e2d57281329940c3f93c2bf04f462539508e" -"checksum slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddc0d2aff1f8f325ef660d9a0eb6e6dcd20b30b3f581a5897f58bf42d061c37a" -"checksum slog-scope 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "60c04b4726fa04595ccf2c2dad7bcd15474242c4c5e109a8a376e8a2c9b1539a" -"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" -"checksum snow 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5a64f02fd208ef15bd2d1a65861df4707e416151e1272d02c8faafad1c138100" -"checksum soketto 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8cf3ae22c0bce5437c7dce6a2b00e492c19da1feb21ad64a7b6fd7058438c3f2" -"checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3" -"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" -"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" -"checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" -"checksum static_slice 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "92a7e0c5e3dfb52e8fbe0e63a1b947bbb17b4036408b151353c4491374931362" -"checksum stream-cipher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8861bc80f649f5b4c9bd38b696ae9af74499d479dbfb327f0607de6b326a36bc" -"checksum strum 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1810e25f576e7ffce1ff5243b37066da5ded0310b3274c20baaeccb1145b2806" -"checksum strum_macros 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "572a2f4e53dd4c3483fd79e5cc10ddd773a3acb1169bbfe8762365e107110579" -"checksum substrate-bip39 0.2.1 (git+https://github.com/paritytech/substrate-bip39)" = "" -"checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" -"checksum subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "01dca13cf6c3b179864ab3292bd794e757618d35a7766b7c46050c614ba00829" -"checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe" -"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" -"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" -"checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea" -"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" -"checksum tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c1c5676413eaeb1ea35300a0224416f57abc3bd251657e0fafc12c47ff98c060" -"checksum tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e9175261fbdb60781fcd388a4d6cc7e14764a2b629a7ad94abb439aed223a44f" -"checksum tk-listen 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5462b0f968c0457efe38fcd2df7e487096b992419e4f5337b06775a614bbda4b" -"checksum tokio 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "94a1f9396aec29d31bb16c24d155cfa144d1af91c40740125db3131bdaf76da8" -"checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" -"checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443" -"checksum tokio-dns-unofficial 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82c65483db54eb91b4ef3a9389a3364558590faf30ce473141707c0e16fda975" -"checksum tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "83ea44c6c0773cc034771693711c35c677b4b5a4b21b9e7071704c54de7d555e" -"checksum tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe6dc22b08d6993916647d108a1a7d15b9cd29c4f4496c62b92c45b5041b7af" -"checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926" -"checksum tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6af16bfac7e112bea8b0442542161bfc41cbfa4466b580bdda7d18cb88b911ce" -"checksum tokio-rustls 0.10.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)" = "316fdbc899efec48b3b492bd0f339e6d81c4ee96a409257572147ec341943452" -"checksum tokio-sync 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "5b2f843ffdf8d6e1f90bddd48da43f99ab071660cd92b7ec560ef3cdfd7a409a" -"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" -"checksum tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72558af20be886ea124595ea0f806dd5703b8958e4705429dd58b3d8231f72f2" -"checksum tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f2106812d500ed25a4f38235b9cae8f78a09edf43203e16e59c3b769a342a60e" -"checksum tokio-trace-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "350c9edade9830dc185ae48ba45667a445ab59f6167ef6d0254ec9d2430d9dd3" -"checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92" -"checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" -"checksum toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8c96d7873fa7ef8bdeb3a9cda3ac48389b4154f32b9803b4bc26220b677b039" -"checksum trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1ba73747fd3a64ab531274c04cb588dfa9d30d972d62990831e63fbce2cfec59" -"checksum trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfa2e20c4f1418ac2e71ddc418e35e1b56e34022e2146209ffdbf1b2de8b1bd9" -"checksum twofish 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d261e83e727c8e2dbb75dacac67c36e35db36a958ee504f2164fc052434e1" -"checksum twox-hash 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6c7bcecad121018bdcd6b709fa2325b004878fcb3d3067934ce90749f0faff9a" -"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" -"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" -"checksum uint 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2143cded94692b156c356508d92888acc824db5bffc0b4089732264c6fcf86d4" -"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" -"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2c64cdf40b4a9645534a943668681bcb219faf51874d4b65d2e0abda1b10a2ab" -"checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" -"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" -"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum wasm-bindgen 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "b7ccc7b93cfd13e26700a9e2e41e6305f1951b87e166599069f77d10358100e6" -"checksum wasm-bindgen-backend 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "1953f91b1608eb1522513623c7739f047bb0fed4128ce51a93f08e12cc314645" -"checksum wasm-bindgen-futures 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "fa1af11c73eca3dc8c51c76ea475a4416e912da6402064a49fc6c0214701866d" -"checksum wasm-bindgen-macro 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "0f69da5696545d7ca6607a2e4b1a0edf5a6b36b2c49dbb0f1df6ad1d92884047" -"checksum wasm-bindgen-macro-support 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d4246f3bc73223bbb846f4f2430a60725826a96c9389adf715ed1d5af46dec6" -"checksum wasm-bindgen-shared 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "c08381e07e7a79e5e229ad7c60d15833d19033542cc5dd91d085df59d235f4a6" -"checksum wasm-bindgen-webidl 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "1f42ff7adb8102bf5ad8adbc45b1635c520c8175f9fdf6eb2c54479d485d435a" -"checksum wasm-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad9ac33c834103916e373d648adf65f58c83fb3d8a0f3e6b9a64bca7253a4dca" -"checksum wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aebbaef470840d157a5c47c8c49f024da7b1b80e90ff729ca982b2b80447e78b" -"checksum wasmi-validation 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab380192444b3e8522ae79c0a1976e42a82920916ccdfbce3def89f456ea33f3" -"checksum web-sys 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "540b8259eb242ff3a566fa0140bda03a4ece4e5c226e1284b5c95dddcd4341f6" -"checksum webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4f7e1cd7900a3a6b65a3e8780c51a3e6b59c0e2c55c6dc69578c288d69f7d082" -"checksum webpki-roots 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c10fa4212003ba19a564f25cd8ab572c6791f99a03cc219c13ed35ccab00de0e" -"checksum weedle 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc44aa200daee8b1f3a004beaf16554369746f1b4486f0cf93b0caf8a3c2d1e" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" -"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -"checksum x25519-dalek 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7ee1585dc1484373cbc1cee7aafda26634665cf449436fd6e24bfd1fad230538" -"checksum yamux 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "01bd67889938c48f0049fc60a77341039e6c3eaf16cb7693e6ead7c0ba701295" -"checksum zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8ddfeb6eee2fb3b262ef6e0898a52b7563bb8e0d5955a313b3cf2f808246ea14" -"checksum zeroize 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b60a6c572b91d8ecb0a460950d84fe5b40699edd07d65f73789b31237afc8f66" -"checksum zeroize_derive 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9dac4b660d969bff9c3fe1847a891cacaa8b21dd5f2aae6e0a3e0975aea96431" diff --git a/node/runtime/wasm/Cargo.toml b/node/runtime/wasm/Cargo.toml deleted file mode 100644 index e98d4cb918a916577c63a3de5298c0510bdc08c8..0000000000000000000000000000000000000000 --- a/node/runtime/wasm/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "node-runtime-wasm" -version = "2.0.0" -authors = ["Parity Technologies "] -edition = "2018" - -[lib] -name = "node_runtime" -crate-type = ["cdylib"] - -[dependencies] -node-runtime = { path = "..", default-features = false } - -[features] -default = ["core"] -core = [ - "node-runtime/core", -] -std = [ - "node-runtime/std", -] - -[profile.release] -panic = "abort" -lto = true - -[workspace] -members = [] diff --git a/node/runtime/wasm/build.sh b/node/runtime/wasm/build.sh deleted file mode 100755 index 4a81e47f9ee843943de032c4177c8b693f6e92d5..0000000000000000000000000000000000000000 --- a/node/runtime/wasm/build.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -set -e - -if cargo --version | grep -q "nightly"; then - CARGO_CMD="cargo" -else - CARGO_CMD="cargo +nightly" -fi -CARGO_INCREMENTAL=0 RUSTFLAGS="-C link-arg=--export-table" $CARGO_CMD build --target=wasm32-unknown-unknown --release "$@" -for i in node_runtime -do - wasm-gc target/wasm32-unknown-unknown/release/$i.wasm target/wasm32-unknown-unknown/release/$i.compact.wasm -done diff --git a/scripts/build.sh b/scripts/build.sh deleted file mode 100755 index d79ebe52301e5e0d764eff3203a0feda2b09c771..0000000000000000000000000000000000000000 --- a/scripts/build.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash - -# This script assumes that all pre-requisites are installed. - -set -e - -PROJECT_ROOT=`git rev-parse --show-toplevel` -source "`dirname \"$0\"`/common.sh" - -export CARGO_INCREMENTAL=0 - -# Save current directory. -pushd . - -cd -- "$ROOT" - -for SRC in "${SRCS[@]}" -do - echo "*** Building wasm binaries in $SRC" - cd "$PROJECT_ROOT/$SRC" - - ./build.sh "$@" - - cd - >> /dev/null -done - -# Restore initial directory. -popd diff --git a/scripts/gitlab/check_runtime.sh b/scripts/gitlab/check_runtime.sh index 03c46601360d16d49dff9c95d198f29b0757d40d..725c5077c56494838ba283a59bddf991585bbdef 100755 --- a/scripts/gitlab/check_runtime.sh +++ b/scripts/gitlab/check_runtime.sh @@ -112,10 +112,7 @@ else # drop through into pushing `gotissues` and exit 1... fi -# dropped through. there's something wrong; mark `gotissues` and exit 1. - -github_label "A4-gotissues" - +# dropped through. there's something wrong; exit 1. exit 1 diff --git a/scripts/node-template-release/src/main.rs b/scripts/node-template-release/src/main.rs index 470d34ef0d8837f335e5842e8168b49a1511ab51..4036104f6030a243f44deaf25664597ad13ed69b 100644 --- a/scripts/node-template-release/src/main.rs +++ b/scripts/node-template-release/src/main.rs @@ -136,9 +136,6 @@ fn write_cargo_toml(path: &Path, cargo_toml: CargoToml) { /// Build and test the generated node-template fn build_and_test(path: &Path, cargo_tomls: &[PathBuf]) { - // Build wasm - assert!(Command::new(path.join("./scripts/build.sh")).current_dir(path).status().expect("Compiles wasm").success()); - // Build node assert!(Command::new("cargo").args(&["build", "--all"]).current_dir(path).status().expect("Compiles node").success()); diff --git a/scripts/sentry-node/docker-compose.yml b/scripts/sentry-node/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..78f8ba36b82eed93e7c72a0b40ea43d9a85364fd --- /dev/null +++ b/scripts/sentry-node/docker-compose.yml @@ -0,0 +1,140 @@ +# Docker compose file to simulate a sentry node setup. +# +# +# Setup: +# +# Validator A is not supposed to be connected to the public internet. Instead it +# connects to a sentry node (sentry-a) which connects to the public internet. +# Validator B can reach validator A via sentry node A and vice versa. +# +# +# Usage: +# +# 1. Build `target/release/substrate` binary: `cargo build --release` +# +# 2. Start networks and containers: `sudo docker-compose -f scripts/sentry-node/docker-compose.yml up` +# +# 3. Reach: +# - polkadot/apps on localhost:3000 +# - validator-a: localhost:9944 +# - validator-b: localhost:9945 +# - sentry-a: localhost:9946 + +version: "3.7" +services: + + validator-a: + ports: + - "9944:9944" + volumes: + - ../../target/release/substrate:/usr/local/bin/substrate + image: parity/substrate + networks: + - network-a + command: + # Local node id: QmRpheLN4JWdAnY7HGJfWFNbfkQCb6tFf4vvA6hgjMZKrR + - "--node-key" + - "0000000000000000000000000000000000000000000000000000000000000001" + - "--base-path" + - "/tmp/alice" + - "--chain=local" + - "--key" + - "//Alice" + - "--port" + - "30333" + - "--validator" + - "--name" + - "AlicesNode" + - "--reserved-nodes" + - "/dns4/sentry-a/tcp/30333/p2p/QmV7EhW6J6KgmNdr558RH1mPx2xGGznW7At4BhXzntRFsi" + # Not only bind to localhost. + - "--ws-external" + - "--rpc-external" + # - "--log" + # - "sub-libp2p=trace" + # - "--log" + # - "afg=trace" + - "--no-telemetry" + - "--rpc-cors" + - "all" + + sentry-a: + image: parity/substrate + ports: + - "9946:9944" + volumes: + - ../../target/release/substrate:/usr/local/bin/substrate + networks: + - network-a + - internet + command: + # Local node id: QmV7EhW6J6KgmNdr558RH1mPx2xGGznW7At4BhXzntRFsi + - "--node-key" + - "0000000000000000000000000000000000000000000000000000000000000003" + - "--base-path" + - "/tmp/sentry" + - "--chain=local" + # Don't configure a key, as sentry-a is not a validator. + # - "--key" + # - "//Charlie" + - "--port" + - "30333" + # sentry-a is not a validator. + # - "--validator" + - "--name" + - "CharliesNode" + - "--bootnodes" + - "/dns4/validator-a/tcp/30333/p2p/QmRpheLN4JWdAnY7HGJfWFNbfkQCb6tFf4vvA6hgjMZKrR" + - "--bootnodes" + - "/dns4/validator-b/tcp/30333/p2p/QmSVnNf9HwVMT1Y4cK1P6aoJcEZjmoTXpjKBmAABLMnZEk" + - "--no-telemetry" + - "--rpc-cors" + - "all" + # Not only bind to localhost. + - "--ws-external" + - "--rpc-external" + # Make sure sentry-a still participates as a grandpa voter to forward + # grandpa finality gossip messages. + - "--grandpa-voter" + + validator-b: + image: parity/substrate + ports: + - "9945:9944" + volumes: + - ../../target/release/substrate:/usr/local/bin/substrate + networks: + - internet + command: + # Local node id: QmSVnNf9HwVMT1Y4cK1P6aoJcEZjmoTXpjKBmAABLMnZEk + - "--node-key" + - "0000000000000000000000000000000000000000000000000000000000000002" + - "--base-path" + - "/tmp/bob" + - "--chain=local" + - "--key" + - "//Bob" + - "--port" + - "30333" + - "--validator" + - "--name" + - "BobsNode" + - "--bootnodes" + - "/dns4/validator-a/tcp/30333/p2p/QmRpheLN4JWdAnY7HGJfWFNbfkQCb6tFf4vvA6hgjMZKrR" + - "--bootnodes" + - "/dns4/sentry-a/tcp/30333/p2p/QmV7EhW6J6KgmNdr558RH1mPx2xGGznW7At4BhXzntRFsi" + - "--no-telemetry" + - "--rpc-cors" + - "all" + # Not only bind to localhost. + - "--ws-external" + - "--rpc-external" + + ui: + image: polkadot-js/apps + ports: + - "3000:80" + +networks: + network-a: + internet: diff --git a/srml/assets/Cargo.toml b/srml/assets/Cargo.toml index 88a443db94cdb80c3b48e8f1407193b3e16ad8d2..977248a7a7ca144010f16bd0cfd011f6f15ead05 100644 --- a/srml/assets/Cargo.toml +++ b/srml/assets/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] serde = { version = "1.0", optional = true } -parity-codec = { version = "3.3", default-features = false } +parity-codec = { version = "4.1.1", default-features = false } # Needed for various traits. In our case, `OnFinalize`. primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } # Needed for type-safe access to storage DB. diff --git a/srml/assets/src/lib.rs b/srml/assets/src/lib.rs index d563db3b14146eb01bd22a937e10867a03c17ee2..19159bf60fba356fb649d86e2e951e7fb1571848 100644 --- a/srml/assets/src/lib.rs +++ b/srml/assets/src/lib.rs @@ -240,15 +240,11 @@ mod tests { use super::*; use runtime_io::with_externalities; - use srml_support::{impl_outer_origin, assert_ok, assert_noop}; + use srml_support::{impl_outer_origin, assert_ok, assert_noop, parameter_types}; use substrate_primitives::{H256, Blake2Hasher}; // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. - use primitives::{ - BuildStorage, - traits::{BlakeTwo256, IdentityLookup}, - testing::Header - }; + use primitives::{traits::{BlakeTwo256, IdentityLookup}, testing::Header}; impl_outer_origin! { pub enum Origin for Test {} @@ -259,6 +255,9 @@ mod tests { // configuration traits of modules we want to use. #[derive(Clone, Eq, PartialEq)] pub struct Test; + parameter_types! { + pub const BlockHashCount: u64 = 250; + } impl system::Trait for Test { type Origin = Origin; type Index = u64; @@ -269,6 +268,7 @@ mod tests { type Lookup = IdentityLookup; type Header = Header; type Event = (); + type BlockHashCount = BlockHashCount; } impl Trait for Test { type Event = (); @@ -280,7 +280,7 @@ mod tests { // This function basically just builds a genesis storage key/value store according to // our desired mockup. fn new_test_ext() -> runtime_io::TestExternalities { - system::GenesisConfig::::default().build_storage().unwrap().0.into() + system::GenesisConfig::default().build_storage::().unwrap().0.into() } #[test] diff --git a/srml/aura/Cargo.toml b/srml/aura/Cargo.toml index 5624df7be6c54f6b90effeb4b2f7ea10b375c90f..c1bf922a581af181a4a10fa9f132426e24c56fab 100644 --- a/srml/aura/Cargo.toml +++ b/srml/aura/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0", optional = true } inherents = { package = "substrate-inherents", path = "../../core/inherents", default-features = false } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } diff --git a/srml/aura/src/lib.rs b/srml/aura/src/lib.rs index 43f2da88af8000571631d501b6e3a41a52e928ab..1e92d411f4e0125bcbbea348ece1dbbf03b1d37d 100644 --- a/srml/aura/src/lib.rs +++ b/srml/aura/src/lib.rs @@ -52,8 +52,11 @@ pub use timestamp; use rstd::{result, prelude::*}; use parity_codec::Encode; -use srml_support::{decl_storage, decl_module, Parameter, storage::StorageValue}; -use primitives::{traits::{SaturatedConversion, Saturating, Zero, One, Member}, generic::DigestItem}; +use srml_support::{decl_storage, decl_module, Parameter, storage::StorageValue, traits::Get}; +use primitives::{ + traits::{SaturatedConversion, Saturating, Zero, One, Member, TypedKey}, + generic::DigestItem, +}; use timestamp::OnTimestampSet; #[cfg(feature = "std")] use timestamp::TimestampInherentData; @@ -153,7 +156,7 @@ pub trait Trait: timestamp::Trait { type HandleReport: HandleReport; /// The identifier type for an authority. - type AuthorityId: Member + Parameter + Default; + type AuthorityId: Member + Parameter + TypedKey + Default; } decl_storage! { @@ -184,6 +187,7 @@ impl Module { impl session::OneSessionHandler for Module { type Key = T::AuthorityId; + fn on_new_session<'a, I: 'a>(changed: bool, validators: I) where I: Iterator { @@ -196,8 +200,13 @@ impl session::OneSessionHandler for Module { } } } - fn on_disabled(_i: usize) { - // ignore? + fn on_disabled(i: usize) { + let log: DigestItem = DigestItem::Consensus( + AURA_ENGINE_ID, + ConsensusLog::::OnDisabled(i as u64).encode(), + ); + + >::deposit_log(log.into()); } } @@ -234,7 +243,7 @@ impl Module { pub fn slot_duration() -> T::Moment { // we double the minimum block-period so each author can always propose within // the majority of its slot. - >::minimum_period().saturating_mul(2.into()) + ::MinimumPeriod::get().saturating_mul(2.into()) } fn on_timestamp_set(now: T::Moment, slot_duration: T::Moment) { @@ -274,7 +283,8 @@ pub struct StakingSlasher(::rstd::marker::PhantomData); impl HandleReport for StakingSlasher { fn handle_report(report: AuraReport) { - let validators = session::Module::::validators(); + use staking::SessionInterface; + let validators = T::SessionInterface::validators(); report.punish( validators.len(), diff --git a/srml/aura/src/mock.rs b/srml/aura/src/mock.rs index e9c43850f6e01648c99809be89dc18a701abaa32..0cce522c76032aee17174747d9489fed562ff977 100644 --- a/srml/aura/src/mock.rs +++ b/srml/aura/src/mock.rs @@ -18,8 +18,11 @@ #![cfg(test)] -use primitives::{BuildStorage, traits::IdentityLookup, testing::{Header, UintAuthorityId}}; -use srml_support::impl_outer_origin; +use primitives::{ + traits::IdentityLookup, + testing::{Header, UintAuthorityId}, +}; +use srml_support::{impl_outer_origin, parameter_types}; use runtime_io; use substrate_primitives::{H256, Blake2Hasher}; use crate::{Trait, Module, GenesisConfig}; @@ -32,6 +35,11 @@ impl_outer_origin!{ #[derive(Clone, PartialEq, Eq, Debug)] pub struct Test; +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MinimumPeriod: u64 = 1; +} + impl system::Trait for Test { type Origin = Origin; type Index = u64; @@ -42,11 +50,13 @@ impl system::Trait for Test { type Lookup = IdentityLookup; type Header = Header; type Event = (); + type BlockHashCount = BlockHashCount; } impl timestamp::Trait for Test { type Moment = u64; type OnTimestampSet = Aura; + type MinimumPeriod = MinimumPeriod; } impl Trait for Test { @@ -55,10 +65,7 @@ impl Trait for Test { } pub fn new_test_ext(authorities: Vec) -> runtime_io::TestExternalities { - let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; - t.extend(timestamp::GenesisConfig::{ - minimum_period: 1, - }.build_storage().unwrap().0); + let mut t = system::GenesisConfig::default().build_storage::().unwrap().0; t.extend(GenesisConfig::{ authorities: authorities.into_iter().map(|a| UintAuthorityId(a)).collect(), }.build_storage().unwrap().0); diff --git a/srml/authorship/Cargo.toml b/srml/authorship/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..0cf2f1e256f0cbd839f76e1aeafff02251208a2a --- /dev/null +++ b/srml/authorship/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "srml-authorship" +version = "0.1.0" +description = "Block and Uncle Author tracking for the SRML" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +substrate-primitives = { path = "../../core/primitives", default-features = false } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } +rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } +primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } +srml-support = { path = "../support", default-features = false } +system = { package = "srml-system", path = "../system", default-features = false } +runtime_io = { package = "sr-io", path = "../../core/sr-io", default-features = false } + +[features] +default = ["std"] +std = [ + "parity-codec/std", + "substrate-primitives/std", + "rstd/std", + "srml-support/std", + "primitives/std", + "system/std", + "runtime_io/std", +] diff --git a/srml/authorship/src/lib.rs b/srml/authorship/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..758eeb285e19746867748811358668e4fd9dcf06 --- /dev/null +++ b/srml/authorship/src/lib.rs @@ -0,0 +1,632 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +//! Authorship tracking for SRML runtimes. +//! +//! This tracks the current author of the block and recent uncles. + +#![cfg_attr(not(feature = "std"), no_std)] + +use rstd::prelude::*; +use rstd::collections::btree_set::BTreeSet; +use srml_support::{decl_module, decl_storage, for_each_tuple, StorageValue}; +use srml_support::traits::{FindAuthor, VerifySeal, Get}; +use srml_support::dispatch::Result as DispatchResult; +use parity_codec::{Encode, Decode}; +use system::ensure_none; +use primitives::traits::{SimpleArithmetic, Header as HeaderT, One, Zero}; + +pub trait Trait: system::Trait { + /// Find the author of a block. + type FindAuthor: FindAuthor; + /// The number of blocks back we should accept uncles. + /// This means that we will deal with uncle-parents that are + /// `UncleGenerations + 1` before `now`. + type UncleGenerations: Get; + /// A filter for uncles within a block. This is for implementing + /// further constraints on what uncles can be included, other than their ancestry. + /// + /// For PoW, as long as the seals are checked, there is no need to use anything + /// but the `VerifySeal` implementation as the filter. This is because the cost of making many equivocating + /// uncles is high. + /// + /// For PoS, there is no such limitation, so a further constraint must be imposed + /// beyond a seal check in order to prevent an arbitrary number of + /// equivocating uncles from being included. + /// + /// The `OnePerAuthorPerHeight` filter is good for many slot-based PoS + /// engines. + type FilterUncle: FilterUncle; + /// An event handler for authored blocks. + type EventHandler: EventHandler; +} + +/// An event handler for the authorship module. There is a dummy implementation +/// for `()`, which does nothing. +pub trait EventHandler { + /// Note that the given account ID is the author of the current block. + fn note_author(author: Author); + + /// Note that the given account ID authored the given uncle, and how many + /// blocks older than the current block it is (age >= 0, so siblings are allowed) + fn note_uncle(author: Author, age: BlockNumber); +} + +macro_rules! impl_event_handler { + () => ( + impl EventHandler for () { + fn note_author(_author: A) { } + fn note_uncle(_author: A, _age: B) { } + } + ); + + ( $($t:ident)* ) => { + impl),*> + EventHandler for ($($t,)*) + { + fn note_author(author: Author) { + $($t::note_author(author.clone());)* + } + fn note_uncle(author: Author, age: BlockNumber) { + $($t::note_uncle(author.clone(), age.clone());)* + } + } + } +} + +for_each_tuple!(impl_event_handler); + +/// Additional filtering on uncles that pass preliminary ancestry checks. +/// +/// This should do work such as checking seals +pub trait FilterUncle { + /// An accumulator of data about uncles included. + /// + /// In practice, this is used to validate uncles against others in the same block. + type Accumulator: Default; + + /// Do additional filtering on a seal-checked uncle block, with the accumulated + /// filter. + fn filter_uncle(header: &Header, acc: Self::Accumulator) + -> Result<(Option, Self::Accumulator), &'static str>; +} + +impl FilterUncle for () { + type Accumulator = (); + fn filter_uncle(_: &H, acc: Self::Accumulator) + -> Result<(Option, Self::Accumulator), &'static str> + { + Ok((None, acc)) + } +} + +/// A filter on uncles which verifies seals and does no additional checks. +/// This is well-suited to consensus modes such as PoW where the cost of +/// equivocating is high. +pub struct SealVerify(rstd::marker::PhantomData); + +impl> FilterUncle + for SealVerify +{ + type Accumulator = (); + + fn filter_uncle(header: &Header, _acc: ()) + -> Result<(Option, ()), &'static str> + { + T::verify_seal(header).map(|author| (author, ())) + } +} + +/// A filter on uncles which verifies seals and ensures that there is only +/// one uncle included per author per height. +/// +/// This does O(n log n) work in the number of uncles included. +pub struct OnePerAuthorPerHeight(rstd::marker::PhantomData<(T, N)>); + +impl FilterUncle + for OnePerAuthorPerHeight +where + Header: HeaderT + PartialEq, + Header::Number: Ord, + Author: Clone + PartialEq + Ord, + T: VerifySeal, +{ + type Accumulator = BTreeSet<(Header::Number, Author)>; + + fn filter_uncle(header: &Header, mut acc: Self::Accumulator) + -> Result<(Option, Self::Accumulator), &'static str> + { + let author = T::verify_seal(header)?; + let number = header.number(); + + if let Some(ref author) = author { + if !acc.insert((number.clone(), author.clone())) { + return Err("more than one uncle per number per author included"); + } + } + + Ok((author, acc)) + } +} + +#[derive(Encode, Decode)] +#[cfg_attr(any(feature = "std", test), derive(PartialEq, Debug))] +enum UncleEntryItem { + InclusionHeight(BlockNumber), + Uncle(Hash, Option), +} + +decl_storage! { + trait Store for Module as Authorship { + /// Uncles + Uncles: Vec>; + /// Author of current block. + Author: Option; + /// Whether uncles were already set in this block. + DidSetUncles: bool; + } +} + +fn prune_old_uncles( + minimum_height: BlockNumber, + uncles: &mut Vec> +) where BlockNumber: SimpleArithmetic { + let prune_entries = uncles.iter().take_while(|item| match item { + UncleEntryItem::Uncle(_, _) => true, + UncleEntryItem::InclusionHeight(height) => height < &minimum_height, + }); + let prune_index = prune_entries.count(); + + let _ = uncles.drain(..prune_index); +} + +decl_module! { + pub struct Module for enum Call where origin: T::Origin { + fn on_initialize(now: T::BlockNumber) { + let uncle_generations = T::UncleGenerations::get(); + let mut uncles = ::Uncles::get(); + + // prune uncles that are older than the allowed number of generations. + if uncle_generations <= now { + let minimum_height = now - uncle_generations; + prune_old_uncles(minimum_height, &mut uncles) + } + + ::DidSetUncles::put(false); + + T::EventHandler::note_author(Self::author()); + } + + fn on_finalize() { + // ensure we never go to trie with these values. + ::Author::kill(); + ::DidSetUncles::kill(); + } + + /// Provide a set of uncles. + fn set_uncles(origin, new_uncles: Vec) -> DispatchResult { + ensure_none(origin)?; + + if ::DidSetUncles::get() { + return Err("Uncles already set in block."); + } + ::DidSetUncles::put(true); + + Self::verify_and_import_uncles(new_uncles) + } + } +} + +impl Module { + /// Fetch the author of the block. + /// + /// This is safe to invoke in `on_initialize` implementations, as well + /// as afterwards. + pub fn author() -> T::AccountId { + // Check the memoized storage value. + if let Some(author) = ::Author::get() { + return author; + } + + let digest = >::digest(); + let pre_runtime_digests = digest.logs.iter().filter_map(|d| d.as_pre_runtime()); + if let Some(author) = T::FindAuthor::find_author(pre_runtime_digests) { + ::Author::put(&author); + author + } else { + Default::default() + } + } + + fn verify_and_import_uncles(new_uncles: Vec) -> DispatchResult { + let now = >::block_number(); + + let (minimum_height, maximum_height) = { + let uncle_generations = T::UncleGenerations::get(); + let min = if now >= uncle_generations { + now - uncle_generations + } else { + Zero::zero() + }; + + (min, now) + }; + + let mut uncles = ::Uncles::get(); + uncles.push(UncleEntryItem::InclusionHeight(now)); + + let mut acc: >::Accumulator = Default::default(); + + for uncle in new_uncles { + let hash = uncle.hash(); + + if uncle.number() < &One::one() { + return Err("uncle is genesis"); + } + + if uncle.number() > &maximum_height { + return Err("uncles too high in chain"); + } + + { + let parent_number = uncle.number().clone() - One::one(); + let parent_hash = >::block_hash(&parent_number); + if &parent_hash != uncle.parent_hash() { + return Err("uncle parent not in chain"); + } + } + + if uncle.number() < &minimum_height { + return Err("uncle not recent enough to be included"); + } + + let duplicate = uncles.iter().find(|entry| match entry { + UncleEntryItem::InclusionHeight(_) => false, + UncleEntryItem::Uncle(h, _) => h == &hash, + }).is_some(); + + let in_chain = >::block_hash(uncle.number()) == hash; + + if duplicate || in_chain { return Err("uncle already included") } + + // check uncle validity. + let (author, temp_acc) = T::FilterUncle::filter_uncle(&uncle, acc)?; + acc = temp_acc; + + T::EventHandler::note_uncle( + author.clone().unwrap_or_default(), + now - uncle.number().clone(), + ); + uncles.push(UncleEntryItem::Uncle(hash, author)); + } + + ::Uncles::put(&uncles); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use runtime_io::with_externalities; + use substrate_primitives::{H256, Blake2Hasher}; + use primitives::traits::{BlakeTwo256, IdentityLookup}; + use primitives::testing::Header; + use primitives::generic::DigestItem; + use srml_support::{parameter_types, impl_outer_origin, ConsensusEngineId}; + + impl_outer_origin!{ + pub enum Origin for Test {} + } + + #[derive(Clone, Eq, PartialEq)] + pub struct Test; + + parameter_types! { + pub const BlockHashCount: u64 = 250; + } + + impl system::Trait for Test { + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = (); + type BlockHashCount = BlockHashCount; + } + + impl Trait for Test { + type FindAuthor = AuthorGiven; + type UncleGenerations = UncleGenerations; + type FilterUncle = SealVerify; + type EventHandler = (); + } + + type System = system::Module; + type Authorship = Module; + + const TEST_ID: ConsensusEngineId = [1, 2, 3, 4]; + + pub struct AuthorGiven; + + impl FindAuthor for AuthorGiven { + fn find_author<'a, I>(digests: I) -> Option + where I: 'a + IntoIterator + { + for (id, data) in digests { + if id == TEST_ID { + return u64::decode(&mut &data[..]); + } + } + + None + } + } + + parameter_types! { + pub const UncleGenerations: u64 = 5; + } + + pub struct VerifyBlock; + + impl VerifySeal for VerifyBlock { + fn verify_seal(header: &Header) -> Result, &'static str> { + let pre_runtime_digests = header.digest.logs.iter().filter_map(|d| d.as_pre_runtime()); + let seals = header.digest.logs.iter().filter_map(|d| d.as_seal()); + + let author = match AuthorGiven::find_author(pre_runtime_digests) { + None => return Err("no author"), + Some(author) => author, + }; + + for (id, seal) in seals { + if id == TEST_ID { + match u64::decode(&mut &seal[..]) { + None => return Err("wrong seal"), + Some(a) => { + if a != author { + return Err("wrong author in seal"); + } + break + } + } + } + } + + Ok(Some(author)) + } + } + + fn seal_header(mut header: Header, author: u64) -> Header { + { + let digest = header.digest_mut(); + digest.logs.push(DigestItem::PreRuntime(TEST_ID, author.encode())); + digest.logs.push(DigestItem::Seal(TEST_ID, author.encode())); + } + + header + } + + + fn create_header(number: u64, parent_hash: H256, state_root: H256) -> Header { + Header::new( + number, + Default::default(), + state_root, + parent_hash, + Default::default(), + ) + } + + fn new_test_ext() -> runtime_io::TestExternalities { + let t = system::GenesisConfig::default().build_storage::().unwrap().0; + t.into() + } + + #[test] + fn prune_old_uncles_works() { + use UncleEntryItem::*; + let mut uncles = vec![ + InclusionHeight(1u32), Uncle((), Some(())), Uncle((), None), Uncle((), None), + InclusionHeight(2u32), Uncle((), None), + InclusionHeight(3u32), Uncle((), None), + ]; + + prune_old_uncles(3, &mut uncles); + + assert_eq!(uncles, vec![InclusionHeight(3), Uncle((), None)]); + } + + #[test] + fn rejects_bad_uncles() { + with_externalities(&mut new_test_ext(), || { + let author_a = 69; + + struct CanonChain { + inner: Vec

, + } + + impl CanonChain { + fn best_hash(&self) -> H256 { + self.inner.last().unwrap().hash() + } + + fn canon_hash(&self, index: usize) -> H256 { + self.inner[index].hash() + } + + fn header(&self, index: usize) -> &Header { + &self.inner[index] + } + + fn push(&mut self, header: Header) { + self.inner.push(header) + } + } + + let mut canon_chain = CanonChain { + inner: vec![seal_header(create_header(0, Default::default(), Default::default()), 999)], + }; + + for number in 1..8 { + System::initialize(&number, &canon_chain.best_hash(), &Default::default(), &Default::default()); + let header = seal_header(System::finalize(), author_a); + canon_chain.push(header); + } + + // initialize so system context is set up correctly. + System::initialize(&8, &canon_chain.best_hash(), &Default::default(), &Default::default()); + + // 2 of the same uncle at once + { + let uncle_a = seal_header( + create_header(3, canon_chain.canon_hash(2), [1; 32].into()), + author_a, + ); + assert_eq!( + Authorship::verify_and_import_uncles(vec![uncle_a.clone(), uncle_a.clone()]), + Err("uncle already included"), + ); + } + + // 2 of the same uncle at different times. + { + let uncle_a = seal_header( + create_header(3, canon_chain.canon_hash(2), [1; 32].into()), + author_a, + ); + + assert!(Authorship::verify_and_import_uncles(vec![uncle_a.clone()]).is_ok()); + + assert_eq!( + Authorship::verify_and_import_uncles(vec![uncle_a.clone()]), + Err("uncle already included"), + ); + } + + // same uncle as ancestor. + { + let uncle_clone = canon_chain.header(5).clone(); + + assert_eq!( + Authorship::verify_and_import_uncles(vec![uncle_clone]), + Err("uncle already included"), + ); + } + + // uncle without valid seal. + { + let unsealed = create_header(3, canon_chain.canon_hash(2), [2; 32].into()); + assert_eq!( + Authorship::verify_and_import_uncles(vec![unsealed]), + Err("no author"), + ); + } + + // old uncles can't get in. + { + assert_eq!(System::block_number(), 8); + + let gen_2 = seal_header( + create_header(2, canon_chain.canon_hash(1), [3; 32].into()), + author_a, + ); + + assert_eq!( + Authorship::verify_and_import_uncles(vec![gen_2]), + Err("uncle not recent enough to be included"), + ); + } + + // siblings are also allowed + { + let other_8 = seal_header( + create_header(8, canon_chain.canon_hash(7), [1; 32].into()), + author_a, + ); + + assert!(Authorship::verify_and_import_uncles(vec![other_8]).is_ok()); + } + }); + } + + #[test] + fn sets_author_lazily() { + with_externalities(&mut new_test_ext(), || { + let author = 42; + let mut header = seal_header( + create_header(1, Default::default(), [1; 32].into()), + author, + ); + + header.digest_mut().pop(); // pop the seal off. + System::initialize(&1, &Default::default(), &Default::default(), header.digest()); + + assert_eq!(Authorship::author(), author); + }); + } + + #[test] + fn one_uncle_per_author_per_number() { + type Filter = OnePerAuthorPerHeight; + + let author_a = 42; + let author_b = 43; + + let mut acc: Option<>::Accumulator> = Some(Default::default()); + let header_a1 = seal_header( + create_header(1, Default::default(), [1; 32].into()), + author_a, + ); + let header_b1 = seal_header( + create_header(1, Default::default(), [1; 32].into()), + author_b, + ); + + let header_a2_1 = seal_header( + create_header(2, Default::default(), [1; 32].into()), + author_a, + ); + let header_a2_2 = seal_header( + create_header(2, Default::default(), [2; 32].into()), + author_a, + ); + + let mut check_filter = move |uncle| { + match Filter::filter_uncle(uncle, acc.take().unwrap()) { + Ok((author, a)) => { + acc = Some(a); + Ok(author) + } + Err(e) => Err(e), + } + }; + + // same height, different author is OK. + assert_eq!(check_filter(&header_a1), Ok(Some(author_a))); + assert_eq!(check_filter(&header_b1), Ok(Some(author_b))); + + // same author, different height. + assert_eq!(check_filter(&header_a2_1), Ok(Some(author_a))); + + // same author, same height (author a, height 2) + assert!(check_filter(&header_a2_2).is_err()); + } +} diff --git a/srml/babe/Cargo.toml b/srml/babe/Cargo.toml index 4b82a6c6bc7b8e9c867eca4101b0c4510f744af4..afa46370cd0c740e0d6eb9c7f2f87a34710e7b68 100644 --- a/srml/babe/Cargo.toml +++ b/srml/babe/Cargo.toml @@ -6,8 +6,8 @@ edition = "2018" [dependencies] hex-literal = "0.1.4" -parity-codec = { version = "3.5.1", default-features = false, features = ["derive"] } -serde = { version = "1.0.90", optional = true } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } +serde = { version = "1.0.93", optional = true } inherents = { package = "substrate-inherents", path = "../../core/inherents", default-features = false } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } @@ -16,12 +16,12 @@ system = { package = "srml-system", path = "../system", default-features = false timestamp = { package = "srml-timestamp", path = "../timestamp", default-features = false } session = { package = "srml-session", path = "../session", default-features = false } babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../../core/consensus/babe/primitives", default-features = false } +runtime_io = { package = "sr-io", path = "../../core/sr-io", default-features = false } [dev-dependencies] lazy_static = "1.3.0" parking_lot = "0.8.0" substrate-primitives = { path = "../../core/primitives" } -runtime_io = { package = "sr-io", path = "../../core/sr-io" } [features] default = ["std"] @@ -36,4 +36,5 @@ std = [ "inherents/std", "babe-primitives/std", "session/std", + "runtime_io/std", ] diff --git a/srml/babe/src/lib.rs b/srml/babe/src/lib.rs index 0cfc0fb8d059dee5bb077715f425cab1f2293cec..f1c8894a4d8f6338e1bcacfeb7654a2770379982 100644 --- a/srml/babe/src/lib.rs +++ b/srml/babe/src/lib.rs @@ -17,22 +17,22 @@ //! Consensus extension module for BABE consensus. #![cfg_attr(not(feature = "std"), no_std)] -#![forbid(unsafe_code)] +#![forbid(unused_must_use, unsafe_code, unused_variables, dead_code)] pub use timestamp; use rstd::{result, prelude::*}; -use srml_support::{decl_storage, decl_module, StorageValue}; +use srml_support::{decl_storage, decl_module, StorageValue, traits::FindAuthor, traits::Get}; use timestamp::{OnTimestampSet, Trait}; -use primitives::{generic::DigestItem, traits::{SaturatedConversion, Saturating}}; +use primitives::{generic::DigestItem, traits::{SaturatedConversion, Saturating, RandomnessBeacon}}; +use primitives::ConsensusEngineId; #[cfg(feature = "std")] use timestamp::TimestampInherentData; use parity_codec::{Encode, Decode}; use inherents::{RuntimeString, InherentIdentifier, InherentData, ProvideInherent, MakeFatalError}; #[cfg(feature = "std")] use inherents::{InherentDataProviders, ProvideInherentData}; -use babe_primitives::BABE_ENGINE_ID; - -pub use babe_primitives::AuthorityId; +use babe_primitives::{BABE_ENGINE_ID, ConsensusLog}; +pub use babe_primitives::{AuthorityId, VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH, PUBLIC_KEY_LENGTH}; /// The BABE inherent identifier. pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"babeslot"; @@ -67,6 +67,7 @@ pub struct InherentDataProvider { #[cfg(feature = "std")] impl InherentDataProvider { + /// Constructs `Self` pub fn new(slot_duration: u64) -> Self { Self { slot_duration @@ -106,6 +107,9 @@ impl ProvideInherentData for InherentDataProvider { } } +/// The length of the BABE randomness +pub const RANDOMNESS_LENGTH: usize = 32; + decl_storage! { trait Store for Module as Babe { /// The last timestamp. @@ -113,11 +117,75 @@ decl_storage! { /// The current authorities set. Authorities get(authorities): Vec; + + /// The epoch randomness. + /// + /// # Security + /// + /// This MUST NOT be used for gambling, as it can be influenced by a + /// malicious validator in the short term. It MAY be used in many + /// cryptographic protocols, however, so long as one remembers that this + /// (like everything else on-chain) it is public. For example, it can be + /// used where a number is needed that cannot have been chosen by an + /// adversary, for purposes such as public-coin zero-knowledge proofs. + EpochRandomness get(epoch_randomness): [u8; VRF_OUTPUT_LENGTH]; + + /// The randomness under construction + UnderConstruction: [u8; VRF_OUTPUT_LENGTH]; + + /// The randomness for the next epoch + NextEpochRandomness: [u8; VRF_OUTPUT_LENGTH]; + + /// The current epoch + EpochIndex get(epoch_index): u64; } } decl_module! { - pub struct Module for enum Call where origin: T::Origin { } + /// The BABE SRML module + pub struct Module for enum Call where origin: T::Origin { + /// Initialization + fn on_initialize() { + for i in Self::get_inherent_digests() + .logs + .iter() + .filter_map(|s| s.as_pre_runtime()) + .filter_map(|(id, mut data)| if id == BABE_ENGINE_ID { + <[u8; VRF_OUTPUT_LENGTH]>::decode(&mut data) + } else { + None + }) { + Self::deposit_vrf_output(&i); + } + } + } +} + +impl RandomnessBeacon for Module { + fn random() -> [u8; VRF_OUTPUT_LENGTH] { + Self::epoch_randomness() + } +} + +/// A BABE public key +pub type BabeKey = [u8; PUBLIC_KEY_LENGTH]; + +impl FindAuthor for Module { + fn find_author<'a, I>(digests: I) -> Option where + I: 'a + IntoIterator + { + for (id, mut data) in digests.into_iter() { + if id == BABE_ENGINE_ID { + let (_, _, i): ( + [u8; VRF_OUTPUT_LENGTH], + [u8; VRF_PROOF_LENGTH], + u64, + ) = Decode::decode(&mut data)?; + return Some(i) + } + } + return None + } } impl Module { @@ -125,27 +193,34 @@ impl Module { pub fn slot_duration() -> T::Moment { // we double the minimum block-period so each author can always propose within // the majority of their slot. - >::minimum_period().saturating_mul(2.into()) + ::MinimumPeriod::get().saturating_mul(2.into()) } -} - -impl OnTimestampSet for Module { - fn on_timestamp_set(_moment: T::Moment) { } -} -impl Module { fn change_authorities(new: Vec) { - >::put(&new); + Authorities::put(&new); let log: DigestItem = DigestItem::Consensus(BABE_ENGINE_ID, new.encode()); >::deposit_log(log.into()); } + + fn deposit_vrf_output(vrf_output: &[u8; VRF_OUTPUT_LENGTH]) { + UnderConstruction::mutate(|z| z.iter_mut().zip(vrf_output).for_each(|(x, y)| *x^=y)) + } + + fn get_inherent_digests() -> system::DigestOf { + >::digest() + } +} + +impl OnTimestampSet for Module { + fn on_timestamp_set(_moment: T::Moment) { } } impl session::OneSessionHandler for Module { type Key = AuthorityId; + fn on_new_session<'a, I: 'a>(changed: bool, validators: I) - where I: Iterator + where I: Iterator { // instant changes if changed { @@ -155,9 +230,28 @@ impl session::OneSessionHandler for Module { Self::change_authorities(next_authorities); } } + + let rho = UnderConstruction::get(); + UnderConstruction::put([0; 32]); + let last_epoch_randomness = EpochRandomness::get(); + let epoch_index = EpochIndex::get() + .checked_add(1) + .expect("epoch indices will never reach 2^64 before the death of the universe; qed"); + EpochIndex::put(epoch_index); + EpochRandomness::put(NextEpochRandomness::get()); + let mut s = [0; 72]; + s[..32].copy_from_slice(&last_epoch_randomness); + s[32..40].copy_from_slice(&epoch_index.to_le_bytes()); + s[40..].copy_from_slice(&rho); + NextEpochRandomness::put(runtime_io::blake2_256(&s)) } - fn on_disabled(_i: usize) { - // ignore? + + fn on_disabled(i: usize) { + let log: DigestItem = DigestItem::Consensus( + BABE_ENGINE_ID, + ConsensusLog::OnDisabled(i as u64).encode(), + ); + >::deposit_log(log.into()); } } diff --git a/srml/balances/Cargo.toml b/srml/balances/Cargo.toml index 6c000294ba12e057c864d2f0f3add72b7a93c565..a61b95b2ada4a4e4f593c8befbfc2840fc09ebfe 100644 --- a/srml/balances/Cargo.toml +++ b/srml/balances/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] serde = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false} -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } substrate-keyring = { path = "../../core/keyring", optional = true } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index 72ec997206550bc0c6b48933c188fa7d246778d5..30fb2a48e935cfea792c2ab6904aba1fe16f5d1f 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -158,18 +158,24 @@ use srml_support::traits::{ WithdrawReason, WithdrawReasons, LockIdentifier, LockableCurrency, ExistenceRequirement, Imbalance, SignedImbalance, ReservableCurrency }; -use srml_support::dispatch::Result; +use srml_support::{dispatch::Result, traits::Get}; use primitives::traits::{ Zero, SimpleArithmetic, StaticLookup, Member, CheckedAdd, CheckedSub, - MaybeSerializeDebug, Saturating + MaybeSerializeDebug, Saturating, Bounded }; -use system::{IsDeadAccount, OnNewAccount, ensure_signed}; +use system::{IsDeadAccount, OnNewAccount, ensure_signed, ensure_root}; mod mock; mod tests; pub use self::imbalances::{PositiveImbalance, NegativeImbalance}; +pub const DEFAULT_EXISTENTIAL_DEPOSIT: u32 = 0; +pub const DEFAULT_TRANSFER_FEE: u32 = 0; +pub const DEFAULT_CREATION_FEE: u32 = 0; +pub const DEFAULT_TRANSACTION_BASE_FEE: u32 = 0; +pub const DEFAULT_TRANSACTION_BYTE_FEE: u32 = 0; + pub trait Subtrait: system::Trait { /// The balance of an account. type Balance: Parameter + Member + SimpleArithmetic + Codec + Default + Copy + @@ -183,6 +189,21 @@ pub trait Subtrait: system::Trait { /// Handler for when a new account is created. type OnNewAccount: OnNewAccount; + + /// The minimum amount required to keep an account open. + type ExistentialDeposit: Get; + + /// The fee required to make a transfer. + type TransferFee: Get; + + /// The fee required to create an account. + type CreationFee: Get; + + /// The fee to be paid for making a transaction; the base. + type TransactionBaseFee: Get; + + /// The fee to be paid for making a transaction; the per-byte portion. + type TransactionByteFee: Get; } pub trait Trait: system::Trait { @@ -211,12 +232,32 @@ pub trait Trait: system::Trait { /// The overarching event type. type Event: From> + Into<::Event>; + + /// The minimum amount required to keep an account open. + type ExistentialDeposit: Get; + + /// The fee required to make a transfer. + type TransferFee: Get; + + /// The fee required to create an account. + type CreationFee: Get; + + /// The fee to be paid for making a transaction; the base. + type TransactionBaseFee: Get; + + /// The fee to be paid for making a transaction; the per-byte portion. + type TransactionByteFee: Get; } impl, I: Instance> Subtrait for T { type Balance = T::Balance; type OnFreeBalanceZero = T::OnFreeBalanceZero; type OnNewAccount = T::OnNewAccount; + type ExistentialDeposit = T::ExistentialDeposit; + type TransferFee = T::TransferFee; + type CreationFee = T::CreationFee; + type TransactionBaseFee = T::TransactionBaseFee; + type TransactionByteFee = T::TransactionByteFee; } decl_event!( @@ -236,20 +277,26 @@ decl_event!( /// Struct to encode the vesting schedule of an individual account. #[derive(Encode, Decode, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Debug))] -pub struct VestingSchedule { +pub struct VestingSchedule { /// Locked amount at genesis. - pub offset: Balance, - /// Amount that gets unlocked every block from genesis. + pub locked: Balance, + /// Amount that gets unlocked every block after `starting_block`. pub per_block: Balance, + /// Starting block for unlocking(vesting). + pub starting_block: BlockNumber, } -impl VestingSchedule { +impl VestingSchedule { /// Amount locked at block `n`. - pub fn locked_at(&self, n: BlockNumber) -> Balance + pub fn locked_at(&self, n: BlockNumber) -> Balance where Balance: From { - if let Some(x) = Balance::from(n).checked_mul(&self.per_block) { - self.offset.max(x) - x + // Number of blocks that count toward vesting + // Saturating to 0 when n < starting_block + let vested_block_count = n.saturating_sub(self.starting_block); + // Return amount that is still locked in vesting + if let Some(x) = Balance::from(vested_block_count).checked_mul(&self.per_block) { + self.locked.max(x) - x } else { Zero::zero() } @@ -271,36 +318,33 @@ decl_storage! { pub TotalIssuance get(total_issuance) build(|config: &GenesisConfig| { config.balances.iter().fold(Zero::zero(), |acc: T::Balance, &(_, n)| acc + n) }): T::Balance; - /// The minimum amount required to keep an account open. - pub ExistentialDeposit get(existential_deposit) config(): T::Balance; - /// The fee required to make a transfer. - pub TransferFee get(transfer_fee) config(): T::Balance; - /// The fee required to create an account. - pub CreationFee get(creation_fee) config(): T::Balance; - /// The fee to be paid for making a transaction; the base. - pub TransactionBaseFee get(transaction_base_fee) config(): T::Balance; - /// The fee to be paid for making a transaction; the per-byte portion. - pub TransactionByteFee get(transaction_byte_fee) config(): T::Balance; /// Information regarding the vesting of a given account. pub Vesting get(vesting) build(|config: &GenesisConfig| { - config.vesting.iter().filter_map(|&(ref who, begin, length)| { - let begin = >::from(begin); + // Generate initial vesting configuration + // * who - Account which we are generating vesting configuration for + // * begin - Block when the account will start to vest + // * length - Number of blocks from `begin` until fully vested + // * liquid - Number of units which can be spent before vesting begins + config.vesting.iter().filter_map(|&(ref who, begin, length, liquid)| { let length = >::from(length); config.balances.iter() .find(|&&(ref w, _)| w == who) .map(|&(_, balance)| { - // <= begin it should be >= balance - // >= begin+length it should be <= 0 - - let per_block = balance / length.max(primitives::traits::One::one()); - let offset = begin * per_block + balance; - - (who.clone(), VestingSchedule { offset, per_block }) + // Total genesis `balance` minus `liquid` equals funds locked for vesting + let locked = balance.saturating_sub(liquid); + // Number of units unlocked per block after `begin` + let per_block = locked / length.max(primitives::traits::One::one()); + + (who.clone(), VestingSchedule { + locked: locked, + per_block: per_block, + starting_block: begin + }) }) }).collect::>() - }): map T::AccountId => Option>; + }): map T::AccountId => Option>; /// The 'free' balance of a given account. /// @@ -313,7 +357,9 @@ decl_storage! { /// /// `system::AccountNonce` is also deleted if `ReservedBalance` is also zero (it also gets /// collapsed to zero if it ever becomes less than `ExistentialDeposit`. - pub FreeBalance get(free_balance) build(|config: &GenesisConfig| config.balances.clone()): map T::AccountId => T::Balance; + pub FreeBalance get(free_balance) + build(|config: &GenesisConfig| config.balances.clone()): + map T::AccountId => T::Balance; /// The amount of the balance of a given account that is externally reserved; this can still get /// slashed, but gets slashed last of all. @@ -333,13 +379,28 @@ decl_storage! { } add_extra_genesis { config(balances): Vec<(T::AccountId, T::Balance)>; - config(vesting): Vec<(T::AccountId, T::BlockNumber, T::BlockNumber)>; // begin, length + config(vesting): Vec<(T::AccountId, T::BlockNumber, T::BlockNumber, T::Balance)>; + // ^^ begin, length, amount liquid at genesis } - extra_genesis_skip_phantom_data_field; } decl_module! { pub struct Module, I: Instance = DefaultInstance> for enum Call where origin: T::Origin { + /// The minimum amount required to keep an account open. + const ExistentialDeposit: T::Balance = T::ExistentialDeposit::get(); + + /// The fee required to make a transfer. + const TransferFee: T::Balance = T::TransferFee::get(); + + /// The fee required to create an account. + const CreationFee: T::Balance = T::CreationFee::get(); + + /// The fee to be paid for making a transaction; the base. + const TransactionBaseFee: T::Balance = T::TransactionBaseFee::get(); + + /// The fee to be paid for making a transaction; the per-byte portion. + const TransactionByteFee: T::Balance = T::TransactionByteFee::get(); + fn deposit_event() = default; /// Transfer some liquid free balance to another account. @@ -389,10 +450,12 @@ decl_module! { /// - Contains a limited number of reads and writes. /// # fn set_balance( + origin, who: ::Source, #[compact] new_free: T::Balance, #[compact] new_reserved: T::Balance ) { + ensure_root(origin)?; let who = T::Lookup::lookup(who)?; let current_free = >::get(&who); @@ -422,7 +485,7 @@ impl, I: Instance> Module { pub fn vesting_balance(who: &T::AccountId) -> T::Balance { if let Some(v) = Self::vesting(who) { Self::free_balance(who) - .min(v.locked_at::(>::block_number())) + .min(v.locked_at(>::block_number())) } else { Zero::zero() } @@ -439,7 +502,7 @@ impl, I: Instance> Module { /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that /// the caller will do this. fn set_reserved_balance(who: &T::AccountId, balance: T::Balance) -> UpdateBalanceOutcome { - if balance < Self::existential_deposit() { + if balance < T::ExistentialDeposit::get() { >::insert(who, balance); Self::on_reserved_too_low(who); UpdateBalanceOutcome::AccountKilled @@ -460,8 +523,8 @@ impl, I: Instance> Module { fn set_free_balance(who: &T::AccountId, balance: T::Balance) -> UpdateBalanceOutcome { // Commented out for now - but consider it instructive. // assert!(!Self::total_balance(who).is_zero()); - // assert!(Self::free_balance(who) > Self::existential_deposit()); - if balance < Self::existential_deposit() { + // assert!(Self::free_balance(who) > T::ExistentialDeposit::get()); + if balance < T::ExistentialDeposit::get() { >::insert(who, balance); Self::on_free_too_low(who); UpdateBalanceOutcome::AccountKilled @@ -697,6 +760,7 @@ impl, I: Instance> system::Trait for ElevatedTrait { type Lookup = T::Lookup; type Header = T::Header; type Event = (); + type BlockHashCount = T::BlockHashCount; } impl, I: Instance> Trait for ElevatedTrait { type Balance = T::Balance; @@ -706,6 +770,11 @@ impl, I: Instance> Trait for ElevatedTrait { type TransactionPayment = (); type TransferPayment = (); type DustRemoval = (); + type ExistentialDeposit = T::ExistentialDeposit; + type TransferFee = T::TransferFee; + type CreationFee = T::CreationFee; + type TransactionBaseFee = T::TransactionBaseFee; + type TransactionByteFee = T::TransactionByteFee; } impl, I: Instance> Currency for Module @@ -729,13 +798,33 @@ where } fn minimum_balance() -> Self::Balance { - Self::existential_deposit() + T::ExistentialDeposit::get() } fn free_balance(who: &T::AccountId) -> Self::Balance { >::get(who) } + fn burn(mut amount: Self::Balance) -> Self::PositiveImbalance { + >::mutate(|issued| + issued.checked_sub(&amount).unwrap_or_else(|| { + amount = *issued; + Zero::zero() + }) + ); + PositiveImbalance::new(amount) + } + + fn issue(mut amount: Self::Balance) -> Self::NegativeImbalance { + >::mutate(|issued| + *issued = issued.checked_add(&amount).unwrap_or_else(|| { + amount = Self::Balance::max_value() - *issued; + Self::Balance::max_value() + }) + ); + NegativeImbalance::new(amount) + } + // # // Despite iterating over a list of locks, they are limited by the number of // lock IDs, which means the number of runtime modules that intend to use and create locks. @@ -774,7 +863,7 @@ where let from_balance = Self::free_balance(transactor); let to_balance = Self::free_balance(dest); let would_create = to_balance.is_zero(); - let fee = if would_create { Self::creation_fee() } else { Self::transfer_fee() }; + let fee = if would_create { T::CreationFee::get() } else { T::TransferFee::get() }; let liability = match value.checked_add(&fee) { Some(l) => l, None => return Err("got overflow after adding a fee to value"), @@ -784,7 +873,7 @@ where None => return Err("balance too low to send value"), Some(b) => b, }; - if would_create && value < Self::existential_deposit() { + if would_create && value < T::ExistentialDeposit::get() { return Err("value too low to create account"); } Self::ensure_can_withdraw(transactor, value, WithdrawReason::Transfer, new_from_balance)?; @@ -816,7 +905,7 @@ where liveness: ExistenceRequirement, ) -> result::Result { if let Some(new_balance) = Self::free_balance(who).checked_sub(&value) { - if liveness == ExistenceRequirement::KeepAlive && new_balance < Self::existential_deposit() { + if liveness == ExistenceRequirement::KeepAlive && new_balance < T::ExistentialDeposit::get() { return Err("payment would kill account") } Self::ensure_can_withdraw(who, value, reason, new_balance)?; @@ -873,12 +962,12 @@ where } } - fn make_free_balance_be(who: &T::AccountId, balance: T::Balance) -> ( + fn make_free_balance_be(who: &T::AccountId, balance: Self::Balance) -> ( SignedImbalance, UpdateBalanceOutcome ) { let original = Self::free_balance(who); - if balance < Self::existential_deposit() && original.is_zero() { + if balance < T::ExistentialDeposit::get() && original.is_zero() { // If we're attempting to set an existing account to less than ED, then // bypass the entire operation. It's a no-op if you follow it through, but // since this is an instance where we might account for a negative imbalance @@ -904,7 +993,7 @@ where // Free balance can never be less than ED. If that happens, it gets reduced to zero // and the account information relevant to this subsystem is deleted (i.e. the // account is reaped). - let outcome = if balance < >::existential_deposit() { + let outcome = if balance < T::ExistentialDeposit::get() { Self::set_free_balance(who, balance); UpdateBalanceOutcome::AccountKilled } else { @@ -1058,7 +1147,7 @@ where impl, I: Instance> MakePayment for Module { fn make_payment(transactor: &T::AccountId, encoded_len: usize) -> Result { let encoded_len = T::Balance::from(encoded_len as u32); - let transaction_fee = Self::transaction_base_fee() + Self::transaction_byte_fee() * encoded_len; + let transaction_fee = T::TransactionBaseFee::get() + T::TransactionByteFee::get() * encoded_len; let imbalance = Self::withdraw( transactor, transaction_fee, diff --git a/srml/balances/src/mock.rs b/srml/balances/src/mock.rs index ac5208ab90c2a3c1e7367f706eecfa708118508a..38dae9f25f6f52c9f0c371b88f353ce5b04882fd 100644 --- a/srml/balances/src/mock.rs +++ b/srml/balances/src/mock.rs @@ -18,20 +18,56 @@ #![cfg(test)] -use primitives::BuildStorage; use primitives::{traits::{IdentityLookup}, testing::Header}; use substrate_primitives::{H256, Blake2Hasher}; use runtime_io; -use srml_support::impl_outer_origin; +use srml_support::{impl_outer_origin, parameter_types, traits::Get}; +use std::cell::RefCell; use crate::{GenesisConfig, Module, Trait}; impl_outer_origin!{ pub enum Origin for Runtime {} } +thread_local! { + static EXISTENTIAL_DEPOSIT: RefCell = RefCell::new(0); + static TRANSFER_FEE: RefCell = RefCell::new(0); + static CREATION_FEE: RefCell = RefCell::new(0); + static TRANSACTION_BASE_FEE: RefCell = RefCell::new(0); + static TRANSACTION_BYTE_FEE: RefCell = RefCell::new(0); +} + +pub struct ExistentialDeposit; +impl Get for ExistentialDeposit { + fn get() -> u64 { EXISTENTIAL_DEPOSIT.with(|v| *v.borrow()) } +} + +pub struct TransferFee; +impl Get for TransferFee { + fn get() -> u64 { TRANSFER_FEE.with(|v| *v.borrow()) } +} + +pub struct CreationFee; +impl Get for CreationFee { + fn get() -> u64 { CREATION_FEE.with(|v| *v.borrow()) } +} + +pub struct TransactionBaseFee; +impl Get for TransactionBaseFee { + fn get() -> u64 { TRANSACTION_BASE_FEE.with(|v| *v.borrow()) } +} + +pub struct TransactionByteFee; +impl Get for TransactionByteFee { + fn get() -> u64 { TRANSACTION_BYTE_FEE.with(|v| *v.borrow()) } +} + // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, PartialEq, Eq, Debug)] pub struct Runtime; +parameter_types! { + pub const BlockHashCount: u64 = 250; +} impl system::Trait for Runtime { type Origin = Origin; type Index = u64; @@ -42,6 +78,7 @@ impl system::Trait for Runtime { type Lookup = IdentityLookup; type Header = Header; type Event = (); + type BlockHashCount = BlockHashCount; } impl Trait for Runtime { type Balance = u64; @@ -51,6 +88,11 @@ impl Trait for Runtime { type TransactionPayment = (); type DustRemoval = (); type TransferPayment = (); + type ExistentialDeposit = ExistentialDeposit; + type TransferFee = TransferFee; + type CreationFee = CreationFee; + type TransactionBaseFee = TransactionBaseFee; + type TransactionByteFee = TransactionByteFee; } pub struct ExtBuilder { @@ -105,21 +147,34 @@ impl ExtBuilder { self.vesting = vesting; self } + pub fn set_associated_consts(&self) { + EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit); + TRANSFER_FEE.with(|v| *v.borrow_mut() = self.transfer_fee); + CREATION_FEE.with(|v| *v.borrow_mut() = self.creation_fee); + TRANSACTION_BASE_FEE.with(|v| *v.borrow_mut() = self.transaction_base_fee); + TRANSACTION_BYTE_FEE.with(|v| *v.borrow_mut() = self.transaction_byte_fee); + } pub fn build(self) -> runtime_io::TestExternalities { - let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; + self.set_associated_consts(); + let mut t = system::GenesisConfig::default().build_storage::().unwrap().0; t.extend(GenesisConfig:: { - transaction_base_fee: self.transaction_base_fee, - transaction_byte_fee: self.transaction_byte_fee, balances: if self.monied { - vec![(1, 10 * self.existential_deposit), (2, 20 * self.existential_deposit), (3, 30 * self.existential_deposit), (4, 40 * self.existential_deposit)] + vec![ + (1, 10 * self.existential_deposit), + (2, 20 * self.existential_deposit), + (3, 30 * self.existential_deposit), + (4, 40 * self.existential_deposit), + (12, 10 * self.existential_deposit) + ] } else { vec![] }, - existential_deposit: self.existential_deposit, - transfer_fee: self.transfer_fee, - creation_fee: self.creation_fee, vesting: if self.vesting && self.monied { - vec![(1, 0, 10), (2, 10, 20)] + vec![ + (1, 0, 10, 5 * self.existential_deposit), + (2, 10, 20, 0), + (12, 10, 20, 5 * self.existential_deposit) + ] } else { vec![] }, diff --git a/srml/balances/src/tests.rs b/srml/balances/src/tests.rs index 0a5a4b5bb70a69478ae19beddb3940e211b58495..2d53ae510cc9a12c3ca7a0e9874074917b1a5d09 100644 --- a/srml/balances/src/tests.rs +++ b/srml/balances/src/tests.rs @@ -111,31 +111,37 @@ fn lock_value_extension_should_work() { #[test] fn lock_reasons_should_work() { - with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).transaction_fees(0, 1).build(), || { - Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::Transfer.into()); - assert_noop!( - >::transfer(&1, &2, 1), - "account liquidity restrictions prevent withdrawal" - ); - assert_ok!(>::reserve(&1, 1)); - assert_ok!(>::make_payment(&1, 1)); + with_externalities( + &mut ExtBuilder::default() + .existential_deposit(1) + .monied(true).transaction_fees(0, 1) + .build(), + || { + Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::Transfer.into()); + assert_noop!( + >::transfer(&1, &2, 1), + "account liquidity restrictions prevent withdrawal" + ); + assert_ok!(>::reserve(&1, 1)); + assert_ok!(>::make_payment(&1, 1)); - Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::Reserve.into()); - assert_ok!(>::transfer(&1, &2, 1)); - assert_noop!( - >::reserve(&1, 1), - "account liquidity restrictions prevent withdrawal" - ); - assert_ok!(>::make_payment(&1, 1)); + Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::Reserve.into()); + assert_ok!(>::transfer(&1, &2, 1)); + assert_noop!( + >::reserve(&1, 1), + "account liquidity restrictions prevent withdrawal" + ); + assert_ok!(>::make_payment(&1, 1)); - Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::TransactionPayment.into()); - assert_ok!(>::transfer(&1, &2, 1)); - assert_ok!(>::reserve(&1, 1)); - assert_noop!( - >::make_payment(&1, 1), - "account liquidity restrictions prevent withdrawal" - ); - }); + Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::TransactionPayment.into()); + assert_ok!(>::transfer(&1, &2, 1)); + assert_ok!(>::reserve(&1, 1)); + assert_noop!( + >::make_payment(&1, 1), + "account liquidity restrictions prevent withdrawal" + ); + } + ); } #[test] @@ -204,8 +210,9 @@ fn default_indexing_on_new_accounts_should_not_work2() { .monied(true) .build(), || { + assert_eq!(Balances::is_dead_account(&5), true); // account 5 should not exist - // account 1 has 256 * 10 = 2560, account 5 is not exist, ext_deposit is 10, value is 9, not satisfies for ext_deposit + // ext_deposit is 10, value is 9, not satisfies for ext_deposit assert_noop!( Balances::transfer(Some(1).into(), 5, 9), "value too low to create account" @@ -235,16 +242,19 @@ fn reserved_balance_should_prevent_reclaim_count() { assert_eq!(Balances::is_dead_account(&2), false); assert_eq!(System::account_nonce(&2), 1); - assert_ok!(Balances::transfer(Some(4).into(), 5, 256 * 1 + 0x69)); // account 4 tries to take index 1 for account 5. + // account 4 tries to take index 1 for account 5. + assert_ok!(Balances::transfer(Some(4).into(), 5, 256 * 1 + 0x69)); assert_eq!(Balances::total_balance(&5), 256 * 1 + 0x69); assert_eq!(Balances::is_dead_account(&5), false); assert!(Balances::slash(&2, 256 * 18 + 2).1.is_zero()); // account 2 gets slashed - assert_eq!(Balances::total_balance(&2), 0); // "reserve" account reduced to 255 (below ED) so account deleted + // "reserve" account reduced to 255 (below ED) so account deleted + assert_eq!(Balances::total_balance(&2), 0); assert_eq!(System::account_nonce(&2), 0); // nonce zero assert_eq!(Balances::is_dead_account(&2), true); - assert_ok!(Balances::transfer(Some(4).into(), 6, 256 * 1 + 0x69)); // account 4 tries to take index 1 again for account 6. + // account 4 tries to take index 1 again for account 6. + assert_ok!(Balances::transfer(Some(4).into(), 6, 256 * 1 + 0x69)); assert_eq!(Balances::total_balance(&6), 256 * 1 + 0x69); assert_eq!(Balances::is_dead_account(&6), false); }, @@ -258,7 +268,7 @@ fn reward_should_work() { assert_eq!(Balances::total_balance(&1), 10); assert_ok!(Balances::deposit_into_existing(&1, 10).map(drop)); assert_eq!(Balances::total_balance(&1), 20); - assert_eq!(>::get(), 110); + assert_eq!(>::get(), 120); }); } @@ -294,7 +304,8 @@ fn dust_account_removal_should_work2() { System::inc_account_nonce(&2); assert_eq!(System::account_nonce(&2), 1); assert_eq!(Balances::total_balance(&2), 2000); - assert_ok!(Balances::transfer(Some(2).into(), 5, 1851)); // index 1 (account 2) becomes zombie for 256*10 + 50(fee) < 256 * 10 (ext_deposit) + // index 1 (account 2) becomes zombie for 256*10 + 50(fee) < 256 * 10 (ext_deposit) + assert_ok!(Balances::transfer(Some(2).into(), 5, 1851)); assert_eq!(Balances::total_balance(&2), 0); assert_eq!(Balances::total_balance(&5), 1851); assert_eq!(System::account_nonce(&2), 0); @@ -571,32 +582,52 @@ fn check_vesting_status() { assert_eq!(System::block_number(), 1); let user1_free_balance = Balances::free_balance(&1); let user2_free_balance = Balances::free_balance(&2); + let user12_free_balance = Balances::free_balance(&12); assert_eq!(user1_free_balance, 256 * 10); // Account 1 has free balance assert_eq!(user2_free_balance, 256 * 20); // Account 2 has free balance + assert_eq!(user12_free_balance, 256 * 10); // Account 12 has free balance let user1_vesting_schedule = VestingSchedule { - offset: 256 * 10, - per_block: 256, + locked: 256 * 5, + per_block: 128, // Vesting over 10 blocks + starting_block: 0, }; let user2_vesting_schedule = VestingSchedule { - offset: 256 * 30, - per_block: 256, + locked: 256 * 20, + per_block: 256, // Vesting over 20 blocks + starting_block: 10, + }; + let user12_vesting_schedule = VestingSchedule { + locked: 256 * 5, + per_block: 64, // Vesting over 20 blocks + starting_block: 10, }; assert_eq!(Balances::vesting(&1), Some(user1_vesting_schedule)); // Account 1 has a vesting schedule assert_eq!(Balances::vesting(&2), Some(user2_vesting_schedule)); // Account 2 has a vesting schedule + assert_eq!(Balances::vesting(&12), Some(user12_vesting_schedule)); // Account 12 has a vesting schedule - assert_eq!(Balances::vesting_balance(&1), user1_free_balance - 256); // Account 1 has only 256 units vested at block 1 + // Account 1 has only 128 units vested from their illiquid 256 * 5 units at block 1 + assert_eq!(Balances::vesting_balance(&1), 128 * 9); + // Account 2 has their full balance locked + assert_eq!(Balances::vesting_balance(&2), user2_free_balance); + // Account 12 has only their illiquid funds locked + assert_eq!(Balances::vesting_balance(&12), user12_free_balance - 256 * 5); System::set_block_number(10); assert_eq!(System::block_number(), 10); - assert_eq!(Balances::vesting_balance(&1), 0); // Account 1 has fully vested by block 10 - assert_eq!(Balances::vesting_balance(&2), user2_free_balance); // Account 2 has started vesting by block 10 + // Account 1 has fully vested by block 10 + assert_eq!(Balances::vesting_balance(&1), 0); + // Account 2 has started vesting by block 10 + assert_eq!(Balances::vesting_balance(&2), user2_free_balance); + // Account 12 has started vesting by block 10 + assert_eq!(Balances::vesting_balance(&12), user12_free_balance - 256 * 5); System::set_block_number(30); assert_eq!(System::block_number(), 30); assert_eq!(Balances::vesting_balance(&1), 0); // Account 1 is still fully vested, and not negative assert_eq!(Balances::vesting_balance(&2), 0); // Account 2 has fully vested by block 30 + assert_eq!(Balances::vesting_balance(&12), 0); // Account 2 has fully vested by block 30 } ); @@ -614,9 +645,10 @@ fn unvested_balance_should_not_transfer() { assert_eq!(System::block_number(), 1); let user1_free_balance = Balances::free_balance(&1); assert_eq!(user1_free_balance, 100); // Account 1 has free balance - assert_eq!(Balances::vesting_balance(&1), 90); // Account 1 has only 10 units vested at block 1 + // Account 1 has only 5 units vested at block 1 (plus 50 unvested) + assert_eq!(Balances::vesting_balance(&1), 45); assert_noop!( - Balances::transfer(Some(1).into(), 2, 11), + Balances::transfer(Some(1).into(), 2, 56), "vesting balance too high to send value" ); // Account 1 cannot send more than vested amount } @@ -635,8 +667,9 @@ fn vested_balance_should_transfer() { assert_eq!(System::block_number(), 1); let user1_free_balance = Balances::free_balance(&1); assert_eq!(user1_free_balance, 100); // Account 1 has free balance - assert_eq!(Balances::vesting_balance(&1), 90); // Account 1 has only 10 units vested at block 1 - assert_ok!(Balances::transfer(Some(1).into(), 2, 10)); + // Account 1 has only 5 units vested at block 1 (plus 50 unvested) + assert_eq!(Balances::vesting_balance(&1), 45); + assert_ok!(Balances::transfer(Some(1).into(), 2, 55)); } ); } @@ -652,11 +685,51 @@ fn extra_balance_should_transfer() { || { assert_eq!(System::block_number(), 1); assert_ok!(Balances::transfer(Some(3).into(), 1, 100)); + assert_ok!(Balances::transfer(Some(3).into(), 2, 100)); + let user1_free_balance = Balances::free_balance(&1); assert_eq!(user1_free_balance, 200); // Account 1 has 100 more free balance than normal - assert_eq!(Balances::vesting_balance(&1), 90); // Account 1 has 90 units vested at block 1 - assert_ok!(Balances::transfer(Some(1).into(), 2, 105)); // Account 1 can send extra units gained + let user2_free_balance = Balances::free_balance(&2); + assert_eq!(user2_free_balance, 300); // Account 2 has 100 more free balance than normal + + // Account 1 has only 5 units vested at block 1 (plus 150 unvested) + assert_eq!(Balances::vesting_balance(&1), 45); + assert_ok!(Balances::transfer(Some(1).into(), 3, 155)); // Account 1 can send extra units gained + + // Account 2 has no units vested at block 1, but gained 100 + assert_eq!(Balances::vesting_balance(&2), 200); + assert_ok!(Balances::transfer(Some(2).into(), 3, 100)); // Account 2 can send extra units gained + } + ); +} + +#[test] +fn liquid_funds_should_transfer_with_delayed_vesting() { + with_externalities( + &mut ExtBuilder::default() + .existential_deposit(256) + .monied(true) + .vesting(true) + .build(), + || { + assert_eq!(System::block_number(), 1); + let user12_free_balance = Balances::free_balance(&12); + + assert_eq!(user12_free_balance, 2560); // Account 12 has free balance + // Account 12 has liquid funds + assert_eq!(Balances::vesting_balance(&12), user12_free_balance - 256 * 5); + + // Account 12 has delayed vesting + let user12_vesting_schedule = VestingSchedule { + locked: 256 * 5, + per_block: 64, // Vesting over 20 blocks + starting_block: 10, + }; + assert_eq!(Balances::vesting(&12), Some(user12_vesting_schedule)); + + // Account 12 can still send liquid funds + assert_ok!(Balances::transfer(Some(12).into(), 3, 256 * 5)); } ); } diff --git a/srml/council/Cargo.toml b/srml/collective/Cargo.toml similarity index 82% rename from srml/council/Cargo.toml rename to srml/collective/Cargo.toml index c180846b8e969dfde3e126ae5840ef12b7c59db2..cd0bb17871a4add8b4c88f38dd98495de4f87e01 100644 --- a/srml/council/Cargo.toml +++ b/srml/collective/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "srml-council" +name = "srml-collective" version = "2.0.0" authors = ["Parity Technologies "] edition = "2018" @@ -7,13 +7,12 @@ edition = "2018" [dependencies] serde = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false} -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } substrate-primitives = { path = "../../core/primitives", default-features = false } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } runtime_io = { package = "sr-io", path = "../../core/sr-io", default-features = false } primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } srml-support = { path = "../support", default-features = false } -democracy = { package = "srml-democracy", path = "../democracy", default-features = false } system = { package = "srml-system", path = "../system", default-features = false } [dev-dependencies] @@ -31,6 +30,5 @@ std = [ "runtime_io/std", "srml-support/std", "primitives/std", - "democracy/std", "system/std", ] diff --git a/srml/collective/src/lib.rs b/srml/collective/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..153a5df00ae8df246c46712c14b7fd8d28aac0e5 --- /dev/null +++ b/srml/collective/src/lib.rs @@ -0,0 +1,728 @@ +// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +//! Collective system: Members of a set of account IDs can make their collective feelings known +//! through dispatched calls from one of two specialised origins. + +#![cfg_attr(not(feature = "std"), no_std)] +#![recursion_limit="128"] + +use rstd::{prelude::*, result}; +use substrate_primitives::u32_trait::Value as U32; +use primitives::traits::{Hash, EnsureOrigin}; +use srml_support::{ + dispatch::{Dispatchable, Parameter}, codec::{Encode, Decode}, traits::ChangeMembers, + StorageValue, StorageMap, decl_module, decl_event, decl_storage, ensure +}; +use system::{self, ensure_signed, ensure_root}; + +/// Simple index type for proposal counting. +pub type ProposalIndex = u32; + +/// A number of members. +/// +/// This also serves as a number of voting members, and since for motions, each member may +/// vote exactly once, therefore also the number of votes for any given motion. +pub type MemberCount = u32; + +pub trait Trait: system::Trait { + /// The outer origin type. + type Origin: From>; + + /// The outer call dispatch type. + type Proposal: Parameter + Dispatchable>::Origin>; + + /// The outer event type. + type Event: From> + Into<::Event>; +} + +/// Origin for the collective module. +#[derive(PartialEq, Eq, Clone)] +#[cfg_attr(feature = "std", derive(Debug))] +pub enum RawOrigin { + /// It has been condoned by a given number of members of the collective from a given total. + Members(MemberCount, MemberCount), + /// It has been condoned by a single member of the collective. + Member(AccountId), + /// Dummy to manage the fact we have instancing. + _Phantom(rstd::marker::PhantomData), +} + +/// Origin for the collective module. +pub type Origin = RawOrigin<::AccountId, I>; + +#[derive(PartialEq, Eq, Clone, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Debug))] +/// Info for keeping track of a motion being voted on. +pub struct Votes { + /// The proposal's unique index. + index: ProposalIndex, + /// The number of approval votes that are needed to pass the motion. + threshold: MemberCount, + /// The current set of voters that approved it. + ayes: Vec, + /// The current set of voters that rejected it. + nays: Vec, +} + +decl_storage! { + trait Store for Module, I: Instance=DefaultInstance> as Collective { + /// The hashes of the active proposals. + pub Proposals get(proposals): Vec; + /// Actual proposal for a given hash, if it's current. + pub ProposalOf get(proposal_of): map T::Hash => Option<>::Proposal>; + /// Votes on a given proposal, if it is ongoing. + pub Voting get(voting): map T::Hash => Option>; + /// Proposals so far. + pub ProposalCount get(proposal_count): u32; + /// The current members of the collective. This is stored sorted (just by value). + pub Members get(members) config(): Vec; + } + add_extra_genesis { + config(phantom): rstd::marker::PhantomData; + } +} + +decl_event!( + pub enum Event where + ::Hash, + ::AccountId, + Phantom = rstd::marker::PhantomData + { + /// Dummy to manage the fact we have instancing. + _Phantom(Phantom), + /// A motion (given hash) has been proposed (by given account) with a threshold (given + /// `MemberCount`). + Proposed(AccountId, ProposalIndex, Hash, MemberCount), + /// A motion (given hash) has been voted on by given account, leaving + /// a tally (yes votes and no votes given respectively as `MemberCount`). + Voted(AccountId, Hash, bool, MemberCount, MemberCount), + /// A motion was approved by the required threshold. + Approved(Hash), + /// A motion was not approved by the required threshold. + Disapproved(Hash), + /// A motion was executed; `bool` is true if returned without error. + Executed(Hash, bool), + /// A single member did some action; `bool` is true if returned without error. + MemberExecuted(Hash, bool), + } +); + +decl_module! { + pub struct Module, I: Instance=DefaultInstance> for enum Call where origin: ::Origin { + fn deposit_event() = default; + + /// Set the collective's membership manually to `new_members`. Be nice to the chain and + /// provide it pre-sorted. + /// + /// Requires root origin. + fn set_members(origin, new_members: Vec) { + ensure_root(origin)?; + + // stable sorting since they will generally be provided sorted. + let mut old_members = >::get(); + old_members.sort(); + let mut new_members = new_members; + new_members.sort(); + let mut old_iter = old_members.iter(); + let mut new_iter = new_members.iter(); + let mut incoming = vec![]; + let mut outgoing = vec![]; + let mut old_i = old_iter.next(); + let mut new_i = new_iter.next(); + loop { + match (old_i, new_i) { + (None, None) => break, + (Some(old), Some(new)) if old == new => { + old_i = old_iter.next(); + new_i = new_iter.next(); + } + (Some(old), Some(new)) if old < new => { + outgoing.push(old.clone()); + old_i = old_iter.next(); + } + (Some(old), None) => { + outgoing.push(old.clone()); + old_i = old_iter.next(); + } + (_, Some(new)) => { + incoming.push(new.clone()); + new_i = new_iter.next(); + } + } + } + + Self::change_members(&incoming, &outgoing, &new_members); + } + + /// Dispatch a proposal from a member using the `Member` origin. + /// + /// Origin must be a member of the collective. + fn execute(origin, proposal: Box<>::Proposal>) { + let who = ensure_signed(origin)?; + ensure!(Self::is_member(&who), "proposer not a member"); + + let proposal_hash = T::Hashing::hash_of(&proposal); + let ok = proposal.dispatch(RawOrigin::Member(who).into()).is_ok(); + Self::deposit_event(RawEvent::MemberExecuted(proposal_hash, ok)); + } + + /// # + /// - Bounded storage reads and writes. + /// - Argument `threshold` has bearing on weight. + /// # + fn propose(origin, #[compact] threshold: MemberCount, proposal: Box<>::Proposal>) { + let who = ensure_signed(origin)?; + + ensure!(Self::is_member(&who), "proposer not a member"); + + let proposal_hash = T::Hashing::hash_of(&proposal); + + ensure!(!>::exists(proposal_hash), "duplicate proposals not allowed"); + + if threshold < 2 { + let seats = Self::members().len() as MemberCount; + let ok = proposal.dispatch(RawOrigin::Members(1, seats).into()).is_ok(); + Self::deposit_event(RawEvent::Executed(proposal_hash, ok)); + } else { + let index = Self::proposal_count(); + >::mutate(|i| *i += 1); + >::mutate(|proposals| proposals.push(proposal_hash)); + >::insert(proposal_hash, *proposal); + let votes = Votes { index, threshold, ayes: vec![who.clone()], nays: vec![] }; + >::insert(proposal_hash, votes); + + Self::deposit_event(RawEvent::Proposed(who, index, proposal_hash, threshold)); + } + } + + /// # + /// - Bounded storage read and writes. + /// - Will be slightly heavier if the proposal is approved / disapproved after the vote. + /// # + fn vote(origin, proposal: T::Hash, #[compact] index: ProposalIndex, approve: bool) { + let who = ensure_signed(origin)?; + + ensure!(Self::is_member(&who), "voter not a member"); + + let mut voting = Self::voting(&proposal).ok_or("proposal must exist")?; + ensure!(voting.index == index, "mismatched index"); + + let position_yes = voting.ayes.iter().position(|a| a == &who); + let position_no = voting.nays.iter().position(|a| a == &who); + + if approve { + if position_yes.is_none() { + voting.ayes.push(who.clone()); + } else { + return Err("duplicate vote ignored") + } + if let Some(pos) = position_no { + voting.nays.swap_remove(pos); + } + } else { + if position_no.is_none() { + voting.nays.push(who.clone()); + } else { + return Err("duplicate vote ignored") + } + if let Some(pos) = position_yes { + voting.ayes.swap_remove(pos); + } + } + + let yes_votes = voting.ayes.len() as MemberCount; + let no_votes = voting.nays.len() as MemberCount; + Self::deposit_event(RawEvent::Voted(who, proposal, approve, yes_votes, no_votes)); + + let seats = Self::members().len() as MemberCount; + let approved = yes_votes >= voting.threshold; + let disapproved = seats.saturating_sub(no_votes) < voting.threshold; + if approved || disapproved { + if approved { + Self::deposit_event(RawEvent::Approved(proposal)); + + // execute motion, assuming it exists. + if let Some(p) = >::take(&proposal) { + let origin = RawOrigin::Members(voting.threshold, seats).into(); + let ok = p.dispatch(origin).is_ok(); + Self::deposit_event(RawEvent::Executed(proposal, ok)); + } + } else { + // disapproved + Self::deposit_event(RawEvent::Disapproved(proposal)); + } + + // remove vote + >::remove(&proposal); + >::mutate(|proposals| proposals.retain(|h| h != &proposal)); + } else { + // update voting + >::insert(&proposal, voting); + } + } + } +} + +impl, I: Instance> Module { + pub fn is_member(who: &T::AccountId) -> bool { + Self::members().contains(who) + } +} + +impl, I: Instance> ChangeMembers for Module { + fn change_members(_incoming: &[T::AccountId], outgoing: &[T::AccountId], new: &[T::AccountId]) { + // remove accounts from all current voting in motions. + let mut old = outgoing.to_vec(); + old.sort_unstable(); + for h in Self::proposals().into_iter() { + >::mutate(h, |v| + if let Some(mut votes) = v.take() { + votes.ayes = votes.ayes.into_iter() + .filter(|i| old.binary_search(i).is_err()) + .collect(); + votes.nays = votes.nays.into_iter() + .filter(|i| old.binary_search(i).is_err()) + .collect(); + *v = Some(votes); + } + ); + } + >::put_ref(new); + } +} + +/// Ensure that the origin `o` represents at least `n` members. Returns `Ok` or an `Err` +/// otherwise. +pub fn ensure_members(o: OuterOrigin, n: MemberCount) + -> result::Result +where + OuterOrigin: Into, OuterOrigin>> +{ + match o.into() { + Ok(RawOrigin::Members(x, _)) if x >= n => Ok(n), + _ => Err("bad origin: expected to be a threshold number of members"), + } +} + +pub struct EnsureMember(rstd::marker::PhantomData<(AccountId, I)>); +impl< + O: Into, O>> + From>, + AccountId, + I, +> EnsureOrigin for EnsureMember { + type Success = AccountId; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + RawOrigin::Member(id) => Ok(id), + r => Err(O::from(r)), + }) + } +} + +pub struct EnsureMembers(rstd::marker::PhantomData<(N, AccountId, I)>); +impl< + O: Into, O>> + From>, + N: U32, + AccountId, + I, +> EnsureOrigin for EnsureMembers { + type Success = (MemberCount, MemberCount); + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + RawOrigin::Members(n, m) if n >= N::VALUE => Ok((n, m)), + r => Err(O::from(r)), + }) + } +} + +pub struct EnsureProportionMoreThan( + rstd::marker::PhantomData<(N, D, AccountId, I)> +); +impl< + O: Into, O>> + From>, + N: U32, + D: U32, + AccountId, + I, +> EnsureOrigin for EnsureProportionMoreThan { + type Success = (); + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + RawOrigin::Members(n, m) if n * D::VALUE > N::VALUE * m => Ok(()), + r => Err(O::from(r)), + }) + } +} + +pub struct EnsureProportionAtLeast( + rstd::marker::PhantomData<(N, D, AccountId, I)> +); +impl< + O: Into, O>> + From>, + N: U32, + D: U32, + AccountId, + I, +> EnsureOrigin for EnsureProportionAtLeast { + type Success = (); + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + RawOrigin::Members(n, m) if n * D::VALUE >= N::VALUE * m => Ok(()), + r => Err(O::from(r)), + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use srml_support::{Hashable, assert_ok, assert_noop, parameter_types}; + use system::{EventRecord, Phase}; + use hex_literal::hex; + use runtime_io::with_externalities; + use substrate_primitives::{H256, Blake2Hasher}; + use primitives::{ + traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, testing::Header, BuildStorage + }; + use crate as collective; + + parameter_types! { + pub const BlockHashCount: u64 = 250; + } + impl system::Trait for Test { + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + } + impl Trait for Test { + type Origin = Origin; + type Proposal = Call; + type Event = Event; + } + + pub type Block = primitives::generic::Block; + pub type UncheckedExtrinsic = primitives::generic::UncheckedMortalCompactExtrinsic; + + srml_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: system::{Module, Call, Event}, + Collective: collective::::{Module, Call, Event, Origin, Config}, + } + ); + + fn make_ext() -> runtime_io::TestExternalities { + GenesisConfig { + collective_Instance1: Some(collective::GenesisConfig { + members: vec![1, 2, 3], + phantom: Default::default(), + }), + }.build_storage().unwrap().0.into() + } + + #[test] + fn motions_basic_environment_works() { + with_externalities(&mut make_ext(), || { + System::set_block_number(1); + assert_eq!(Collective::members(), vec![1, 2, 3]); + assert_eq!(Collective::proposals(), Vec::::new()); + }); + } + + fn make_proposal(value: u64) -> Call { + Call::System(system::Call::remark(value.encode())) + } + + #[test] + fn removal_of_old_voters_votes_works() { + with_externalities(&mut make_ext(), || { + System::set_block_number(1); + let proposal = make_proposal(42); + let hash = BlakeTwo256::hash_of(&proposal); + assert_ok!(Collective::propose(Origin::signed(1), 3, Box::new(proposal.clone()))); + assert_ok!(Collective::vote(Origin::signed(2), hash.clone(), 0, true)); + assert_eq!( + Collective::voting(&hash), + Some(Votes { index: 0, threshold: 3, ayes: vec![1, 2], nays: vec![] }) + ); + Collective::change_members(&[4], &[1], &[2, 3, 4]); + assert_eq!( + Collective::voting(&hash), + Some(Votes { index: 0, threshold: 3, ayes: vec![2], nays: vec![] }) + ); + + let proposal = make_proposal(69); + let hash = BlakeTwo256::hash_of(&proposal); + assert_ok!(Collective::propose(Origin::signed(2), 2, Box::new(proposal.clone()))); + assert_ok!(Collective::vote(Origin::signed(3), hash.clone(), 1, false)); + assert_eq!( + Collective::voting(&hash), + Some(Votes { index: 1, threshold: 2, ayes: vec![2], nays: vec![3] }) + ); + Collective::change_members(&[], &[3], &[2, 4]); + assert_eq!( + Collective::voting(&hash), + Some(Votes { index: 1, threshold: 2, ayes: vec![2], nays: vec![] }) + ); + }); + } + + #[test] + fn removal_of_old_voters_votes_works_with_set_members() { + with_externalities(&mut make_ext(), || { + System::set_block_number(1); + let proposal = make_proposal(42); + let hash = BlakeTwo256::hash_of(&proposal); + assert_ok!(Collective::propose(Origin::signed(1), 3, Box::new(proposal.clone()))); + assert_ok!(Collective::vote(Origin::signed(2), hash.clone(), 0, true)); + assert_eq!( + Collective::voting(&hash), + Some(Votes { index: 0, threshold: 3, ayes: vec![1, 2], nays: vec![] }) + ); + assert_ok!(Collective::set_members(Origin::ROOT, vec![2, 3, 4])); + assert_eq!( + Collective::voting(&hash), + Some(Votes { index: 0, threshold: 3, ayes: vec![2], nays: vec![] }) + ); + + let proposal = make_proposal(69); + let hash = BlakeTwo256::hash_of(&proposal); + assert_ok!(Collective::propose(Origin::signed(2), 2, Box::new(proposal.clone()))); + assert_ok!(Collective::vote(Origin::signed(3), hash.clone(), 1, false)); + assert_eq!( + Collective::voting(&hash), + Some(Votes { index: 1, threshold: 2, ayes: vec![2], nays: vec![3] }) + ); + assert_ok!(Collective::set_members(Origin::ROOT, vec![2, 4])); + assert_eq!( + Collective::voting(&hash), + Some(Votes { index: 1, threshold: 2, ayes: vec![2], nays: vec![] }) + ); + }); + } + + #[test] + fn propose_works() { + with_externalities(&mut make_ext(), || { + System::set_block_number(1); + let proposal = make_proposal(42); + let hash = proposal.blake2_256().into(); + assert_ok!(Collective::propose(Origin::signed(1), 3, Box::new(proposal.clone()))); + assert_eq!(Collective::proposals(), vec![hash]); + assert_eq!(Collective::proposal_of(&hash), Some(proposal)); + assert_eq!( + Collective::voting(&hash), + Some(Votes { index: 0, threshold: 3, ayes: vec![1], nays: vec![] }) + ); + + assert_eq!(System::events(), vec![ + EventRecord { + phase: Phase::Finalization, + event: Event::collective_Instance1(RawEvent::Proposed( + 1, + 0, + hex!["10b209e55d0f37cd45574674bba42519a29bf0ccf3c85c3c773fcbacab820bb4"].into(), + 3, + )), + topics: vec![], + } + ]); + }); + } + + #[test] + fn motions_ignoring_non_collective_proposals_works() { + with_externalities(&mut make_ext(), || { + System::set_block_number(1); + let proposal = make_proposal(42); + assert_noop!( + Collective::propose(Origin::signed(42), 3, Box::new(proposal.clone())), + "proposer not a member" + ); + }); + } + + #[test] + fn motions_ignoring_non_collective_votes_works() { + with_externalities(&mut make_ext(), || { + System::set_block_number(1); + let proposal = make_proposal(42); + let hash: H256 = proposal.blake2_256().into(); + assert_ok!(Collective::propose(Origin::signed(1), 3, Box::new(proposal.clone()))); + assert_noop!(Collective::vote(Origin::signed(42), hash.clone(), 0, true), "voter not a member"); + }); + } + + #[test] + fn motions_ignoring_bad_index_collective_vote_works() { + with_externalities(&mut make_ext(), || { + System::set_block_number(3); + let proposal = make_proposal(42); + let hash: H256 = proposal.blake2_256().into(); + assert_ok!(Collective::propose(Origin::signed(1), 3, Box::new(proposal.clone()))); + assert_noop!(Collective::vote(Origin::signed(2), hash.clone(), 1, true), "mismatched index"); + }); + } + + #[test] + fn motions_revoting_works() { + with_externalities(&mut make_ext(), || { + System::set_block_number(1); + let proposal = make_proposal(42); + let hash: H256 = proposal.blake2_256().into(); + assert_ok!(Collective::propose(Origin::signed(1), 2, Box::new(proposal.clone()))); + assert_eq!( + Collective::voting(&hash), + Some(Votes { index: 0, threshold: 2, ayes: vec![1], nays: vec![] }) + ); + assert_noop!(Collective::vote(Origin::signed(1), hash.clone(), 0, true), "duplicate vote ignored"); + assert_ok!(Collective::vote(Origin::signed(1), hash.clone(), 0, false)); + assert_eq!( + Collective::voting(&hash), + Some(Votes { index: 0, threshold: 2, ayes: vec![], nays: vec![1] }) + ); + assert_noop!(Collective::vote(Origin::signed(1), hash.clone(), 0, false), "duplicate vote ignored"); + + assert_eq!(System::events(), vec![ + EventRecord { + phase: Phase::Finalization, + event: Event::collective_Instance1(RawEvent::Proposed( + 1, + 0, + hex!["10b209e55d0f37cd45574674bba42519a29bf0ccf3c85c3c773fcbacab820bb4"].into(), + 2, + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Finalization, + event: Event::collective_Instance1(RawEvent::Voted( + 1, + hex!["10b209e55d0f37cd45574674bba42519a29bf0ccf3c85c3c773fcbacab820bb4"].into(), + false, + 0, + 1, + )), + topics: vec![], + } + ]); + }); + } + + #[test] + fn motions_disapproval_works() { + with_externalities(&mut make_ext(), || { + System::set_block_number(1); + let proposal = make_proposal(42); + let hash: H256 = proposal.blake2_256().into(); + assert_ok!(Collective::propose(Origin::signed(1), 3, Box::new(proposal.clone()))); + assert_ok!(Collective::vote(Origin::signed(2), hash.clone(), 0, false)); + + assert_eq!(System::events(), vec![ + EventRecord { + phase: Phase::Finalization, + event: Event::collective_Instance1( + RawEvent::Proposed( + 1, + 0, + hex!["10b209e55d0f37cd45574674bba42519a29bf0ccf3c85c3c773fcbacab820bb4"].into(), + 3, + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Finalization, + event: Event::collective_Instance1(RawEvent::Voted( + 2, + hex!["10b209e55d0f37cd45574674bba42519a29bf0ccf3c85c3c773fcbacab820bb4"].into(), + false, + 1, + 1, + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Finalization, + event: Event::collective_Instance1(RawEvent::Disapproved( + hex!["10b209e55d0f37cd45574674bba42519a29bf0ccf3c85c3c773fcbacab820bb4"].into(), + )), + topics: vec![], + } + ]); + }); + } + + #[test] + fn motions_approval_works() { + with_externalities(&mut make_ext(), || { + System::set_block_number(1); + let proposal = make_proposal(42); + let hash: H256 = proposal.blake2_256().into(); + assert_ok!(Collective::propose(Origin::signed(1), 2, Box::new(proposal.clone()))); + assert_ok!(Collective::vote(Origin::signed(2), hash.clone(), 0, true)); + + assert_eq!(System::events(), vec![ + EventRecord { + phase: Phase::Finalization, + event: Event::collective_Instance1(RawEvent::Proposed( + 1, + 0, + hex!["10b209e55d0f37cd45574674bba42519a29bf0ccf3c85c3c773fcbacab820bb4"].into(), + 2, + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Finalization, + event: Event::collective_Instance1(RawEvent::Voted( + 2, + hex!["10b209e55d0f37cd45574674bba42519a29bf0ccf3c85c3c773fcbacab820bb4"].into(), + true, + 2, + 0, + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Finalization, + event: Event::collective_Instance1(RawEvent::Approved( + hex!["10b209e55d0f37cd45574674bba42519a29bf0ccf3c85c3c773fcbacab820bb4"].into(), + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Finalization, + event: Event::collective_Instance1(RawEvent::Executed( + hex!["10b209e55d0f37cd45574674bba42519a29bf0ccf3c85c3c773fcbacab820bb4"].into(), + false, + )), + topics: vec![], + } + ]); + }); + } +} diff --git a/srml/contracts/COMPLEXITY.md b/srml/contracts/COMPLEXITY.md index d87525a982291d20c6480ed24301780255c6dc23..acf1ee737589f566a66544aef0373e5be2ed615e 100644 --- a/srml/contracts/COMPLEXITY.md +++ b/srml/contracts/COMPLEXITY.md @@ -172,15 +172,27 @@ Assuming marshaled size of a balance value is of the constant size we can neglec **complexity**: up to 2 DB reads and up to 2 DB writes (if flushed to the storage) in the standard case. If removal of the source account takes place then it will additionally perform a DB write per one storage entry that the account has. For the current `AccountDb` implementation computing complexity also depends on the depth of the `AccountDb` cascade. Memorywise it can be assumed to be constant. +## Initialization + +Before a call or create can be performed the execution context must be initialized. This involves +two calls: + +1. `>::now()` +2. `>::block_number()` + +the complexity of initialization depends on the complexity of these functions. In the current +implementation they just involve a DB read. + ## Call This function receives input data for the contract execution. The execution consists of the following steps: -1. Checking rent payment. -2. Loading code from the DB. -3. `transfer`-ing funds between the caller and the destination account. -4. Executing the code of the destination account. -5. Committing overlayed changed to the underlying `AccountDb`. +1. Initialization of the execution context. +2. Checking rent payment. +3. Loading code from the DB. +4. `transfer`-ing funds between the caller and the destination account. +5. Executing the code of the destination account. +6. Committing overlayed changed to the underlying `AccountDb`. **Note** that the complexity of executing the contract code should be considered separately. @@ -211,11 +223,12 @@ Finally, all changes are `commit`-ted into the underlying overlay. The complexit This function takes the code of the constructor and input data. Creation of a contract consists of the following steps: -1. Calling `DetermineContractAddress` hook to determine an address for the contract, -2. `transfer`-ing funds between self and the newly created contract. -3. Executing the constructor code. This will yield the final code of the code. -4. Storing the code for the newly created contract in the overlay. -5. Committing overlayed changed to the underlying `AccountDb`. +1. Initialization of the execution context. +2. Calling `DetermineContractAddress` hook to determine an address for the contract, +3. `transfer`-ing funds between self and the newly created contract. +4. Executing the constructor code. This will yield the final code of the code. +5. Storing the code for the newly created contract in the overlay. +6. Committing overlayed changed to the underlying `AccountDb`. **Note** that the complexity of executing the constructor code should be considered separately. @@ -348,18 +361,6 @@ This function serializes the current block's timestamp into the scratch buffer. **complexity**: Assuming that the timestamp is of constant size, this function has constant complexity. -## ext_input_size - -**complexity**: This function is of constant complexity. - -## ext_input_copy - -This function copies slice of data from the input buffer to the sandbox memory. The calling code specifies the slice length. Execution of the function consists of the following steps: - -1. Storing a specified slice of the input data into the sandbox memory (see sandboxing memory set) - -**complexity**: The computing complexity of this function is proportional to the length of the slice. No additional memory is required. - ## ext_scratch_size This function returns the size of the scratch buffer. @@ -396,3 +397,9 @@ It consists of the following steps: **complexity**: Assuming that the rent allowance is of constant size, this function has constant complexity. This function performs a DB read. + +## ext_block_number + +This function serializes the current block's number into the scratch buffer. + +**complexity**: Assuming that the block number is of constant size, this function has constant complexity. diff --git a/srml/contracts/Cargo.toml b/srml/contracts/Cargo.toml index 08c44bf63af1e664398d90bfa1387a71f612a667..19afc06406110c6ce9e3b9f127eb50f1089afef8 100644 --- a/srml/contracts/Cargo.toml +++ b/srml/contracts/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] serde = { version = "1.0", optional = true, features = ["derive"] } pwasm-utils = { version = "0.6.1", default-features = false } -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } parity-wasm = { version = "0.31", default-features = false } wasmi-validation = { version = "0.1", default-features = false } substrate-primitives = { path = "../../core/primitives", default-features = false } diff --git a/srml/contracts/src/account_db.rs b/srml/contracts/src/account_db.rs index 80d5fbe3bba58d8af2319e54b4e11a3d333abcd0..f91226641575cf1563981293b41bdb6ddf2d85d6 100644 --- a/srml/contracts/src/account_db.rs +++ b/srml/contracts/src/account_db.rs @@ -14,10 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! Auxilliaries to help with managing partial changes to accounts state. +//! Auxiliaries to help with managing partial changes to accounts state. use super::{ - AliveContractInfo, BalanceOf, CodeHash, ContractInfo, ContractInfoOf, Module, Trait, TrieId, + AliveContractInfo, BalanceOf, CodeHash, ContractInfo, ContractInfoOf, Trait, TrieId, TrieIdGenerator, }; use crate::exec::StorageKey; @@ -26,7 +26,7 @@ use rstd::collections::btree_map::{BTreeMap, Entry}; use rstd::prelude::*; use runtime_io::blake2_256; use runtime_primitives::traits::{Bounded, Zero}; -use srml_support::traits::{Currency, Imbalance, SignedImbalance, UpdateBalanceOutcome}; +use srml_support::traits::{Currency, Get, Imbalance, SignedImbalance, UpdateBalanceOutcome}; use srml_support::{storage::child, StorageMap}; use system; @@ -125,7 +125,7 @@ impl AccountDb for DirectAccountDb { } else if let Some(code_hash) = changed.code_hash { AliveContractInfo:: { code_hash, - storage_size: >::storage_size_offset(), + storage_size: T::StorageSizeOffset::get(), trie_id: ::TrieIdGenerator::trie_id(&address), deduct_block: >::block_number(), rent_allowance: >::max_value(), diff --git a/srml/contracts/src/exec.rs b/srml/contracts/src/exec.rs index 7a16c9d60dc7c0ca0ffbf0033224eae1b4adc808..d2abbb8ee755717bf761aa806c801d554fa611a9 100644 --- a/srml/contracts/src/exec.rs +++ b/srml/contracts/src/exec.rs @@ -15,19 +15,21 @@ // along with Substrate. If not, see . use super::{CodeHash, Config, ContractAddressFor, Event, RawEvent, Trait, - TrieId, BalanceOf, ContractInfoOf}; + TrieId, BalanceOf, ContractInfo}; use crate::account_db::{AccountDb, DirectAccountDb, OverlayAccountDb}; -use crate::gas::{GasMeter, Token, approx_gas_for_balance}; +use crate::gas::{Gas, GasMeter, Token, approx_gas_for_balance}; +use crate::rent; use rstd::prelude::*; use runtime_primitives::traits::{Bounded, CheckedAdd, CheckedSub, Zero}; -use srml_support::{StorageMap, traits::{WithdrawReason, Currency}}; +use srml_support::traits::{WithdrawReason, Currency}; use timestamp; pub type AccountIdOf = ::AccountId; pub type CallOf = ::Call; pub type MomentOf = ::Moment; pub type SeedOf = ::Hash; +pub type BlockNumberOf = ::BlockNumber; /// A type that represents a topic of an event. At the moment a hash is used. pub type TopicOf = ::Hash; @@ -67,7 +69,7 @@ pub trait Ext { /// Instantiate a contract from the given code. /// /// The newly created account will be associated with `code`. `value` specifies the amount of value - /// transfered from this to the newly created account (also known as endowment). + /// transferred from this to the newly created account (also known as endowment). fn instantiate( &mut self, code: &CodeHash, @@ -76,7 +78,7 @@ pub trait Ext { input_data: &[u8], ) -> Result>, &'static str>; - /// Call (possibly transfering some amount of funds) into the specified account. + /// Call (possibly transferring some amount of funds) into the specified account. fn call( &mut self, to: &AccountIdOf, @@ -100,7 +102,7 @@ pub trait Ext { /// The `value_transferred` is already added. fn balance(&self) -> BalanceOf; - /// Returns the value transfered along with this call or as endowment. + /// Returns the value transferred along with this call or as endowment. fn value_transferred(&self) -> BalanceOf; /// Returns a reference to the timestamp of the current block @@ -119,6 +121,9 @@ pub trait Ext { /// Rent allowance of the contract fn rent_allowance(&self) -> BalanceOf; + + /// Returns the current block number. + fn block_number(&self) -> BlockNumberOf; } /// Loader is a companion of the `Vm` trait. It loads an appropriate abstract @@ -239,10 +244,10 @@ pub enum ExecFeeToken { impl Token for ExecFeeToken { type Metadata = Config; #[inline] - fn calculate_amount(&self, metadata: &Config) -> T::Gas { + fn calculate_amount(&self, metadata: &Config) -> Gas { match *self { - ExecFeeToken::Call => metadata.call_base_fee, - ExecFeeToken::Instantiate => metadata.instantiate_base_fee, + ExecFeeToken::Call => metadata.schedule.call_base_cost, + ExecFeeToken::Instantiate => metadata.schedule.instantiate_base_cost, } } } @@ -267,11 +272,11 @@ where { /// Create the top level execution context. /// - /// The specified `origin` address will be used as `sender` for + /// The specified `origin` address will be used as `sender` for. The `origin` must be a regular + /// account (not a contract). pub fn top_level(origin: T::AccountId, cfg: &'a Config, vm: &'a V, loader: &'a L) -> Self { ExecutionContext { - self_trie_id: >::get(&origin) - .and_then(|i| i.as_alive().map(|i| i.trie_id.clone())), + self_trie_id: None, self_account: origin, overlay: OverlayAccountDb::::new(&DirectAccountDb), depth: 0, @@ -283,10 +288,11 @@ where } } - fn nested(&self, overlay: OverlayAccountDb<'a, T>, dest: T::AccountId) -> Self { + fn nested(&self, overlay: OverlayAccountDb<'a, T>, dest: T::AccountId, trie_id: Option) + -> Self + { ExecutionContext { - self_trie_id: >::get(&dest) - .and_then(|i| i.as_alive().map(|i| i.trie_id.clone())), + self_trie_id: trie_id, self_account: dest, overlay, depth: self.depth + 1, @@ -298,7 +304,7 @@ where } } - /// Make a call to the specified address, optionally transfering some funds. + /// Make a call to the specified address, optionally transferring some funds. pub fn call( &mut self, dest: T::AccountId, @@ -321,14 +327,20 @@ where // Assumption: pay_rent doesn't collide with overlay because // pay_rent will be done on first call and dest contract and balance // cannot be changed before the first call - crate::rent::pay_rent::(&dest); + let contract_info = rent::pay_rent::(&dest); + + // Calls to dead contracts always fail. + if let Some(ContractInfo::Tombstone(_)) = contract_info { + return Err("contract has been evicted"); + }; let mut output_data = Vec::new(); let (change_set, events, calls) = { let mut nested = self.nested( OverlayAccountDb::new(&self.overlay), - dest.clone() + dest.clone(), + contract_info.and_then(|i| i.as_alive().map(|i| i.trie_id.clone())) ); if value > BalanceOf::::zero() { @@ -342,6 +354,8 @@ where )?; } + // If code_hash is not none, then the destination account is a live contract, otherwise + // it is a regular account since tombstone accounts have already been rejected. if let Some(dest_code_hash) = self.overlay.get_code_hash(&dest) { let executable = self.loader.load_main(&dest_code_hash)?; output_data = self @@ -352,7 +366,8 @@ where ctx: &mut nested, caller: self.self_account.clone(), value_transferred: value, - timestamp: timestamp::Module::::now(), + timestamp: >::now(), + block_number: >::block_number(), }, input_data, empty_output_buf, @@ -400,7 +415,8 @@ where overlay.create_contract(&dest, code_hash.clone())?; - let mut nested = self.nested(overlay, dest.clone()); + // TrieId has not been generated yet and storage is empty since contract is new. + let mut nested = self.nested(overlay, dest.clone(), None); // Send funds unconditionally here. If the `endowment` is below existential_deposit // then error will be returned here. @@ -421,7 +437,8 @@ where ctx: &mut nested, caller: self.self_account.clone(), value_transferred: endowment, - timestamp: timestamp::Module::::now(), + timestamp: >::now(), + block_number: >::block_number(), }, input_data, EmptyOutputBuf::new(), @@ -465,13 +482,13 @@ impl Token for TransferFeeToken> { type Metadata = Config; #[inline] - fn calculate_amount(&self, metadata: &Config) -> T::Gas { + fn calculate_amount(&self, metadata: &Config) -> Gas { let balance_fee = match self.kind { TransferFeeKind::ContractInstantiate => metadata.contract_account_instantiate_fee, TransferFeeKind::AccountCreate => metadata.account_create_fee, TransferFeeKind::Transfer => metadata.transfer_fee, }; - approx_gas_for_balance::(self.gas_price, balance_fee) + approx_gas_for_balance(self.gas_price, balance_fee) } } @@ -487,11 +504,11 @@ enum TransferCause { /// /// This function also handles charging the fee. The fee depends /// on whether the transfer happening because of contract instantiation -/// (transfering endowment) or because of a transfer via `call`. This +/// (transferring endowment) or because of a transfer via `call`. This /// is specified using the `cause` parameter. /// /// NOTE: that the fee is denominated in `BalanceOf` units, but -/// charged in `T::Gas` from the provided `gas_meter`. This means +/// charged in `Gas` from the provided `gas_meter`. This means /// that the actual amount charged might differ. /// /// NOTE: that we allow for draining all funds of the contract so it @@ -574,6 +591,7 @@ struct CallContext<'a, 'b: 'a, T: Trait + 'b, V: Vm + 'b, L: Loader> { caller: T::AccountId, value_transferred: BalanceOf, timestamp: T::Moment, + block_number: T::BlockNumber, } impl<'a, 'b: 'a, T, E, V, L> Ext for CallContext<'a, 'b, T, V, L> @@ -662,6 +680,8 @@ where self.ctx.overlay.get_rent_allowance(&self.ctx.self_account) .unwrap_or(>::max_value()) // Must never be triggered actually } + + fn block_number(&self) -> T::BlockNumber { self.block_number } } /// These tests exercise the executive layer. diff --git a/srml/contracts/src/gas.rs b/srml/contracts/src/gas.rs index 1ea519634463c7ed232e99f1ad9c363247c0ca20..44d5b32fd938b1f1ad5677a5f26a2396a1f27ad6 100644 --- a/srml/contracts/src/gas.rs +++ b/srml/contracts/src/gas.rs @@ -15,13 +15,19 @@ // along with Substrate. If not, see . use crate::{GasSpent, Module, Trait, BalanceOf, NegativeImbalanceOf}; +use rstd::convert::TryFrom; use runtime_primitives::BLOCK_FULL; -use runtime_primitives::traits::{CheckedMul, CheckedSub, Zero, SaturatedConversion}; -use srml_support::{StorageValue, traits::{OnUnbalanced, ExistenceRequirement, WithdrawReason, Currency, Imbalance}}; +use runtime_primitives::traits::{CheckedMul, Zero, SaturatedConversion, SimpleArithmetic, UniqueSaturatedInto}; +use srml_support::StorageValue; +use srml_support::traits::{Currency, ExistenceRequirement, Get, Imbalance, OnUnbalanced, WithdrawReason}; #[cfg(test)] use std::{any::Any, fmt::Debug}; +// Gas units are chosen to be represented by u64 so that gas metering instructions can operate on +// them efficiently. +pub type Gas = u64; + #[must_use] #[derive(Debug, PartialEq, Eq)] pub enum GasMeterResult { @@ -68,7 +74,7 @@ pub trait Token: Copy + Clone + TestAuxiliaries { /// That said, implementors of this function still can run into overflows /// while calculating the amount. In this case it is ok to use saturating operations /// since on overflow they will return `max_value` which should consume all gas. - fn calculate_amount(&self, metadata: &Self::Metadata) -> T::Gas; + fn calculate_amount(&self, metadata: &Self::Metadata) -> Gas; } /// A wrapper around a type-erased trait object of what used to be a `Token`. @@ -79,17 +85,16 @@ pub struct ErasedToken { } pub struct GasMeter { - limit: T::Gas, + limit: Gas, /// Amount of gas left from initial gas limit. Can reach zero. - gas_left: T::Gas, + gas_left: Gas, gas_price: BalanceOf, #[cfg(test)] tokens: Vec, } impl GasMeter { - #[cfg(test)] - pub fn with_limit(gas_limit: T::Gas, gas_price: BalanceOf) -> GasMeter { + pub fn with_limit(gas_limit: Gas, gas_price: BalanceOf) -> GasMeter { GasMeter { limit: gas_limit, gas_left: gas_limit, @@ -125,9 +130,8 @@ impl GasMeter { } let amount = token.calculate_amount(metadata); - let new_value = match self.gas_left.checked_sub(&amount) { + let new_value = match self.gas_left.checked_sub(amount) { None => None, - Some(val) if val.is_zero() => None, Some(val) => Some(val), }; @@ -149,7 +153,7 @@ impl GasMeter { /// All unused gas in the nested gas meter is returned to this gas meter. pub fn with_nested>) -> R>( &mut self, - amount: T::Gas, + amount: Gas, f: F, ) -> R { // NOTE that it is ok to allocate all available gas since it still ensured @@ -158,13 +162,7 @@ impl GasMeter { f(None) } else { self.gas_left = self.gas_left - amount; - let mut nested = GasMeter { - limit: amount, - gas_left: amount, - gas_price: self.gas_price, - #[cfg(test)] - tokens: Vec::new(), - }; + let mut nested = GasMeter::with_limit(amount, self.gas_price); let r = f(Some(&mut nested)); @@ -179,12 +177,12 @@ impl GasMeter { } /// Returns how much gas left from the initial budget. - pub fn gas_left(&self) -> T::Gas { + pub fn gas_left(&self) -> Gas { self.gas_left } /// Returns how much gas was spent. - fn spent(&self) -> T::Gas { + fn spent(&self) -> Gas { self.limit - self.gas_left } @@ -200,11 +198,11 @@ impl GasMeter { /// The funds are deducted from `transactor`. pub fn buy_gas( transactor: &T::AccountId, - gas_limit: T::Gas, + gas_limit: Gas, ) -> Result<(GasMeter, NegativeImbalanceOf), &'static str> { // Check if the specified amount of gas is available in the current block. - // This cannot underflow since `gas_spent` is never greater than `block_gas_limit`. - let gas_available = >::block_gas_limit() - >::gas_spent(); + // This cannot underflow since `gas_spent` is never greater than `T::BlockGasLimit`. + let gas_available = T::BlockGasLimit::get() - >::gas_spent(); if gas_limit > gas_available { // gas limit reached, revert the transaction and retry again in the future return Err(BLOCK_FULL); @@ -212,9 +210,13 @@ pub fn buy_gas( // Buy the specified amount of gas. let gas_price = >::gas_price(); - let cost = gas_limit.clone().into() - .checked_mul(&gas_price) - .ok_or("overflow multiplying gas limit by price")?; + let cost = if gas_price.is_zero() { + >::zero() + } else { + as TryFrom>::try_from(gas_limit).ok() + .and_then(|gas_limit| gas_price.checked_mul(&gas_limit)) + .ok_or("overflow multiplying gas limit by price")? + }; let imbalance = T::Currency::withdraw( transactor, @@ -223,14 +225,7 @@ pub fn buy_gas( ExistenceRequirement::KeepAlive )?; - Ok((GasMeter { - limit: gas_limit, - gas_left: gas_limit, - gas_price, - - #[cfg(test)] - tokens: Vec::new(), - }, imbalance)) + Ok((GasMeter::with_limit(gas_limit, gas_price), imbalance)) } /// Refund the unused gas. @@ -244,11 +239,11 @@ pub fn refund_unused_gas( // Increase total spent gas. // This cannot overflow, since `gas_spent` is never greater than `block_gas_limit`, which - // also has T::Gas type. - >::mutate(|block_gas_spent| *block_gas_spent += gas_spent); + // also has Gas type. + GasSpent::mutate(|block_gas_spent| *block_gas_spent += gas_spent); // Refund gas left by the price it was bought at. - let refund = gas_left.into() * gas_meter.gas_price; + let refund = gas_meter.gas_price * gas_left.unique_saturated_into(); let refund_imbalance = T::Currency::deposit_creating(transactor, refund); if let Ok(imbalance) = imbalance.offset(refund_imbalance) { T::GasPayment::on_unbalanced(imbalance); @@ -257,8 +252,10 @@ pub fn refund_unused_gas( /// A little handy utility for converting a value in balance units into approximate value in gas units /// at the given gas price. -pub fn approx_gas_for_balance(gas_price: BalanceOf, balance: BalanceOf) -> T::Gas { - (balance / gas_price).saturated_into::() +pub fn approx_gas_for_balance(gas_price: Balance, balance: Balance) -> Gas + where Balance: SimpleArithmetic +{ + (balance / gas_price).saturated_into::() } /// A simple utility macro that helps to match against a @@ -277,7 +274,7 @@ macro_rules! match_tokens { // have an iterator of Box and to downcast we need to specify // the type which we want downcast to. // - // So what we do is we assign `_pattern_typed_next_ref` to the a variable which has + // So what we do is we assign `_pattern_typed_next_ref` to a variable which has // the required type. // // Then we make `_pattern_typed_next_ref = token.downcast_ref()`. This makes @@ -304,25 +301,25 @@ mod tests { use super::{GasMeter, Token}; use crate::tests::Test; - /// A trivial token that charges 1 unit of gas. + /// A trivial token that charges the specified number of gas units. #[derive(Copy, Clone, PartialEq, Eq, Debug)] - struct UnitToken; - impl Token for UnitToken { + struct SimpleToken(u64); + impl Token for SimpleToken { type Metadata = (); - fn calculate_amount(&self, _metadata: &()) -> u64 { 1 } + fn calculate_amount(&self, _metadata: &()) -> u64 { self.0 } } - struct DoubleTokenMetadata { + struct MultiplierTokenMetadata { multiplier: u64, } /// A simple token that charges for the given amount multiplied to /// a multiplier taken from a given metadata. #[derive(Copy, Clone, PartialEq, Eq, Debug)] - struct DoubleToken(u64); + struct MultiplierToken(u64); - impl Token for DoubleToken { - type Metadata = DoubleTokenMetadata; - fn calculate_amount(&self, metadata: &DoubleTokenMetadata) -> u64 { + impl Token for MultiplierToken { + type Metadata = MultiplierTokenMetadata; + fn calculate_amount(&self, metadata: &MultiplierTokenMetadata) -> u64 { // Probably you want to use saturating mul in production code. self.0 * metadata.multiplier } @@ -338,7 +335,8 @@ mod tests { fn simple() { let mut gas_meter = GasMeter::::with_limit(50000, 10); - let result = gas_meter.charge(&DoubleTokenMetadata { multiplier: 3 }, DoubleToken(10)); + let result = gas_meter + .charge(&MultiplierTokenMetadata { multiplier: 3 }, MultiplierToken(10)); assert!(!result.is_out_of_gas()); assert_eq!(gas_meter.gas_left(), 49_970); @@ -349,12 +347,44 @@ mod tests { #[test] fn tracing() { let mut gas_meter = GasMeter::::with_limit(50000, 10); - assert!(!gas_meter.charge(&(), UnitToken).is_out_of_gas()); + assert!(!gas_meter.charge(&(), SimpleToken(1)).is_out_of_gas()); assert!(!gas_meter - .charge(&DoubleTokenMetadata { multiplier: 3 }, DoubleToken(10)) + .charge(&MultiplierTokenMetadata { multiplier: 3 }, MultiplierToken(10)) .is_out_of_gas()); let mut tokens = gas_meter.tokens()[0..2].iter(); - match_tokens!(tokens, UnitToken, DoubleToken(10),); + match_tokens!(tokens, SimpleToken(1), MultiplierToken(10),); + } + + // This test makes sure that nothing can be executed if there is no gas. + #[test] + fn refuse_to_execute_anything_if_zero() { + let mut gas_meter = GasMeter::::with_limit(0, 10); + assert!(gas_meter.charge(&(), SimpleToken(1)).is_out_of_gas()); + } + + // Make sure that if the gas meter is charged by exceeding amount then not only an error + // returned for that charge, but also for all consequent charges. + // + // This is not strictly necessary, because the execution should be interrupted immediately + // if the gas meter runs out of gas. However, this is just a nice property to have. + #[test] + fn overcharge_is_unrecoverable() { + let mut gas_meter = GasMeter::::with_limit(200, 10); + + // The first charge is should lead to OOG. + assert!(gas_meter.charge(&(), SimpleToken(300)).is_out_of_gas()); + + // The gas meter is emptied at this moment, so this should also fail. + assert!(gas_meter.charge(&(), SimpleToken(1)).is_out_of_gas()); + } + + + // Charging the exact amount that the user paid for should be + // possible. + #[test] + fn charge_exact_amount() { + let mut gas_meter = GasMeter::::with_limit(25, 10); + assert!(!gas_meter.charge(&(), SimpleToken(25)).is_out_of_gas()); } } diff --git a/srml/contracts/src/lib.rs b/srml/contracts/src/lib.rs index b9c8976cc04be0a97ffb33309b8acaa533fe9462..ff97f6e102379751f778812efc782e61a5030a18 100644 --- a/srml/contracts/src/lib.rs +++ b/srml/contracts/src/lib.rs @@ -68,7 +68,8 @@ //! The Contract module is a work in progress. The following examples show how this Contract module can be //! used to create and call contracts. //! -//! * [`pDSL`](https://github.com/Robbepop/pdsl) is a domain specific language that enables writing +//! * [`ink`](https://github.com/paritytech/ink) is +//! an [`eDSL`](https://wiki.haskell.org/Embedded_domain_specific_language) that enables writing //! WebAssembly based smart contracts in the Rust programming language. This is a work in progress. //! //! ## Related Modules @@ -90,22 +91,24 @@ mod tests; use crate::exec::ExecutionContext; use crate::account_db::{AccountDb, DirectAccountDb}; +pub use crate::gas::Gas; #[cfg(feature = "std")] use serde::{Serialize, Deserialize}; use substrate_primitives::crypto::UncheckedFrom; -use rstd::{prelude::*, marker::PhantomData, convert::TryFrom}; +use rstd::{prelude::*, marker::PhantomData}; use parity_codec::{Codec, Encode, Decode}; use runtime_io::blake2_256; use runtime_primitives::traits::{ - Hash, SimpleArithmetic, Bounded, StaticLookup, Zero, MaybeSerializeDebug, Member + Hash, StaticLookup, Zero, MaybeSerializeDebug, Member }; use srml_support::dispatch::{Result, Dispatchable}; use srml_support::{ - Parameter, StorageMap, StorageValue, decl_module, decl_event, decl_storage, storage::child + Parameter, StorageMap, StorageValue, decl_module, decl_event, decl_storage, storage::child, + parameter_types, }; -use srml_support::traits::{OnFreeBalanceZero, OnUnbalanced, Currency}; -use system::{ensure_signed, RawOrigin}; +use srml_support::traits::{OnFreeBalanceZero, OnUnbalanced, Currency, Get}; +use system::{ensure_signed, RawOrigin, ensure_root}; use substrate_primitives::storage::well_known_keys::CHILD_STORAGE_KEY_PREFIX; use timestamp; @@ -157,7 +160,7 @@ impl ContractInfo { } } - /// If contract is tombstone then return some alive info + /// If contract is tombstone then return some tombstone info pub fn get_tombstone(self) -> Option> { if let ContractInfo::Tombstone(tombstone) = self { Some(tombstone) @@ -256,7 +259,7 @@ where fn trie_id(account_id: &T::AccountId) -> TrieId { // Note that skipping a value due to error is not an issue here. // We only need uniqueness, not sequence. - let new_seed = >::mutate(|v| { + let new_seed = AccountCounter::mutate(|v| { *v = v.wrapping_add(1); *v }); @@ -278,6 +281,39 @@ pub type BalanceOf = <::Currency as Currency< pub type NegativeImbalanceOf = <::Currency as Currency<::AccountId>>::NegativeImbalance; +parameter_types! { + /// A resonable default value for [`Trait::SignedClaimedHandicap`]. + pub const DefaultSignedClaimHandicap: u32 = 2; + /// A resonable default value for [`Trait::TombstoneDeposit`]. + pub const DefaultTombstoneDeposit: u32 = 16; + /// A resonable default value for [`Trait::StorageSizeOffset`]. + pub const DefaultStorageSizeOffset: u32 = 8; + /// A resonable default value for [`Trait::RentByteFee`]. + pub const DefaultRentByteFee: u32 = 4; + /// A resonable default value for [`Trait::RentDepositOffset`]. + pub const DefaultRentDepositOffset: u32 = 1000; + /// A resonable default value for [`Trait::SurchargeReward`]. + pub const DefaultSurchargeReward: u32 = 150; + /// A resonable default value for [`Trait::TransferFee`]. + pub const DefaultTransferFee: u32 = 0; + /// A resonable default value for [`Trait::CreationFee`]. + pub const DefaultCreationFee: u32 = 0; + /// A resonable default value for [`Trait::TransactionBaseFee`]. + pub const DefaultTransactionBaseFee: u32 = 0; + /// A resonable default value for [`Trait::TransactionByteFee`]. + pub const DefaultTransactionByteFee: u32 = 0; + /// A resonable default value for [`Trait::ContractFee`]. + pub const DefaultContractFee: u32 = 21; + /// A resonable default value for [`Trait::CallBaseFee`]. + pub const DefaultCallBaseFee: u32 = 1000; + /// A resonable default value for [`Trait::CreateBaseFee`]. + pub const DefaultCreateBaseFee: u32 = 1000; + /// A resonable default value for [`Trait::MaxDepth`]. + pub const DefaultMaxDepth: u32 = 1024; + /// A resonable default value for [`Trait::BlockGasLimit`]. + pub const DefaultBlockGasLimit: u32 = 10_000_000; +} + pub trait Trait: timestamp::Trait { type Currency: Currency; @@ -287,9 +323,6 @@ pub trait Trait: timestamp::Trait { /// The overarching event type. type Event: From> + Into<::Event>; - type Gas: Parameter + Default + Codec + SimpleArithmetic + Bounded + Copy + - Into> + TryFrom>; - /// A function type to get the contract address given the creator. type DetermineContractAddress: ContractAddressFor, Self::AccountId>; @@ -299,11 +332,67 @@ pub trait Trait: timestamp::Trait { /// by the Executive module for regular dispatch. type ComputeDispatchFee: ComputeDispatchFee>; - /// trieid id generator + /// trie id generator type TrieIdGenerator: TrieIdGenerator; /// Handler for the unbalanced reduction when making a gas payment. type GasPayment: OnUnbalanced>; + + /// Number of block delay an extrinsic claim surcharge has. + /// + /// When claim surcharge is called by an extrinsic the rent is checked + /// for current_block - delay + type SignedClaimHandicap: Get; + + /// The minimum amount required to generate a tombstone. + type TombstoneDeposit: Get>; + + /// Size of a contract at the time of creation. This is a simple way to ensure + /// that empty contracts eventually gets deleted. + type StorageSizeOffset: Get; + + /// Price of a byte of storage per one block interval. Should be greater than 0. + type RentByteFee: Get>; + + /// The amount of funds a contract should deposit in order to offset + /// the cost of one byte. + /// + /// Let's suppose the deposit is 1,000 BU (balance units)/byte and the rent is 1 BU/byte/day, + /// then a contract with 1,000,000 BU that uses 1,000 bytes of storage would pay no rent. + /// But if the balance reduced to 500,000 BU and the storage stayed the same at 1,000, + /// then it would pay 500 BU/day. + type RentDepositOffset: Get>; + + /// Reward that is received by the party whose touch has led + /// to removal of a contract. + type SurchargeReward: Get>; + + /// The fee required to make a transfer. + type TransferFee: Get>; + + /// The fee required to create an account. + type CreationFee: Get>; + + /// The fee to be paid for making a transaction; the base. + type TransactionBaseFee: Get>; + + /// The fee to be paid for making a transaction; the per-byte portion. + type TransactionByteFee: Get>; + + /// The fee required to create a contract instance. + type ContractFee: Get>; + + /// The base fee charged for calling into a contract. + type CallBaseFee: Get; + + /// The base fee charged for creating a contract. + type CreateBaseFee: Get; + + /// The maximum nesting level of a call/create stack. + type MaxDepth: Get; + + /// The maximum amount of gas that could be expended per block. + type BlockGasLimit: Get; } /// Simple contract address determiner. @@ -335,8 +424,8 @@ pub struct DefaultDispatchFeeComputor(PhantomData); impl ComputeDispatchFee> for DefaultDispatchFeeComputor { fn compute_dispatch_fee(call: &T::Call) -> BalanceOf { let encoded_len = call.using_encoded(|encoded| encoded.len() as u32); - let base_fee = >::transaction_base_fee(); - let byte_fee = >::transaction_byte_fee(); + let base_fee = T::TransactionBaseFee::get(); + let byte_fee = T::TransactionByteFee::get(); base_fee + byte_fee * encoded_len.into() } } @@ -344,18 +433,80 @@ impl ComputeDispatchFee> for DefaultDispatchFeeC decl_module! { /// Contracts module. pub struct Module for enum Call where origin: ::Origin { + /// Number of block delay an extrinsic claim surcharge has. + /// + /// When claim surcharge is called by an extrinsic the rent is checked + /// for current_block - delay + const SignedClaimHandicap: T::BlockNumber = T::SignedClaimHandicap::get(); + + /// The minimum amount required to generate a tombstone. + const TombstoneDeposit: BalanceOf = T::TombstoneDeposit::get(); + + /// Size of a contract at the time of creation. This is a simple way to ensure + /// that empty contracts eventually gets deleted. + const StorageSizeOffset: u32 = T::StorageSizeOffset::get(); + + /// Price of a byte of storage per one block interval. Should be greater than 0. + const RentByteFee: BalanceOf = T::RentByteFee::get(); + + /// The amount of funds a contract should deposit in order to offset + /// the cost of one byte. + /// + /// Let's suppose the deposit is 1,000 BU (balance units)/byte and the rent is 1 BU/byte/day, + /// then a contract with 1,000,000 BU that uses 1,000 bytes of storage would pay no rent. + /// But if the balance reduced to 500,000 BU and the storage stayed the same at 1,000, + /// then it would pay 500 BU/day. + const RentDepositOffset: BalanceOf = T::RentDepositOffset::get(); + + /// Reward that is received by the party whose touch has led + /// to removal of a contract. + const SurchargeReward: BalanceOf = T::SurchargeReward::get(); + + /// The fee required to make a transfer. + const TransferFee: BalanceOf = T::TransferFee::get(); + + /// The fee required to create an account. + const CreationFee: BalanceOf = T::CreationFee::get(); + + /// The fee to be paid for making a transaction; the base. + const TransactionBaseFee: BalanceOf = T::TransactionBaseFee::get(); + + /// The fee to be paid for making a transaction; the per-byte portion. + const TransactionByteFee: BalanceOf = T::TransactionByteFee::get(); + + /// The fee required to create a contract instance. A reasonable default value + /// is 21. + const ContractFee: BalanceOf = T::ContractFee::get(); + + /// The base fee charged for calling into a contract. A reasonable default + /// value is 135. + const CallBaseFee: Gas = T::CallBaseFee::get(); + + /// The base fee charged for creating a contract. A reasonable default value + /// is 175. + const CreateBaseFee: Gas = T::CreateBaseFee::get(); + + /// The maximum nesting level of a call/create stack. A reasonable default + /// value is 100. + const MaxDepth: u32 = T::MaxDepth::get(); + + /// The maximum amount of gas that could be expended per block. A reasonable + /// default value is 10_000_000. + const BlockGasLimit: Gas = T::BlockGasLimit::get(); + fn deposit_event() = default; /// Updates the schedule for metering contracts. /// /// The schedule must have a greater version than the stored schedule. - pub fn update_schedule(schedule: Schedule) -> Result { + pub fn update_schedule(origin, schedule: Schedule) -> Result { + ensure_root(origin)?; if >::current_schedule().version >= schedule.version { return Err("new schedule must have a greater version than current"); } Self::deposit_event(RawEvent::ScheduleUpdated(schedule.version)); - >::put(schedule); + CurrentSchedule::put(schedule); Ok(()) } @@ -364,7 +515,7 @@ decl_module! { /// You can instantiate contracts only with stored code. pub fn put_code( origin, - #[compact] gas_limit: T::Gas, + #[compact] gas_limit: Gas, code: Vec ) -> Result { let origin = ensure_signed(origin)?; @@ -393,7 +544,7 @@ decl_module! { origin, dest: ::Source, #[compact] value: BalanceOf, - #[compact] gas_limit: T::Gas, + #[compact] gas_limit: Gas, data: Vec ) -> Result { let origin = ensure_signed(origin)?; @@ -453,7 +604,7 @@ decl_module! { pub fn create( origin, #[compact] endowment: BalanceOf, - #[compact] gas_limit: T::Gas, + #[compact] gas_limit: Gas, code_hash: CodeHash, data: Vec ) -> Result { @@ -521,14 +672,14 @@ decl_module! { // adding a handicap: for signed extrinsics we use a slightly older block number // for the eviction check. This can be viewed as if we pushed regular users back in past. let handicap = if signed { - >::signed_claim_handicap() + T::SignedClaimHandicap::get() } else { Zero::zero() }; // If poking the contract has lead to eviction of the contract, give out the rewards. if rent::try_evict::(&dest, handicap) == rent::RentOutcome::Evicted { - T::Currency::deposit_into_existing(rewarded, Self::surcharge_reward())?; + T::Currency::deposit_into_existing(rewarded, T::SurchargeReward::get())?; } } @@ -611,7 +762,7 @@ decl_module! { } fn on_finalize() { - >::kill(); + GasSpent::kill(); } } } @@ -646,53 +797,10 @@ decl_event! { decl_storage! { trait Store for Module as Contract { - /// Number of block delay an extrinsic claim surcharge has. - /// - /// When claim surchage is called by an extrinsic the rent is checked - /// for current_block - delay - SignedClaimHandicap get(signed_claim_handicap) config(): T::BlockNumber; - /// The minimum amount required to generate a tombstone. - TombstoneDeposit get(tombstone_deposit) config(): BalanceOf; - /// Size of a contract at the time of creation. This is a simple way to ensure - /// that empty contracts eventually gets deleted. - StorageSizeOffset get(storage_size_offset) config(): u32; - /// Price of a byte of storage per one block interval. Should be greater than 0. - RentByteFee get(rent_byte_price) config(): BalanceOf; - /// The amount of funds a contract should deposit in order to offset - /// the cost of one byte. - /// - /// Let's suppose the deposit is 1,000 BU (balance units)/byte and the rent is 1 BU/byte/day, - /// then a contract with 1,000,000 BU that uses 1,000 bytes of storage would pay no rent. - /// But if the balance reduced to 500,000 BU and the storage stayed the same at 1,000, - /// then it would pay 500 BU/day. - RentDepositOffset get(rent_deposit_offset) config(): BalanceOf; - /// Reward that is received by the party whose touch has led - /// to removal of a contract. - SurchargeReward get(surcharge_reward) config(): BalanceOf; - /// The fee required to make a transfer. - TransferFee get(transfer_fee) config(): BalanceOf; - /// The fee required to create an account. - CreationFee get(creation_fee) config(): BalanceOf; - /// The fee to be paid for making a transaction; the base. - TransactionBaseFee get(transaction_base_fee) config(): BalanceOf; - /// The fee to be paid for making a transaction; the per-byte portion. - TransactionByteFee get(transaction_byte_fee) config(): BalanceOf; - /// The fee required to create a contract instance. - ContractFee get(contract_fee) config(): BalanceOf = 21.into(); - /// The base fee charged for calling into a contract. - CallBaseFee get(call_base_fee) config(): T::Gas = 135.into(); - /// The base fee charged for creating a contract. - CreateBaseFee get(create_base_fee) config(): T::Gas = 175.into(); - /// The price of one unit of gas. - GasPrice get(gas_price) config(): BalanceOf = 1.into(); - /// The maximum nesting level of a call/create stack. - MaxDepth get(max_depth) config(): u32 = 100; - /// The maximum amount of gas that could be expended per block. - BlockGasLimit get(block_gas_limit) config(): T::Gas = 10_000_000.into(); /// Gas spent so far in this block. - GasSpent get(gas_spent): T::Gas; + GasSpent get(gas_spent): Gas; /// Current cost schedule for contracts. - CurrentSchedule get(current_schedule) config(): Schedule = Schedule::default(); + CurrentSchedule get(current_schedule) config(): Schedule = Schedule::default(); /// A mapping from an original code hash to the original code, untouched by instrumentation. pub PristineCode: map CodeHash => Option>; /// A mapping between an original code hash and instrumented wasm code, ready for execution. @@ -701,6 +809,8 @@ decl_storage! { pub AccountCounter: u64 = 0; /// The code associated with a given account. pub ContractInfoOf: map T::AccountId => Option>; + /// The price of one unit of gas. + GasPrice get(gas_price) config(): BalanceOf = 1.into(); } } @@ -718,14 +828,12 @@ impl OnFreeBalanceZero for Module { /// We assume that these values can't be changed in the /// course of transaction execution. pub struct Config { - pub schedule: Schedule, + pub schedule: Schedule, pub existential_deposit: BalanceOf, pub max_depth: u32, pub contract_account_instantiate_fee: BalanceOf, pub account_create_fee: BalanceOf, pub transfer_fee: BalanceOf, - pub call_base_fee: T::Gas, - pub instantiate_base_fee: T::Gas, } impl Config { @@ -733,12 +841,10 @@ impl Config { Config { schedule: >::current_schedule(), existential_deposit: T::Currency::minimum_balance(), - max_depth: >::max_depth(), - contract_account_instantiate_fee: >::contract_fee(), - account_create_fee: >::creation_fee(), - transfer_fee: >::transfer_fee(), - call_base_fee: >::call_base_fee(), - instantiate_base_fee: >::create_base_fee(), + max_depth: T::MaxDepth::get(), + contract_account_instantiate_fee: T::ContractFee::get(), + account_create_fee: T::CreationFee::get(), + transfer_fee: T::TransferFee::get(), } } } @@ -746,7 +852,7 @@ impl Config { /// Definition of the cost schedule and other parameterizations for wasm vm. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[derive(Clone, Encode, Decode, PartialEq, Eq)] -pub struct Schedule { +pub struct Schedule { /// Version of the schedule. pub version: u32, @@ -771,6 +877,12 @@ pub struct Schedule { /// Gas cost to deposit an event; the base. pub event_base_cost: Gas, + /// Base gas cost to call into a contract. + pub call_base_cost: Gas, + + /// Base gas cost to instantiate a contract. + pub instantiate_base_cost: Gas, + /// Gas cost per one byte read from the sandbox memory. pub sandbox_data_read_cost: Gas, @@ -789,6 +901,9 @@ pub struct Schedule { /// Maximum number of memory pages allowed for a contract. pub max_memory_pages: u32, + /// Maximum allowed size of a declared table. + pub max_table_size: u32, + /// Whether the `ext_println` function is allowed to be used contracts. /// MUST only be enabled for `dev` chains, NOT for production chains pub enable_println: bool, @@ -797,22 +912,25 @@ pub struct Schedule { pub max_subject_len: u32, } -impl> Default for Schedule { - fn default() -> Schedule { +impl Default for Schedule { + fn default() -> Schedule { Schedule { version: 0, - put_code_per_byte_cost: 1.into(), - grow_mem_cost: 1.into(), - regular_op_cost: 1.into(), - return_data_per_byte_cost: 1.into(), - event_data_per_byte_cost: 1.into(), - event_per_topic_cost: 1.into(), - event_base_cost: 1.into(), - sandbox_data_read_cost: 1.into(), - sandbox_data_write_cost: 1.into(), + put_code_per_byte_cost: 1, + grow_mem_cost: 1, + regular_op_cost: 1, + return_data_per_byte_cost: 1, + event_data_per_byte_cost: 1, + event_per_topic_cost: 1, + event_base_cost: 1, + call_base_cost: 135, + instantiate_base_cost: 175, + sandbox_data_read_cost: 1, + sandbox_data_write_cost: 1, max_event_topics: 4, max_stack_height: 64 * 1024, max_memory_pages: 16, + max_table_size: 16 * 1024, enable_println: false, max_subject_len: 32, } diff --git a/srml/contracts/src/rent.rs b/srml/contracts/src/rent.rs index 3baf043b90d37d16ceefd29e141f5c727a5d3eb0..96f8516a5f189c2bba8b23a60b9d350d99e7ae15 100644 --- a/srml/contracts/src/rent.rs +++ b/srml/contracts/src/rent.rs @@ -14,10 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use crate::{BalanceOf, ContractInfo, ContractInfoOf, Module, TombstoneContractInfo, Trait}; +use crate::{BalanceOf, ContractInfo, ContractInfoOf, TombstoneContractInfo, Trait, AliveContractInfo}; use runtime_primitives::traits::{Bounded, CheckedDiv, CheckedMul, Saturating, Zero, SaturatedConversion}; -use srml_support::traits::{Currency, ExistenceRequirement, Imbalance, WithdrawReason}; +use srml_support::traits::{Currency, ExistenceRequirement, Get, WithdrawReason}; use srml_support::StorageMap; #[derive(PartialEq, Eq, Copy, Clone)] @@ -50,9 +50,10 @@ fn try_evict_or_and_pay_rent( account: &T::AccountId, handicap: T::BlockNumber, pay_rent: bool, -) -> RentOutcome { - let contract = match >::get(account) { - None | Some(ContractInfo::Tombstone(_)) => return RentOutcome::Exempted, +) -> (RentOutcome, Option>) { + let contract_info = >::get(account); + let contract = match contract_info { + None | Some(ContractInfo::Tombstone(_)) => return (RentOutcome::Exempted, contract_info), Some(ContractInfo::Alive(contract)) => contract, }; @@ -65,7 +66,7 @@ fn try_evict_or_and_pay_rent( let n = effective_block_number.saturating_sub(contract.deduct_block); if n.is_zero() { // Rent has already been paid - return RentOutcome::Exempted; + return (RentOutcome::Exempted, Some(ContractInfo::Alive(contract))); } n }; @@ -75,34 +76,46 @@ fn try_evict_or_and_pay_rent( // An amount of funds to charge per block for storage taken up by the contract. let fee_per_block = { let free_storage = balance - .checked_div(&>::rent_deposit_offset()) + .checked_div(&T::RentDepositOffset::get()) .unwrap_or_else(Zero::zero); let effective_storage_size = >::from(contract.storage_size).saturating_sub(free_storage); effective_storage_size - .checked_mul(&>::rent_byte_price()) + .checked_mul(&T::RentByteFee::get()) .unwrap_or(>::max_value()) }; if fee_per_block.is_zero() { // The rent deposit offset reduced the fee to 0. This means that the contract // gets the rent for free. - return RentOutcome::Exempted; + return (RentOutcome::Exempted, Some(ContractInfo::Alive(contract))); } // The minimal amount of funds required for a contract not to be evicted. - let subsistence_threshold = T::Currency::minimum_balance() + >::tombstone_deposit(); + let subsistence_threshold = T::Currency::minimum_balance() + T::TombstoneDeposit::get(); + + if balance < subsistence_threshold { + // The contract cannot afford to leave a tombstone, so remove the contract info altogether. + >::remove(account); + runtime_io::kill_child_storage(&contract.trie_id); + return (RentOutcome::Evicted, None); + } let dues = fee_per_block .checked_mul(&blocks_passed.saturated_into::().into()) .unwrap_or(>::max_value()); - - let dues_limited = dues.min(contract.rent_allowance); - let rent_allowance_exceeded = dues > contract.rent_allowance; - let is_below_subsistence = balance < subsistence_threshold; - let go_below_subsistence = balance.saturating_sub(dues_limited) < subsistence_threshold; + let rent_budget = contract.rent_allowance.min(balance - subsistence_threshold); + let insufficient_rent = rent_budget < dues; + + // If the rent payment cannot be withdrawn due to locks on the account balance, then evict the + // account. + // + // NOTE: This seems problematic because it provides a way to tombstone an account while + // avoiding the last rent payment. In effect, someone could retroactively set rent_allowance + // for their contract to 0. + let dues_limited = dues.min(rent_budget); let can_withdraw_rent = T::Currency::ensure_can_withdraw( account, dues_limited, @@ -111,75 +124,60 @@ fn try_evict_or_and_pay_rent( ) .is_ok(); - if !rent_allowance_exceeded && can_withdraw_rent && !go_below_subsistence { - // Collect dues - - if pay_rent { - let imbalance = T::Currency::withdraw( - account, - dues, - WithdrawReason::Fee, - ExistenceRequirement::KeepAlive, - ) - .expect( - "Withdraw has been checked above; - go_below_subsistence is false and subsistence > existencial_deposit; - qed", - ); - - >::mutate(account, |contract| { - let contract = contract - .as_mut() - .and_then(|c| c.as_alive_mut()) - .expect("Dead or inexistent account has been exempt above; qed"); - - contract.rent_allowance -= imbalance.peek(); // rent_allowance is not exceeded - contract.deduct_block = current_block_number; - }) - } + if can_withdraw_rent && (insufficient_rent || pay_rent) { + // Collect dues. + let _ = T::Currency::withdraw( + account, + dues_limited, + WithdrawReason::Fee, + ExistenceRequirement::KeepAlive, + ) + .expect( + "Withdraw has been checked above; + dues_limited < rent_budget < balance - subsistence < balance - existential_deposit; + qed", + ); + } - RentOutcome::Ok - } else { - // Evict - - if can_withdraw_rent && !go_below_subsistence { - T::Currency::withdraw( - account, - dues, - WithdrawReason::Fee, - ExistenceRequirement::KeepAlive, - ) - .expect("Can withdraw and don't go below subsistence"); - } else if !is_below_subsistence { - T::Currency::make_free_balance_be(account, subsistence_threshold); - } else { - T::Currency::make_free_balance_be(account, >::zero()); - } + if insufficient_rent || !can_withdraw_rent { + // The contract cannot afford the rent payment and has a balance above the subsistence + // threshold, so it leaves a tombstone. - if !is_below_subsistence { - // The contract has funds above subsistence deposit and that means it can afford to - // leave tombstone. + // Note: this operation is heavy. + let child_storage_root = runtime_io::child_storage_root(&contract.trie_id); - // Note: this operation is heavy. - let child_storage_root = runtime_io::child_storage_root(&contract.trie_id); + let tombstone = >::new( + &child_storage_root[..], + contract.code_hash, + ); + let tombstone_info = ContractInfo::Tombstone(tombstone); + >::insert(account, &tombstone_info); - let tombstone = >::new( - &child_storage_root[..], - contract.code_hash, - ); - >::insert(account, ContractInfo::Tombstone(tombstone)); - runtime_io::kill_child_storage(&contract.trie_id); - } + runtime_io::kill_child_storage(&contract.trie_id); + + return (RentOutcome::Evicted, Some(tombstone_info)); + } - RentOutcome::Evicted + if pay_rent { + let contract_info = ContractInfo::Alive(AliveContractInfo:: { + rent_allowance: contract.rent_allowance - dues, // rent_allowance is not exceeded + deduct_block: current_block_number, + ..contract + }); + + >::insert(account, &contract_info); + + return (RentOutcome::Ok, Some(contract_info)); } + + (RentOutcome::Ok, Some(ContractInfo::Alive(contract))) } /// Make account paying the rent for the current block number /// /// NOTE: This function acts eagerly. -pub fn pay_rent(account: &T::AccountId) { - let _ = try_evict_or_and_pay_rent::(account, Zero::zero(), true); +pub fn pay_rent(account: &T::AccountId) -> Option> { + try_evict_or_and_pay_rent::(account, Zero::zero(), true).1 } /// Evict the account if it should be evicted at the given block number. @@ -190,5 +188,5 @@ pub fn pay_rent(account: &T::AccountId) { /// /// NOTE: This function acts eagerly. pub fn try_evict(account: &T::AccountId, handicap: T::BlockNumber) -> RentOutcome { - try_evict_or_and_pay_rent::(account, handicap, false) + try_evict_or_and_pay_rent::(account, handicap, false).0 } diff --git a/srml/contracts/src/tests.rs b/srml/contracts/src/tests.rs index 61a81a4eb683b89cd00d8a78f22fd75ef0e2346f..bd7ed1f4ff8455f604b26afd09610deced60b4d5 100644 --- a/srml/contracts/src/tests.rs +++ b/srml/contracts/src/tests.rs @@ -33,9 +33,10 @@ use runtime_primitives::testing::{Digest, DigestItem, Header, UintAuthorityId, H use runtime_primitives::traits::{BlakeTwo256, IdentityLookup}; use runtime_primitives::BuildStorage; use srml_support::{ - assert_ok, impl_outer_dispatch, impl_outer_event, impl_outer_origin, storage::child, - traits::Currency, StorageMap, StorageValue + assert_ok, assert_err, impl_outer_dispatch, impl_outer_event, impl_outer_origin, parameter_types, + storage::child, StorageMap, StorageValue, traits::{Currency, Get}, }; +use std::cell::RefCell; use std::sync::atomic::{AtomicUsize, Ordering}; use substrate_primitives::storage::well_known_keys; use substrate_primitives::Blake2Hasher; @@ -64,8 +65,38 @@ impl_outer_dispatch! { } } +thread_local! { + static EXISTENTIAL_DEPOSIT: RefCell = RefCell::new(0); + static TRANSFER_FEE: RefCell = RefCell::new(0); + static CREATION_FEE: RefCell = RefCell::new(0); + static BLOCK_GAS_LIMIT: RefCell = RefCell::new(0); +} + +pub struct ExistentialDeposit; +impl Get for ExistentialDeposit { + fn get() -> u64 { EXISTENTIAL_DEPOSIT.with(|v| *v.borrow()) } +} + +pub struct TransferFee; +impl Get for TransferFee { + fn get() -> u64 { TRANSFER_FEE.with(|v| *v.borrow()) } +} + +pub struct CreationFee; +impl Get for CreationFee { + fn get() -> u64 { CREATION_FEE.with(|v| *v.borrow()) } +} + +pub struct BlockGasLimit; +impl Get for BlockGasLimit { + fn get() -> u64 { BLOCK_GAS_LIMIT.with(|v| *v.borrow()) } +} + #[derive(Clone, Eq, PartialEq, Debug)] pub struct Test; +parameter_types! { + pub const BlockHashCount: u64 = 250; +} impl system::Trait for Test { type Origin = Origin; type Index = u64; @@ -76,6 +107,11 @@ impl system::Trait for Test { type Lookup = IdentityLookup; type Header = Header; type Event = MetaEvent; + type BlockHashCount = BlockHashCount; +} +parameter_types! { + pub const BalancesTransactionBaseFee: u64 = 0; + pub const BalancesTransactionByteFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; @@ -85,20 +121,57 @@ impl balances::Trait for Test { type TransactionPayment = (); type DustRemoval = (); type TransferPayment = (); + type ExistentialDeposit = ExistentialDeposit; + type TransferFee = TransferFee; + type CreationFee = CreationFee; + type TransactionBaseFee = BalancesTransactionBaseFee; + type TransactionByteFee = BalancesTransactionByteFee; +} +parameter_types! { + pub const MinimumPeriod: u64 = 1; } impl timestamp::Trait for Test { type Moment = u64; type OnTimestampSet = (); + type MinimumPeriod = MinimumPeriod; +} +parameter_types! { + pub const SignedClaimHandicap: u64 = 2; + pub const TombstoneDeposit: u64 = 16; + pub const StorageSizeOffset: u32 = 8; + pub const RentByteFee: u64 = 4; + pub const RentDepositOffset: u64 = 10_000; + pub const SurchargeReward: u64 = 150; + pub const TransactionBaseFee: u64 = 2; + pub const TransactionByteFee: u64 = 6; + pub const ContractFee: u64 = 21; + pub const CallBaseFee: u64 = 135; + pub const CreateBaseFee: u64 = 175; + pub const MaxDepth: u32 = 100; } impl Trait for Test { type Currency = Balances; type Call = Call; - type Gas = u64; type DetermineContractAddress = DummyContractAddressFor; type Event = MetaEvent; type ComputeDispatchFee = DummyComputeDispatchFee; type TrieIdGenerator = DummyTrieIdGenerator; type GasPayment = (); + type SignedClaimHandicap = SignedClaimHandicap; + type TombstoneDeposit = TombstoneDeposit; + type StorageSizeOffset = StorageSizeOffset; + type RentByteFee = RentByteFee; + type RentDepositOffset = RentDepositOffset; + type SurchargeReward = SurchargeReward; + type TransferFee = TransferFee; + type CreationFee = CreationFee; + type TransactionBaseFee = TransactionBaseFee; + type TransactionByteFee = TransactionByteFee; + type ContractFee = ContractFee; + type CallBaseFee = CallBaseFee; + type CreateBaseFee = CreateBaseFee; + type MaxDepth = MaxDepth; + type BlockGasLimit = BlockGasLimit; } type Balances = balances::Module; @@ -117,7 +190,7 @@ impl TrieIdGenerator for DummyTrieIdGenerator { fn trie_id(account_id: &u64) -> TrieId { use substrate_primitives::storage::well_known_keys; - let new_seed = >::mutate(|v| { + let new_seed = super::AccountCounter::mutate(|v| { *v = v.wrapping_add(1); *v }); @@ -183,61 +256,38 @@ impl ExtBuilder { self.creation_fee = creation_fee; self } + pub fn set_associated_consts(&self) { + EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit); + TRANSFER_FEE.with(|v| *v.borrow_mut() = self.transfer_fee); + CREATION_FEE.with(|v| *v.borrow_mut() = self.creation_fee); + BLOCK_GAS_LIMIT.with(|v| *v.borrow_mut() = self.block_gas_limit); + } pub fn build(self) -> runtime_io::TestExternalities { - let mut t = system::GenesisConfig::::default() - .build_storage() - .unwrap() - .0; - t.extend( - balances::GenesisConfig:: { - transaction_base_fee: 0, - transaction_byte_fee: 0, - balances: vec![], - existential_deposit: self.existential_deposit, - transfer_fee: self.transfer_fee, - creation_fee: self.creation_fee, - vesting: vec![], - } - .build_storage() - .unwrap() - .0, - ); - t.extend( - GenesisConfig:: { - signed_claim_handicap: 2, - rent_byte_price: 4, - rent_deposit_offset: 10_000, - storage_size_offset: 8, - surcharge_reward: 150, - tombstone_deposit: 16, - transaction_base_fee: 2, - transaction_byte_fee: 6, - transfer_fee: self.transfer_fee, - creation_fee: self.creation_fee, - contract_fee: 21, - call_base_fee: 135, - create_base_fee: 175, - gas_price: self.gas_price, - max_depth: 100, - block_gas_limit: self.block_gas_limit, - current_schedule: Default::default(), - } - .build_storage() - .unwrap() - .0, - ); - runtime_io::TestExternalities::new(t) + self.set_associated_consts(); + let mut t = system::GenesisConfig::default().build_storage::().unwrap(); + balances::GenesisConfig:: { + balances: vec![], + vesting: vec![], + }.assimilate_storage(&mut t.0, &mut t.1).unwrap(); + GenesisConfig:: { + current_schedule: Default::default(), + gas_price: self.gas_price, + }.assimilate_storage(&mut t.0, &mut t.1).unwrap(); + runtime_io::TestExternalities::new_with_children(t) } } +// Perform a simple transfer to a non-existent account supplying way more gas than needed. +// Then we check that the all unused gas is refunded. #[test] fn refunds_unused_gas() { - with_externalities(&mut ExtBuilder::default().build(), || { - Balances::deposit_creating(&0, 100_000_000); + with_externalities(&mut ExtBuilder::default().gas_price(2).build(), || { + Balances::deposit_creating(&ALICE, 100_000_000); - assert_ok!(Contract::call(Origin::signed(0), 1, 0, 100_000, Vec::new())); + assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, Vec::new())); - assert_eq!(Balances::free_balance(&0), 100_000_000 - (2 * 135)); + // 2 * 135 - gas price multiplied by the call base fee. + assert_eq!(Balances::free_balance(&ALICE), 100_000_000 - (2 * 135)); }); } @@ -256,7 +306,7 @@ fn account_removal_removes_storage() { Balances::deposit_creating(&1, 110); ContractInfoOf::::insert(1, &ContractInfo::Alive(RawAliveContractInfo { trie_id: trie_id1.clone(), - storage_size: Contract::storage_size_offset(), + storage_size: ::StorageSizeOffset::get(), deduct_block: System::block_number(), code_hash: H256::repeat_byte(1), rent_allowance: 40, @@ -271,7 +321,7 @@ fn account_removal_removes_storage() { Balances::deposit_creating(&2, 110); ContractInfoOf::::insert(2, &ContractInfo::Alive(RawAliveContractInfo { trie_id: trie_id2.clone(), - storage_size: Contract::storage_size_offset(), + storage_size: ::StorageSizeOffset::get(), deduct_block: System::block_number(), code_hash: H256::repeat_byte(2), rent_allowance: 40, @@ -522,13 +572,117 @@ fn dispatch_call() { ); } +const CODE_DISPATCH_CALL_THEN_TRAP: &str = r#" +(module + (import "env" "ext_dispatch_call" (func $ext_dispatch_call (param i32 i32))) + (import "env" "memory" (memory 1 1)) + + (func (export "call") + (call $ext_dispatch_call + (i32.const 8) ;; Pointer to the start of encoded call buffer + (i32.const 11) ;; Length of the buffer + ) + (unreachable) ;; trap so that the top level transaction fails + ) + (func (export "deploy")) + + (data (i32.const 8) "\00\00\03\00\00\00\00\00\00\00\C8") +) +"#; +const HASH_DISPATCH_CALL_THEN_TRAP: [u8; 32] = hex!("55fe5c142dfe2519ca76c7c9b9f05012bd2624b7dcc128d2ce5a7af9d2da1846"); + +#[test] +fn dispatch_call_not_dispatched_after_top_level_transaction_failure() { + // This test can fail due to the encoding changes. In case it becomes too annoying + // let's rewrite so as we use this module controlled call or we serialize it in runtime. + let encoded = Encode::encode(&Call::Balances(balances::Call::transfer(CHARLIE, 50))); + assert_eq!(&encoded[..], &hex!("00000300000000000000C8")[..]); + + let wasm = wabt::wat2wasm(CODE_DISPATCH_CALL_THEN_TRAP).unwrap(); + + with_externalities( + &mut ExtBuilder::default().existential_deposit(50).build(), + || { + Balances::deposit_creating(&ALICE, 1_000_000); + + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); + + // Let's keep this assert even though it's redundant. If you ever need to update the + // wasm source this test will fail and will show you the actual hash. + assert_eq!(System::events(), vec![ + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::balances(balances::RawEvent::NewAccount(1, 1_000_000)), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::CodeStored(HASH_DISPATCH_CALL_THEN_TRAP.into())), + topics: vec![], + }, + ]); + + assert_ok!(Contract::create( + Origin::signed(ALICE), + 100, + 100_000, + HASH_DISPATCH_CALL_THEN_TRAP.into(), + vec![], + )); + + // Call the newly created contract. The contract is expected to dispatch a call + // and then trap. + assert_err!( + Contract::call( + Origin::signed(ALICE), + BOB, // newly created account + 0, + 100_000, + vec![], + ), + "during execution" + ); + assert_eq!(System::events(), vec![ + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::balances(balances::RawEvent::NewAccount(1, 1_000_000)), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::CodeStored(HASH_DISPATCH_CALL_THEN_TRAP.into())), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::balances( + balances::RawEvent::NewAccount(BOB, 100) + ), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::Transfer(ALICE, BOB, 100)), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::Instantiated(ALICE, BOB)), + topics: vec![], + }, + // ABSENCE of events which would be caused by dispatched Balances::transfer call + ]); + }, + ); +} + const CODE_SET_RENT: &str = r#" (module (import "env" "ext_dispatch_call" (func $ext_dispatch_call (param i32 i32))) (import "env" "ext_set_storage" (func $ext_set_storage (param i32 i32 i32 i32))) (import "env" "ext_set_rent_allowance" (func $ext_set_rent_allowance (param i32 i32))) - (import "env" "ext_input_size" (func $ext_input_size (result i32))) - (import "env" "ext_input_copy" (func $ext_input_copy (param i32 i32 i32))) + (import "env" "ext_scratch_size" (func $ext_scratch_size (result i32))) + (import "env" "ext_scratch_copy" (func $ext_scratch_copy (param i32 i32 i32))) (import "env" "memory" (memory 1 1)) ;; insert a value of 4 bytes into storage @@ -575,7 +729,7 @@ const CODE_SET_RENT: &str = r#" (func (export "call") (local $input_size i32) (set_local $input_size - (call $ext_input_size) + (call $ext_scratch_size) ) (block $IF_ELSE (block $IF_2 @@ -602,16 +756,16 @@ const CODE_SET_RENT: &str = r#" ;; Set call set_rent_allowance with input (func (export "deploy") (local $input_size i32) + (set_local $input_size + (call $ext_scratch_size) + ) (call $ext_set_storage (i32.const 0) (i32.const 1) (i32.const 0) (i32.const 4) ) - (set_local $input_size - (call $ext_input_size) - ) - (call $ext_input_copy + (call $ext_scratch_copy (i32.const 0) (i32.const 0) (get_local $input_size) @@ -631,7 +785,7 @@ const CODE_SET_RENT: &str = r#" "#; // Use test_hash_and_code test to get the actual hash if the code changed. -const HASH_SET_RENT: [u8; 32] = hex!("21d6b1d59aa6038fcad632488e9026893a1bbb48581774c771b8f24320697f05"); +const HASH_SET_RENT: [u8; 32] = hex!("69aedfb4f6c1c398e97f8a5204de0f95ad5e7dc3540960beab11a86c569fbfcf"); /// Input data for each call in set_rent code mod call { @@ -641,7 +795,7 @@ mod call { pub fn null() -> Vec { vec![0, 0, 0] } } -/// Test correspondance of set_rent code and its hash. +/// Test correspondence of set_rent code and its hash. /// Also test that encoded extrinsic in code correspond to the correct transfer #[test] fn test_set_rent_code_and_hash() { @@ -694,15 +848,15 @@ fn storage_size() { ::Balance::from(1_000u32).encode() // rent allowance )); let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); - assert_eq!(bob_contract.storage_size, Contract::storage_size_offset() + 4); + assert_eq!(bob_contract.storage_size, ::StorageSizeOffset::get() + 4); assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::set_storage_4_byte())); let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); - assert_eq!(bob_contract.storage_size, Contract::storage_size_offset() + 4 + 4); + assert_eq!(bob_contract.storage_size, ::StorageSizeOffset::get() + 4 + 4); assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::remove_storage_4_byte())); let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); - assert_eq!(bob_contract.storage_size, Contract::storage_size_offset() + 4); + assert_eq!(bob_contract.storage_size, ::StorageSizeOffset::get() + 4); } ); } @@ -771,7 +925,11 @@ fn deduct_blocks() { #[test] fn call_contract_removals() { - removals(|| Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null()).is_ok()); + removals(|| { + // Call on already-removed account might fail, and this is fine. + Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null()); + true + }); } #[test] @@ -853,9 +1011,12 @@ fn removals(trigger_call: impl Fn() -> bool) { ::Balance::from(1_000u32).encode() // rent allowance )); + let subsistence_threshold = 50 /*existential_deposit*/ + 16 /*tombstone_deposit*/; + // Trigger rent must have no effect assert!(trigger_call()); assert_eq!(ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 1_000); + assert_eq!(Balances::free_balance(&BOB), 100); // Advance blocks System::initialize(&10, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); @@ -863,6 +1024,7 @@ fn removals(trigger_call: impl Fn() -> bool) { // Trigger rent through call assert!(trigger_call()); assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); + assert_eq!(Balances::free_balance(&BOB), subsistence_threshold); // Advance blocks System::initialize(&20, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); @@ -870,6 +1032,7 @@ fn removals(trigger_call: impl Fn() -> bool) { // Trigger rent must have no effect assert!(trigger_call()); assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); + assert_eq!(Balances::free_balance(&BOB), subsistence_threshold); } ); @@ -890,6 +1053,7 @@ fn removals(trigger_call: impl Fn() -> bool) { // Trigger rent must have no effect assert!(trigger_call()); assert_eq!(ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 100); + assert_eq!(Balances::free_balance(&BOB), 1_000); // Advance blocks System::initialize(&10, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); @@ -897,6 +1061,8 @@ fn removals(trigger_call: impl Fn() -> bool) { // Trigger rent through call assert!(trigger_call()); assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); + // Balance should be initial balance - initial rent_allowance + assert_eq!(Balances::free_balance(&BOB), 900); // Advance blocks System::initialize(&20, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); @@ -904,6 +1070,7 @@ fn removals(trigger_call: impl Fn() -> bool) { // Trigger rent must have no effect assert!(trigger_call()); assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); + assert_eq!(Balances::free_balance(&BOB), 900); } ); @@ -924,10 +1091,12 @@ fn removals(trigger_call: impl Fn() -> bool) { // Trigger rent must have no effect assert!(trigger_call()); assert_eq!(ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 1_000); + assert_eq!(Balances::free_balance(&BOB), 50 + Balances::minimum_balance()); // Transfer funds assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::transfer())); assert_eq!(ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 1_000); + assert_eq!(Balances::free_balance(&BOB), Balances::minimum_balance()); // Advance blocks System::initialize(&10, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); @@ -935,6 +1104,7 @@ fn removals(trigger_call: impl Fn() -> bool) { // Trigger rent through call assert!(trigger_call()); assert!(ContractInfoOf::::get(BOB).is_none()); + assert_eq!(Balances::free_balance(&BOB), Balances::minimum_balance()); // Advance blocks System::initialize(&20, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); @@ -942,10 +1112,50 @@ fn removals(trigger_call: impl Fn() -> bool) { // Trigger rent must have no effect assert!(trigger_call()); assert!(ContractInfoOf::::get(BOB).is_none()); + assert_eq!(Balances::free_balance(&BOB), Balances::minimum_balance()); } ); } +#[test] +fn call_removed_contract() { + let wasm = wabt::wat2wasm(CODE_SET_RENT).unwrap(); + + // Balance reached and superior to subsistence threshold + with_externalities( + &mut ExtBuilder::default().existential_deposit(50).build(), + || { + // Create + Balances::deposit_creating(&ALICE, 1_000_000); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm.clone())); + assert_ok!(Contract::create( + Origin::signed(ALICE), + 100, + 100_000, HASH_SET_RENT.into(), + ::Balance::from(1_000u32).encode() // rent allowance + )); + + // Calling contract should succeed. + assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null())); + + // Advance blocks + System::initialize(&10, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); + + // Calling contract should remove contract and fail. + assert_err!( + Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null()), + "contract has been evicted" + ); + + // Subsequent contract calls should also fail. + assert_err!( + Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null()), + "contract has been evicted" + ); + } + ) +} + const CODE_CHECK_DEFAULT_RENT_ALLOWANCE: &str = r#" (module (import "env" "ext_rent_allowance" (func $ext_rent_allowance)) @@ -1041,8 +1251,12 @@ const CODE_RESTORATION: &str = r#" (func (export "call") (call $ext_dispatch_call - (i32.const 200) ;; Pointer to the start of encoded call buffer - (i32.const 115) ;; Length of the buffer + ;; Pointer to the start of the encoded call buffer + (i32.const 200) + ;; The length of the encoded call buffer. + ;; + ;; NB: This is required to keep in sync with the values in `restoration`. + (i32.const 115) ) ) (func (export "deploy") @@ -1069,16 +1283,17 @@ const CODE_RESTORATION: &str = r#" ;; ACL (data (i32.const 100) "\01") - ;; Call - (data (i32.const 200) "\01\05\02\00\00\00\00\00\00\00\21\d6\b1\d5\9a\a6\03\8f\ca\d6\32\48\8e\90" - "\26\89\3a\1b\bb\48\58\17\74\c7\71\b8\f2\43\20\69\7f\05\32\00\00\00\00\00\00\00\08\01\00\00" - "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\01" - "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00" - "\00" + ;; Serialized version of `T::Call` that encodes a call to `restore_to` function. For more + ;; details check out the `ENCODED_CALL_LITERAL`. + (data (i32.const 200) + "\01\05\02\00\00\00\00\00\00\00\69\ae\df\b4\f6\c1\c3\98\e9\7f\8a\52\04\de\0f\95\ad\5e\7d\c3" + "\54\09\60\be\ab\11\a8\6c\56\9f\bf\cf\32\00\00\00\00\00\00\00\08\01\00\00\00\00\00\00\00\00" + "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\01\00\00\00\00\00\00" + "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00" ) ) "#; -const HASH_RESTORATION: [u8; 32] = hex!("b393bfa8de97b02f08ba1580b46100a80c9489a97c8d870691c9ff7236b29bc7"); +const HASH_RESTORATION: [u8; 32] = hex!("02988182efba70fe605031f5c55bfa59e47f72c0a4707f22b6b74fffbf7803dc"); #[test] fn restorations_dirty_storage_and_different_storage() { @@ -1116,12 +1331,25 @@ fn restoration(test_different_storage: bool, test_restore_to_with_dirty_storage: vec![acl_key, acl_key], )))); - let literal = "0105020000000000000021d6b1d59aa6038fcad632488e9026893a1bbb48581774c771b8f243206\ - 97f053200000000000000080100000000000000000000000000000000000000000000000000000000000000010\ - 0000000000000000000000000000000000000000000000000000000000000"; - - assert_eq!(encoded, literal); - assert_eq!(115, hex::decode(literal).unwrap().len()); + // `ENCODED_CALL_LITERAL` is encoded `T::Call` represented as a byte array. There is an exact + // same copy of this (modulo hex notation differences) in `CODE_RESTORATION`. + // + // When this assert is triggered make sure that you update the literals here and in + // `CODE_RESTORATION`. Hopefully, we switch to automatic injection of the code. + const ENCODED_CALL_LITERAL: &str = + "0105020000000000000069aedfb4f6c1c398e97f8a5204de0f95ad5e7dc3540960beab11a86c569fbfcf320000\ + 0000000000080100000000000000000000000000000000000000000000000000000000000000010000000000000\ + 0000000000000000000000000000000000000000000000000"; + assert_eq!( + encoded, + ENCODED_CALL_LITERAL, + "The literal was changed and requires updating here and in `CODE_RESTORATION`", + ); + assert_eq!( + hex::decode(ENCODED_CALL_LITERAL).unwrap().len(), + 115, + "The size of the literal was changed and requires updating in `CODE_RESTORATION`", + ); let restoration_wasm = wabt::wat2wasm(CODE_RESTORATION).unwrap(); let set_rent_wasm = wabt::wat2wasm(CODE_SET_RENT).unwrap(); @@ -1153,14 +1381,18 @@ fn restoration(test_different_storage: bool, test_restore_to_with_dirty_storage: }, ]); + // Create an account with address `BOB` with code `HASH_SET_RENT`. + // The input parameter sets the rent allowance to 0. assert_ok!(Contract::create( Origin::signed(ALICE), 30_000, - 100_000, HASH_SET_RENT.into(), + 100_000, + HASH_SET_RENT.into(), ::Balance::from(0u32).encode() )); - // Check creation + // Check if `BOB` was created successfully and that the rent allowance is + // set to 0. let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); assert_eq!(bob_contract.rent_allowance, 0); @@ -1172,36 +1404,52 @@ fn restoration(test_different_storage: bool, test_restore_to_with_dirty_storage: ); } - // Advance 4 blocks + // Advance 4 blocks, to the 5th. System::initialize(&5, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); - // Trigger rent through call - assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null())); + // Call `BOB`, which makes it pay rent. Since the rent allowance is set to 0 + // we expect that it will get removed leaving tombstone. + assert_err!( + Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null()), + "contract has been evicted" + ); assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); + /// Create another account with the address `DJANGO` with `CODE_RESTORATION`. + /// + /// Note that we can't use `ALICE` for creating `DJANGO` so we create yet another + /// account `CHARLIE` and create `DJANGO` with it. Balances::deposit_creating(&CHARLIE, 1_000_000); assert_ok!(Contract::create( Origin::signed(CHARLIE), 30_000, - 100_000, HASH_RESTORATION.into(), + 100_000, + HASH_RESTORATION.into(), ::Balance::from(0u32).encode() )); + // Before performing a call to `DJANGO` save its original trie id. let django_trie_id = ContractInfoOf::::get(DJANGO).unwrap() .get_alive().unwrap().trie_id; if !test_restore_to_with_dirty_storage { - // Advance 1 blocks + // Advance 1 block, to the 6th. System::initialize(&6, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); } + // Perform a call to `DJANGO`. This should either perform restoration successfully or + // fail depending on the test parameters. assert_ok!(Contract::call( Origin::signed(ALICE), - DJANGO, 0, 100_000, + DJANGO, + 0, + 100_000, vec![], )); if test_different_storage || test_restore_to_with_dirty_storage { + // Parametrization of the test imply restoration failure. Check that `DJANGO` aka + // restoration contract is still in place and also that `BOB` doesn't exist. assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); let django_contract = ContractInfoOf::::get(DJANGO).unwrap() .get_alive().unwrap(); @@ -1209,6 +1457,8 @@ fn restoration(test_different_storage: bool, test_restore_to_with_dirty_storage: assert_eq!(django_contract.trie_id, django_trie_id); assert_eq!(django_contract.deduct_block, System::block_number()); } else { + // Here we expect that the restoration is succeeded. Check that the restoration + // contract `DJANGO` ceased to exist and that `BOB` returned back. let bob_contract = ContractInfoOf::::get(BOB).unwrap() .get_alive().unwrap(); assert_eq!(bob_contract.rent_allowance, 50); diff --git a/srml/contracts/src/wasm/code_cache.rs b/srml/contracts/src/wasm/code_cache.rs index 30c02ef94200f4b89822c4787efdc0587db315aa..140878f28b8c7018a09722da9b5b0a04ea85daaf 100644 --- a/srml/contracts/src/wasm/code_cache.rs +++ b/srml/contracts/src/wasm/code_cache.rs @@ -26,11 +26,11 @@ //! this guarantees that every instrumented contract code in cache cannot have the version equal to the current one. //! Thus, before executing a contract it should be reinstrument with new schedule. -use crate::gas::{GasMeter, Token}; +use crate::gas::{Gas, GasMeter, Token}; use crate::wasm::{prepare, runtime::Env, PrefabWasmModule}; use crate::{CodeHash, CodeStorage, PristineCode, Schedule, Trait}; use rstd::prelude::*; -use runtime_primitives::traits::{CheckedMul, Hash, Bounded}; +use runtime_primitives::traits::{Hash, Bounded}; use srml_support::StorageMap; /// Gas metering token that used for charging storing code into the code storage. @@ -41,12 +41,12 @@ use srml_support::StorageMap; pub struct PutCodeToken(u32); impl Token for PutCodeToken { - type Metadata = Schedule; + type Metadata = Schedule; - fn calculate_amount(&self, metadata: &Schedule) -> T::Gas { + fn calculate_amount(&self, metadata: &Schedule) -> Gas { metadata .put_code_per_byte_cost - .checked_mul(&self.0.into()) + .checked_mul(self.0.into()) .unwrap_or_else(|| Bounded::max_value()) } } @@ -58,7 +58,7 @@ impl Token for PutCodeToken { pub fn save( original_code: Vec, gas_meter: &mut GasMeter, - schedule: &Schedule, + schedule: &Schedule, ) -> Result, &'static str> { // The first time instrumentation is on the user. However, consequent reinstrumentation // due to the schedule changes is on governance system. @@ -69,7 +69,7 @@ pub fn save( return Err("there is not enough gas for storing the code"); } - let prefab_module = prepare::prepare_contract::(&original_code, schedule)?; + let prefab_module = prepare::prepare_contract::(&original_code, schedule)?; let code_hash = T::Hashing::hash(&original_code); >::insert(code_hash, prefab_module); @@ -85,7 +85,7 @@ pub fn save( /// re-instrumentation and update the cache in the storage. pub fn load( code_hash: &CodeHash, - schedule: &Schedule, + schedule: &Schedule, ) -> Result { let mut prefab_module = >::get(code_hash).ok_or_else(|| "code is not found")?; @@ -97,7 +97,7 @@ pub fn load( // We need to re-instrument the code with the latest schedule here. let original_code = >::get(code_hash).ok_or_else(|| "pristine code is not found")?; - prefab_module = prepare::prepare_contract::(&original_code, schedule)?; + prefab_module = prepare::prepare_contract::(&original_code, schedule)?; >::insert(code_hash, prefab_module.clone()); } Ok(prefab_module) diff --git a/srml/contracts/src/wasm/env_def/macros.rs b/srml/contracts/src/wasm/env_def/macros.rs index 32d02f5abea76f9bd536377878efb257a26216dc..4f8bce99040007420c98367894a384872d9379c8 100644 --- a/srml/contracts/src/wasm/env_def/macros.rs +++ b/srml/contracts/src/wasm/env_def/macros.rs @@ -200,7 +200,7 @@ mod tests { use crate::wasm::tests::MockExt; use crate::wasm::Runtime; use crate::exec::Ext; - use crate::Trait; + use crate::gas::Gas; #[test] fn macro_unmarshall_then_body_then_marshall_value_or_trap() { @@ -256,7 +256,7 @@ mod tests { #[test] fn macro_define_func() { define_func!( ext_gas (_ctx, amount: u32) => { - let amount = ::Gas::from(amount); + let amount = Gas::from(amount); if !amount.is_zero() { Ok(()) } else { @@ -308,7 +308,7 @@ mod tests { define_env!(Env, , ext_gas( _ctx, amount: u32 ) => { - let amount = ::Gas::from(amount); + let amount = Gas::from(amount); if !amount.is_zero() { Ok(()) } else { diff --git a/srml/contracts/src/wasm/mod.rs b/srml/contracts/src/wasm/mod.rs index 7dcd16d5dacb9b5f7488ad5dc67182ac7a1f268f..1f63b5d9dfa55163e89f77d0a12ceeafef66f1d2 100644 --- a/srml/contracts/src/wasm/mod.rs +++ b/srml/contracts/src/wasm/mod.rs @@ -63,17 +63,17 @@ pub struct WasmExecutable { } /// Loader which fetches `WasmExecutable` from the code cache. -pub struct WasmLoader<'a, T: Trait> { - schedule: &'a Schedule, +pub struct WasmLoader<'a> { + schedule: &'a Schedule, } -impl<'a, T: Trait> WasmLoader<'a, T> { - pub fn new(schedule: &'a Schedule) -> Self { +impl<'a> WasmLoader<'a> { + pub fn new(schedule: &'a Schedule) -> Self { WasmLoader { schedule } } } -impl<'a, T: Trait> crate::exec::Loader for WasmLoader<'a, T> { +impl<'a, T: Trait> crate::exec::Loader for WasmLoader<'a> { type Executable = WasmExecutable; fn load_init(&self, code_hash: &CodeHash) -> Result { @@ -93,17 +93,17 @@ impl<'a, T: Trait> crate::exec::Loader for WasmLoader<'a, T> { } /// Implementation of `Vm` that takes `WasmExecutable` and executes it. -pub struct WasmVm<'a, T: Trait> { - schedule: &'a Schedule, +pub struct WasmVm<'a> { + schedule: &'a Schedule, } -impl<'a, T: Trait> WasmVm<'a, T> { - pub fn new(schedule: &'a Schedule) -> Self { +impl<'a> WasmVm<'a> { + pub fn new(schedule: &'a Schedule) -> Self { WasmVm { schedule } } } -impl<'a, T: Trait> crate::exec::Vm for WasmVm<'a, T> { +impl<'a, T: Trait> crate::exec::Vm for WasmVm<'a> { type Executable = WasmExecutable; fn execute>( @@ -134,7 +134,7 @@ impl<'a, T: Trait> crate::exec::Vm for WasmVm<'a, T> { let mut runtime = Runtime::new( ext, - input_data, + input_data.to_vec(), empty_output_buf, &self.schedule, memory, @@ -175,7 +175,7 @@ mod tests { use std::collections::HashMap; use substrate_primitives::H256; use crate::exec::{CallReceipt, Ext, InstantiateReceipt, EmptyOutputBuf, StorageKey}; - use crate::gas::GasMeter; + use crate::gas::{Gas, GasMeter}; use crate::tests::{Test, Call}; use crate::wasm::prepare::prepare_contract; use crate::CodeHash; @@ -291,6 +291,8 @@ mod tests { fn rent_allowance(&self) -> u64 { self.rent_allowance } + + fn block_number(&self) -> u64 { 121 } } fn execute( @@ -303,9 +305,9 @@ mod tests { use crate::exec::Vm; let wasm = wabt::wat2wasm(wat).unwrap(); - let schedule = crate::Schedule::::default(); + let schedule = crate::Schedule::default(); let prefab_module = - prepare_contract::(&wasm, &schedule).unwrap(); + prepare_contract::(&wasm, &schedule).unwrap(); let exec = WasmExecutable { // Use a "call" convention. @@ -906,14 +908,20 @@ mod tests { fn gas_left() { let mut mock_ext = MockExt::default(); let mut gas_meter = GasMeter::with_limit(50_000, 1312); + + let mut return_buf = Vec::new(); execute( CODE_GAS_LEFT, &[], - &mut Vec::new(), + &mut return_buf, &mut mock_ext, &mut gas_meter, ) .unwrap(); + + let gas_left = Gas::decode(&mut &return_buf[..]).unwrap(); + assert!(gas_left < 50_000, "gas_left must be less than initial"); + assert!(gas_left > gas_meter.gas_left(), "gas_left must be greater than final"); } const CODE_VALUE_TRANSFERRED: &str = r#" @@ -1336,4 +1344,70 @@ mod tests { Err("during execution"), ); } + + /// calls `ext_block_number`, loads the current block number from the scratch buffer and + /// compares it with the constant 121. + const CODE_BLOCK_NUMBER: &str = r#" +(module + (import "env" "ext_block_number" (func $ext_block_number)) + (import "env" "ext_scratch_size" (func $ext_scratch_size (result i32))) + (import "env" "ext_scratch_copy" (func $ext_scratch_copy (param i32 i32 i32))) + (import "env" "memory" (memory 1 1)) + + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + + (func (export "call") + ;; This stores the block height in the scratch buffer + (call $ext_block_number) + + ;; assert $ext_scratch_size == 8 + (call $assert + (i32.eq + (call $ext_scratch_size) + (i32.const 8) + ) + ) + + ;; copy contents of the scratch buffer into the contract's memory. + (call $ext_scratch_copy + (i32.const 8) ;; Pointer in memory to the place where to copy. + (i32.const 0) ;; Offset from the start of the scratch buffer. + (i32.const 8) ;; Count of bytes to copy. + ) + + ;; assert that contents of the buffer is equal to the i64 value of 121. + (call $assert + (i64.eq + (i64.load + (i32.const 8) + ) + (i64.const 121) + ) + ) + ) + + (func (export "deploy")) +) +"#; + + #[test] + fn block_number() { + let mut mock_ext = MockExt::default(); + execute( + CODE_BLOCK_NUMBER, + &[], + &mut Vec::new(), + &mut mock_ext, + &mut GasMeter::with_limit(50_000, 1), + ) + .unwrap(); + } + } diff --git a/srml/contracts/src/wasm/prepare.rs b/srml/contracts/src/wasm/prepare.rs index d780cc1a28328ac6c467fefb7f2094d8988080c0..c135c45d3a8d0cab003d1dc93dbd5adc6fe1c492 100644 --- a/srml/contracts/src/wasm/prepare.rs +++ b/srml/contracts/src/wasm/prepare.rs @@ -20,33 +20,29 @@ use crate::wasm::env_def::ImportSatisfyCheck; use crate::wasm::PrefabWasmModule; -use crate::{Schedule, Trait}; +use crate::Schedule; use parity_wasm::elements::{self, Internal, External, MemoryType, Type}; use pwasm_utils; use pwasm_utils::rules; use rstd::prelude::*; -use runtime_primitives::traits::{UniqueSaturatedInto, SaturatedConversion}; +use runtime_primitives::traits::{SaturatedConversion}; -struct ContractModule<'a, Gas: 'a> { +struct ContractModule<'a> { /// A deserialized module. The module is valid (this is Guaranteed by `new` method). - /// - /// An `Option` is used here for loaning (`take()`-ing) the module. - /// Invariant: Can't be `None` (i.e. on enter and on exit from the function - /// the value *must* be `Some`). - module: Option, - schedule: &'a Schedule, + module: elements::Module, + schedule: &'a Schedule, } -impl<'a, Gas: 'a + From + UniqueSaturatedInto + Clone> ContractModule<'a, Gas> { +impl<'a> ContractModule<'a> { /// Creates a new instance of `ContractModule`. /// /// Returns `Err` if the `original_code` couldn't be decoded or /// if it contains an invalid module. fn new( original_code: &[u8], - schedule: &'a Schedule, - ) -> Result, &'static str> { + schedule: &'a Schedule, + ) -> Result { use wasmi_validation::{validate_module, PlainValidator}; let module = @@ -58,7 +54,7 @@ impl<'a, Gas: 'a + From + UniqueSaturatedInto + Clone> ContractModule< // Return a `ContractModule` instance with // __valid__ module. Ok(ContractModule { - module: Some(module), + module, schedule, }) } @@ -69,11 +65,7 @@ impl<'a, Gas: 'a + From + UniqueSaturatedInto + Clone> ContractModule< /// Memory section contains declarations of internal linear memories, so if we find one /// we reject such a module. fn ensure_no_internal_memory(&self) -> Result<(), &'static str> { - let module = self - .module - .as_ref() - .expect("On entry to the function `module` can't be None; qed"); - if module + if self.module .memory_section() .map_or(false, |ms| ms.entries().len() > 0) { @@ -82,7 +74,26 @@ impl<'a, Gas: 'a + From + UniqueSaturatedInto + Clone> ContractModule< Ok(()) } - fn inject_gas_metering(&mut self) -> Result<(), &'static str> { + /// Ensures that tables declared in the module are not too big. + fn ensure_table_size_limit(&self, limit: u32) -> Result<(), &'static str> { + if let Some(table_section) = self.module.table_section() { + // In Wasm MVP spec, there may be at most one table declared. Double check this + // explicitly just in case the Wasm version changes. + if table_section.entries().len() > 1 { + return Err("multiple tables declared"); + } + if let Some(table_type) = table_section.entries().first() { + // Check the table's initial size as there is no instruction or environment function + // capable of growing the table. + if table_type.limits().initial() > limit { + return Err("table exceeds maximum size allowed") + } + } + } + Ok(()) + } + + fn inject_gas_metering(self) -> Result { let gas_rules = rules::Set::new( self.schedule.regular_op_cost.clone().saturated_into(), @@ -91,30 +102,22 @@ impl<'a, Gas: 'a + From + UniqueSaturatedInto + Clone> ContractModule< .with_grow_cost(self.schedule.grow_mem_cost.clone().saturated_into()) .with_forbidden_floats(); - let module = self - .module - .take() - .expect("On entry to the function `module` can't be `None`; qed"); - - let contract_module = pwasm_utils::inject_gas_counter(module, &gas_rules) + let contract_module = pwasm_utils::inject_gas_counter(self.module, &gas_rules) .map_err(|_| "gas instrumentation failed")?; - - self.module = Some(contract_module); - Ok(()) + Ok(ContractModule { + module: contract_module, + schedule: self.schedule, + }) } - fn inject_stack_height_metering(&mut self) -> Result<(), &'static str> { - let module = self - .module - .take() - .expect("On entry to the function `module` can't be `None`; qed"); - + fn inject_stack_height_metering(self) -> Result { let contract_module = - pwasm_utils::stack_height::inject_limiter(module, self.schedule.max_stack_height) + pwasm_utils::stack_height::inject_limiter(self.module, self.schedule.max_stack_height) .map_err(|_| "stack height instrumentation failed")?; - - self.module = Some(contract_module); - Ok(()) + Ok(ContractModule { + module: contract_module, + schedule: self.schedule, + }) } /// Check that the module has required exported functions. For now @@ -128,10 +131,7 @@ impl<'a, Gas: 'a + From + UniqueSaturatedInto + Clone> ContractModule< let mut deploy_found = false; let mut call_found = false; - let module = self - .module - .as_ref() - .expect("On entry to the function `module` can't be `None`; qed"); + let module = &self.module; let types = module.type_section().map(|ts| ts.types()).unwrap_or(&[]); let export_entries = module @@ -213,10 +213,7 @@ impl<'a, Gas: 'a + From + UniqueSaturatedInto + Clone> ContractModule< /// their signatures. /// - if there is a memory import, returns it's descriptor fn scan_imports(&self) -> Result, &'static str> { - let module = self - .module - .as_ref() - .expect("On entry to the function `module` can't be `None`; qed"); + let module = &self.module; let types = module.type_section().map(|ts| ts.types()).unwrap_or(&[]); let import_entries = module @@ -269,13 +266,9 @@ impl<'a, Gas: 'a + From + UniqueSaturatedInto + Clone> ContractModule< Ok(imported_mem_type) } - fn into_wasm_code(mut self) -> Result, &'static str> { - elements::serialize( - self.module - .take() - .expect("On entry to the function `module` can't be `None`; qed"), - ) - .map_err(|_| "error serializing instrumented module") + fn into_wasm_code(self) -> Result, &'static str> { + elements::serialize(self.module) + .map_err(|_| "error serializing instrumented module") } } @@ -290,13 +283,14 @@ impl<'a, Gas: 'a + From + UniqueSaturatedInto + Clone> ContractModule< /// - all imported functions from the external environment matches defined by `env` module, /// /// The preprocessing includes injecting code for gas metering and metering the height of stack. -pub fn prepare_contract( +pub fn prepare_contract( original_code: &[u8], - schedule: &Schedule, + schedule: &Schedule, ) -> Result { let mut contract_module = ContractModule::new(original_code, schedule)?; contract_module.scan_exports()?; contract_module.ensure_no_internal_memory()?; + contract_module.ensure_table_size_limit(schedule.max_table_size)?; struct MemoryDefinition { initial: u32, @@ -332,8 +326,9 @@ pub fn prepare_contract( } }; - contract_module.inject_gas_metering()?; - contract_module.inject_stack_height_metering()?; + contract_module = contract_module + .inject_gas_metering()? + .inject_stack_height_metering()?; Ok(PrefabWasmModule { schedule_version: schedule.version, @@ -347,7 +342,6 @@ pub fn prepare_contract( #[cfg(test)] mod tests { use super::*; - use crate::tests::Test; use crate::exec::Ext; use std::fmt; use wabt; @@ -377,8 +371,8 @@ mod tests { #[test] fn $name() { let wasm = wabt::Wat2Wasm::new().validate(false).convert($wat).unwrap(); - let schedule = Schedule::::default(); - let r = prepare_contract::(wasm.as_ref(), &schedule); + let schedule = Schedule::default(); + let r = prepare_contract::(wasm.as_ref(), &schedule); assert_matches!(r, $($expected)*); } }; @@ -406,7 +400,7 @@ mod tests { // Tests below assumes that maximum page number is configured to a certain number. #[test] fn assume_memory_size() { - assert_eq!(Schedule::::default().max_memory_pages, 16); + assert_eq!(Schedule::default().max_memory_pages, 16); } prepare_test!(memory_with_one_page, @@ -529,6 +523,49 @@ mod tests { ); } + mod tables { + use super::*; + + // Tests below assumes that maximum table size is configured to a certain number. + #[test] + fn assume_table_size() { + assert_eq!(Schedule::default().max_table_size, 16384); + } + + prepare_test!(no_tables, + r#" + (module + (func (export "call")) + (func (export "deploy")) + ) + "#, + Ok(_) + ); + + prepare_test!(table_valid_size, + r#" + (module + (table 10000 funcref) + + (func (export "call")) + (func (export "deploy")) + ) + "#, + Ok(_) + ); + + prepare_test!(table_too_big, + r#" + (module + (table 20000 funcref) + + (func (export "call")) + (func (export "deploy")) + )"#, + Err("table exceeds maximum size allowed") + ); + } + mod imports { use super::*; @@ -620,9 +657,9 @@ mod tests { ) "# ).unwrap(); - let mut schedule = Schedule::::default(); + let mut schedule = Schedule::default(); schedule.enable_println = true; - let r = prepare_contract::(wasm.as_ref(), &schedule); + let r = prepare_contract::(wasm.as_ref(), &schedule); assert_matches!(r, Ok(_)); } } diff --git a/srml/contracts/src/wasm/runtime.rs b/srml/contracts/src/wasm/runtime.rs index 873464c5bea0a743577611e23113c93db6978828..29965c9676aca4eebd7f03b0e7b89d3b303c88a7 100644 --- a/srml/contracts/src/wasm/runtime.rs +++ b/srml/contracts/src/wasm/runtime.rs @@ -21,13 +21,13 @@ use crate::exec::{ Ext, VmExecResult, OutputBuf, EmptyOutputBuf, CallReceipt, InstantiateReceipt, StorageKey, TopicOf, }; -use crate::gas::{GasMeter, Token, GasMeterResult, approx_gas_for_balance}; +use crate::gas::{Gas, GasMeter, Token, GasMeterResult, approx_gas_for_balance}; use sandbox; use system; use rstd::prelude::*; use rstd::mem; use parity_codec::{Decode, Encode}; -use runtime_primitives::traits::{CheckedMul, CheckedAdd, Bounded, SaturatedConversion}; +use runtime_primitives::traits::{Bounded, SaturatedConversion}; /// Enumerates all possible *special* trap conditions. /// @@ -39,32 +39,31 @@ enum SpecialTrap { } /// Can only be used for one call. -pub(crate) struct Runtime<'a, 'data, E: Ext + 'a> { +pub(crate) struct Runtime<'a, E: Ext + 'a> { ext: &'a mut E, - input_data: &'data [u8], // A VM can return a result only once and only by value. So // we wrap output buffer to make it possible to take the buffer out. empty_output_buf: Option, scratch_buf: Vec, - schedule: &'a Schedule<::Gas>, + schedule: &'a Schedule, memory: sandbox::Memory, gas_meter: &'a mut GasMeter, special_trap: Option, } -impl<'a, 'data, E: Ext + 'a> Runtime<'a, 'data, E> { +impl<'a, E: Ext + 'a> Runtime<'a, E> { pub(crate) fn new( ext: &'a mut E, - input_data: &'data [u8], + input_data: Vec, empty_output_buf: EmptyOutputBuf, - schedule: &'a Schedule<::Gas>, + schedule: &'a Schedule, memory: sandbox::Memory, gas_meter: &'a mut GasMeter, ) -> Self { Runtime { ext, - input_data, empty_output_buf: Some(empty_output_buf), - scratch_buf: Vec::new(), + // Put the input data into the scratch buffer immediately. + scratch_buf: input_data, schedule, memory, gas_meter, @@ -98,7 +97,7 @@ pub(crate) fn to_execution_result( #[cfg_attr(test, derive(Debug, PartialEq, Eq))] #[derive(Copy, Clone)] -pub enum RuntimeToken { +pub enum RuntimeToken { /// Explicit call to the `gas` function. Charge the gas meter /// with the value provided. Explicit(u32), @@ -116,39 +115,39 @@ pub enum RuntimeToken { DepositEvent(u32, u32), } -impl Token for RuntimeToken { - type Metadata = Schedule; +impl Token for RuntimeToken { + type Metadata = Schedule; - fn calculate_amount(&self, metadata: &Schedule) -> T::Gas { + fn calculate_amount(&self, metadata: &Schedule) -> Gas { use self::RuntimeToken::*; let value = match *self { Explicit(amount) => Some(amount.into()), ReadMemory(byte_count) => metadata .sandbox_data_read_cost - .checked_mul(&byte_count.into()), + .checked_mul(byte_count.into()), WriteMemory(byte_count) => metadata .sandbox_data_write_cost - .checked_mul(&byte_count.into()), + .checked_mul(byte_count.into()), ReturnData(byte_count) => metadata .return_data_per_byte_cost - .checked_mul(&byte_count.into()), + .checked_mul(byte_count.into()), DepositEvent(topic_count, data_byte_count) => { let data_cost = metadata .event_data_per_byte_cost - .checked_mul(&data_byte_count.into()); + .checked_mul(data_byte_count.into()); let topics_cost = metadata .event_per_topic_cost - .checked_mul(&topic_count.into()); + .checked_mul(topic_count.into()); data_cost .and_then(|data_cost| { topics_cost.and_then(|topics_cost| { - data_cost.checked_add(&topics_cost) + data_cost.checked_add(topics_cost) }) }) .and_then(|data_and_topics_cost| - data_and_topics_cost.checked_add(&metadata.event_base_cost) + data_and_topics_cost.checked_add(metadata.event_base_cost) ) }, ComputedDispatchFee(gas) => Some(gas), @@ -222,7 +221,7 @@ fn read_sandbox_memory_into_buf( /// - out of gas /// - designated area is not within the bounds of the sandbox memory. fn write_sandbox_memory( - schedule: &Schedule, + schedule: &Schedule, gas_meter: &mut GasMeter, memory: &sandbox::Memory, ptr: u32, @@ -277,7 +276,7 @@ define_env!(Env, , Ok(()) }, - // Retrieve the value at the given location from the strorage and return 0. + // Retrieve the value at the given location from the storage and return 0. // If there is no entry at the given location then this function will return 1 and // clear the scratch buffer. // @@ -443,6 +442,8 @@ define_env!(Env, , // Save a data buffer as a result of the execution, terminate the execution and return a // successful result to the caller. + // + // This is the only way to return a data buffer to the caller. ext_return(ctx, data_ptr: u32, data_len: u32) => { match ctx .gas_meter @@ -485,13 +486,15 @@ define_env!(Env, , // will be returned. Otherwise, if this call is initiated by another contract then the address // of the contract will be returned. ext_caller(ctx) => { - ctx.scratch_buf = ctx.ext.caller().encode(); + ctx.scratch_buf.clear(); + ctx.ext.caller().encode_to(&mut ctx.scratch_buf); Ok(()) }, // Stores the address of the current contract into the scratch buffer. ext_address(ctx) => { - ctx.scratch_buf = ctx.ext.address().encode(); + ctx.scratch_buf.clear(); + ctx.ext.address().encode_to(&mut ctx.scratch_buf); Ok(()) }, @@ -499,15 +502,17 @@ define_env!(Env, , // // The data is encoded as T::Balance. The current contents of the scratch buffer are overwritten. ext_gas_price(ctx) => { - ctx.scratch_buf = ctx.gas_meter.gas_price().encode(); + ctx.scratch_buf.clear(); + ctx.gas_meter.gas_price().encode_to(&mut ctx.scratch_buf); Ok(()) }, // Stores the amount of gas left into the scratch buffer. // - // The data is encoded as T::Balance. The current contents of the scratch buffer are overwritten. + // The data is encoded as Gas. The current contents of the scratch buffer are overwritten. ext_gas_left(ctx) => { - ctx.scratch_buf = ctx.gas_meter.gas_left().encode(); + ctx.scratch_buf.clear(); + ctx.gas_meter.gas_left().encode_to(&mut ctx.scratch_buf); Ok(()) }, @@ -515,7 +520,8 @@ define_env!(Env, , // // The data is encoded as T::Balance. The current contents of the scratch buffer are overwritten. ext_balance(ctx) => { - ctx.scratch_buf = ctx.ext.balance().encode(); + ctx.scratch_buf.clear(); + ctx.ext.balance().encode_to(&mut ctx.scratch_buf); Ok(()) }, @@ -523,7 +529,8 @@ define_env!(Env, , // // The data is encoded as T::Balance. The current contents of the scratch buffer are overwritten. ext_value_transferred(ctx) => { - ctx.scratch_buf = ctx.ext.value_transferred().encode(); + ctx.scratch_buf.clear(); + ctx.ext.value_transferred().encode_to(&mut ctx.scratch_buf); Ok(()) }, @@ -539,13 +546,15 @@ define_env!(Env, , } let subject_buf = read_sandbox_memory(ctx, subject_ptr, subject_len)?; - ctx.scratch_buf = ctx.ext.random(&subject_buf).encode(); + ctx.scratch_buf.clear(); + ctx.ext.random(&subject_buf).encode_to(&mut ctx.scratch_buf); Ok(()) }, // Load the latest block timestamp into the scratch buffer ext_now(ctx) => { - ctx.scratch_buf = ctx.ext.now().encode(); + ctx.scratch_buf.clear(); + ctx.ext.now().encode_to(&mut ctx.scratch_buf); Ok(()) }, @@ -564,7 +573,7 @@ define_env!(Env, , // Charge gas for dispatching this call. let fee = { let balance_fee = <::T as Trait>::ComputeDispatchFee::compute_dispatch_fee(&call); - approx_gas_for_balance::<::T>(ctx.gas_meter.gas_price(), balance_fee) + approx_gas_for_balance(ctx.gas_meter.gas_price(), balance_fee) }; charge_gas(&mut ctx.gas_meter, ctx.schedule, RuntimeToken::ComputedDispatchFee(fee))?; @@ -573,45 +582,19 @@ define_env!(Env, , Ok(()) }, - // Returns the size of the input buffer. - ext_input_size(ctx) -> u32 => { - Ok(ctx.input_data.len() as u32) - }, - - // Copy data from the input buffer starting from `offset` with length `len` into the contract memory. - // The region at which the data should be put is specified by `dest_ptr`. - ext_input_copy(ctx, dest_ptr: u32, offset: u32, len: u32) => { - let offset = offset as usize; - if offset > ctx.input_data.len() { - // Offset can't be larger than input buffer length. - return Err(sandbox::HostError); - } - - // This can't panic since `offset <= ctx.input_data.len()`. - let src = &ctx.input_data[offset..]; - if src.len() != len as usize { - return Err(sandbox::HostError); - } - - // Finally, perform the write. - write_sandbox_memory( - ctx.schedule, - ctx.gas_meter, - &ctx.memory, - dest_ptr, - src, - )?; - - Ok(()) - }, - // Returns the size of the scratch buffer. + // + // For more details on the scratch buffer see `ext_scratch_copy`. ext_scratch_size(ctx) -> u32 => { Ok(ctx.scratch_buf.len() as u32) }, // Copy data from the scratch buffer starting from `offset` with length `len` into the contract memory. // The region at which the data should be put is specified by `dest_ptr`. + // + // In order to get size of the scratch buffer use `ext_scratch_size`. At the start of contract + // execution, the scratch buffer is filled with the input data. Whenever a contract calls + // function that uses the scratch buffer the contents of the scratch buffer are overwritten. ext_scratch_copy(ctx, dest_ptr: u32, offset: u32, len: u32) => { let offset = offset as usize; if offset > ctx.scratch_buf.len() { @@ -702,7 +685,8 @@ define_env!(Env, , // // The data is encoded as T::Balance. The current contents of the scratch buffer are overwritten. ext_rent_allowance(ctx) => { - ctx.scratch_buf = ctx.ext.rent_allowance().encode(); + ctx.scratch_buf.clear(); + ctx.ext.rent_allowance().encode_to(&mut ctx.scratch_buf); Ok(()) }, @@ -717,6 +701,13 @@ define_env!(Env, , } Ok(()) }, + + // Stores the current block number of the current contract into the scratch buffer. + ext_block_number(ctx) => { + ctx.scratch_buf.clear(); + ctx.ext.block_number().encode_to(&mut ctx.scratch_buf); + Ok(()) + }, ); /// Finds duplicates in a given vector. diff --git a/srml/council/src/lib.rs b/srml/council/src/lib.rs index 681bc731be895ee3855a4b910dee4ebe741bff99..8a52f9ec004a9615ffc81af03dde5c0dc6ba80e1 100644 --- a/srml/council/src/lib.rs +++ b/srml/council/src/lib.rs @@ -17,6 +17,7 @@ //! Council system: Handles the voting in and maintenance of council members. #![cfg_attr(not(feature = "std"), no_std)] +#![recursion_limit="128"] pub mod motions; pub mod seats; @@ -39,11 +40,12 @@ mod tests { pub use super::*; pub use runtime_io::with_externalities; use srml_support::{impl_outer_origin, impl_outer_event, impl_outer_dispatch, parameter_types}; + use srml_support::traits::Get; pub use substrate_primitives::{H256, Blake2Hasher, u32_trait::{_1, _2, _3, _4}}; - pub use primitives::{ - BuildStorage, traits::{BlakeTwo256, IdentityLookup}, testing::{Digest, DigestItem, Header} - }; + pub use primitives::traits::{BlakeTwo256, IdentityLookup}; + pub use primitives::testing::{Digest, DigestItem, Header}; pub use {seats, motions}; + use std::cell::RefCell; impl_outer_origin! { pub enum Origin for Test { @@ -64,9 +66,39 @@ mod tests { } } + thread_local! { + static VOTER_BOND: RefCell = RefCell::new(0); + static VOTING_FEE: RefCell = RefCell::new(0); + static PRESENT_SLASH_PER_VOTER: RefCell = RefCell::new(0); + static DECAY_RATIO: RefCell = RefCell::new(0); + } + + pub struct VotingBond; + impl Get for VotingBond { + fn get() -> u64 { VOTER_BOND.with(|v| *v.borrow()) } + } + + pub struct VotingFee; + impl Get for VotingFee { + fn get() -> u64 { VOTING_FEE.with(|v| *v.borrow()) } + } + + pub struct PresentSlashPerVoter; + impl Get for PresentSlashPerVoter { + fn get() -> u64 { PRESENT_SLASH_PER_VOTER.with(|v| *v.borrow()) } + } + + pub struct DecayRatio; + impl Get for DecayRatio { + fn get() -> u32 { DECAY_RATIO.with(|v| *v.borrow()) } + } + // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, Eq, PartialEq, Debug)] pub struct Test; + parameter_types! { + pub const BlockHashCount: u64 = 250; + } impl system::Trait for Test { type Origin = Origin; type Index = u64; @@ -77,15 +109,28 @@ mod tests { type Lookup = IdentityLookup; type Header = Header; type Event = Event; + type BlockHashCount = BlockHashCount; + } + parameter_types! { + pub const ExistentialDeposit: u64 = 0; + pub const TransferFee: u64 = 0; + pub const CreationFee: u64 = 0; + pub const TransactionBaseFee: u64 = 0; + pub const TransactionByteFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; - type OnFreeBalanceZero = (); type OnNewAccount = (); + type OnFreeBalanceZero = (); type Event = Event; type TransactionPayment = (); type TransferPayment = (); type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type TransferFee = TransferFee; + type CreationFee = CreationFee; + type TransactionBaseFee = TransactionBaseFee; + type TransactionByteFee = TransactionByteFee; } parameter_types! { pub const LaunchPeriod: u64 = 1; @@ -110,6 +155,12 @@ mod tests { type VetoOrigin = motions::EnsureMember; type CooloffPeriod = CooloffPeriod; } + parameter_types! { + pub const CandidacyBond: u64 = 3; + pub const CarryCount: u32 = 2; + pub const InactiveGracePeriod: u32 = 1; + pub const CouncilVotingPeriod: u64 = 4; + } impl seats::Trait for Test { type Event = Event; type BadPresentation = (); @@ -117,6 +168,14 @@ mod tests { type BadVoterIndex = (); type LoserCandidate = (); type OnMembersChanged = CouncilMotions; + type CandidacyBond = CandidacyBond; + type VotingBond = VotingBond; + type VotingFee = VotingFee; + type PresentSlashPerVoter = PresentSlashPerVoter; + type CarryCount = CarryCount; + type InactiveGracePeriod = InactiveGracePeriod; + type CouncilVotingPeriod = CouncilVotingPeriod; + type DecayRatio = DecayRatio; } impl motions::Trait for Test { type Origin = Origin; @@ -171,11 +230,16 @@ mod tests { self.voter_bond = fee; self } + pub fn set_associated_consts(&self) { + VOTER_BOND.with(|v| *v.borrow_mut() = self.voter_bond); + VOTING_FEE.with(|v| *v.borrow_mut() = self.voting_fee); + PRESENT_SLASH_PER_VOTER.with(|v| *v.borrow_mut() = self.bad_presentation_punishment); + DECAY_RATIO.with(|v| *v.borrow_mut() = self.decay_ratio); + } pub fn build(self) -> runtime_io::TestExternalities { - let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; - t.extend(balances::GenesisConfig::{ - transaction_base_fee: 0, - transaction_byte_fee: 0, + self.set_associated_consts(); + let mut t = system::GenesisConfig::default().build_storage::().unwrap(); + balances::GenesisConfig::{ balances: vec![ (1, 10 * self.balance_factor), (2, 20 * self.balance_factor), @@ -184,30 +248,19 @@ mod tests { (5, 50 * self.balance_factor), (6, 60 * self.balance_factor) ], - existential_deposit: 0, - transfer_fee: 0, - creation_fee: 0, vesting: vec![], - }.build_storage().unwrap().0); - t.extend(seats::GenesisConfig:: { - candidacy_bond: 3, - voter_bond: self.voter_bond, - present_slash_per_voter: self.bad_presentation_punishment, - carry_count: 2, - inactive_grace_period: 1, + }.assimilate_storage(&mut t.0, &mut t.1).unwrap(); + seats::GenesisConfig:: { active_council: if self.with_council { vec![ (1, 10), (2, 10), (3, 10) ] } else { vec![] }, - approval_voting_period: 4, - presentation_duration: 2, desired_seats: 2, - decay_ratio: self.decay_ratio, - voting_fee: self.voting_fee, + presentation_duration: 2, term_duration: 5, - }.build_storage().unwrap().0); - runtime_io::TestExternalities::new(t) + }.assimilate_storage(&mut t.0, &mut t.1).unwrap(); + runtime_io::TestExternalities::new_with_children(t) } } diff --git a/srml/council/src/motions.rs b/srml/council/src/motions.rs deleted file mode 100644 index a53752d71f90525b67fb9e715509262277a02ca9..0000000000000000000000000000000000000000 --- a/srml/council/src/motions.rs +++ /dev/null @@ -1,583 +0,0 @@ -// Copyright 2017-2019 Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate 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. - -// Substrate 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 Substrate. If not, see . - -//! Council voting system. - -use rstd::{prelude::*, result}; -use substrate_primitives::u32_trait::Value as U32; -use primitives::traits::{Hash, EnsureOrigin}; -use srml_support::{ - dispatch::{Dispatchable, Parameter}, codec::{Encode, Decode}, - StorageValue, StorageMap, decl_module, decl_event, decl_storage, ensure -}; -use super::{Trait as CouncilTrait, Module as Council, OnMembersChanged}; -use system::{self, ensure_signed}; - -/// Simple index type for proposal counting. -pub type ProposalIndex = u32; -/// A number of council members. -/// -/// This also serves as a number of voting members, and since for motions, each council member may -/// vote exactly once, therefore also the number of votes for any given motion. -pub type MemberCount = u32; - -pub trait Trait: CouncilTrait { - /// The outer origin type. - type Origin: From>; - - /// The outer call dispatch type. - type Proposal: Parameter + Dispatchable::Origin>; - - /// The outer event type. - type Event: From> + Into<::Event>; -} - -/// Origin for the council module. -#[derive(PartialEq, Eq, Clone)] -#[cfg_attr(feature = "std", derive(Debug))] -pub enum RawOrigin { - /// It has been condoned by a given number of council members from a given total. - Members(MemberCount, MemberCount), - /// It has been condoned by a single council member. - Member(AccountId), -} - -/// Origin for the council module. -pub type Origin = RawOrigin<::AccountId>; - -#[derive(PartialEq, Eq, Clone, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] -/// Info for keeping track of a motion being voted on. -pub struct Votes { - /// The proposal's unique index. - index: ProposalIndex, - /// The number of approval votes that are needed to pass the motion. - threshold: MemberCount, - /// The current set of voters that approved it. - ayes: Vec, - /// The current set of voters that rejected it. - nays: Vec, -} - -decl_storage! { - trait Store for Module as CouncilMotions { - /// The hashes of the active proposals. - pub Proposals get(proposals): Vec; - /// Actual proposal for a given hash, if it's current. - pub ProposalOf get(proposal_of): map T::Hash => Option<::Proposal>; - /// Votes on a given proposal, if it is ongoing. - pub Voting get(voting): map T::Hash => Option>; - /// Proposals so far. - pub ProposalCount get(proposal_count): u32; - } -} - -decl_event!( - pub enum Event where ::Hash, ::AccountId { - /// A motion (given hash) has been proposed (by given account) with a threshold (given - /// `MemberCount`). - Proposed(AccountId, ProposalIndex, Hash, MemberCount), - /// A motion (given hash) has been voted on by given account, leaving - /// a tally (yes votes and no votes given respectively as `MemberCount`). - Voted(AccountId, Hash, bool, MemberCount, MemberCount), - /// A motion was approved by the required threshold. - Approved(Hash), - /// A motion was not approved by the required threshold. - Disapproved(Hash), - /// A motion was executed; `bool` is true if returned without error. - Executed(Hash, bool), - /// A single councillor did some action; `bool` is true if returned without error. - MemberExecuted(Hash, bool), - } -); - -decl_module! { - pub struct Module for enum Call where origin: ::Origin { - fn deposit_event() = default; - - /// Dispatch a proposal from a councilor using the `Member` origin. - /// - /// Origin must be a council member. - fn execute(origin, proposal: Box<::Proposal>) { - let who = ensure_signed(origin)?; - ensure!(Self::is_councillor(&who), "proposer not on council"); - - let proposal_hash = T::Hashing::hash_of(&proposal); - let ok = proposal.dispatch(RawOrigin::Member(who).into()).is_ok(); - Self::deposit_event(RawEvent::MemberExecuted(proposal_hash, ok)); - } - - /// # - /// - Bounded storage reads and writes. - /// - Argument `threshold` has bearing on weight. - /// # - fn propose(origin, #[compact] threshold: MemberCount, proposal: Box<::Proposal>) { - let who = ensure_signed(origin)?; - - ensure!(Self::is_councillor(&who), "proposer not on council"); - - let proposal_hash = T::Hashing::hash_of(&proposal); - - ensure!(!>::exists(proposal_hash), "duplicate proposals not allowed"); - - if threshold < 2 { - let seats = >::active_council().len() as MemberCount; - let ok = proposal.dispatch(RawOrigin::Members(1, seats).into()).is_ok(); - Self::deposit_event(RawEvent::Executed(proposal_hash, ok)); - } else { - let index = Self::proposal_count(); - >::mutate(|i| *i += 1); - >::mutate(|proposals| proposals.push(proposal_hash)); - >::insert(proposal_hash, *proposal); - let votes = Votes { index, threshold, ayes: vec![who.clone()], nays: vec![] }; - >::insert(proposal_hash, votes); - - Self::deposit_event(RawEvent::Proposed(who, index, proposal_hash, threshold)); - } - } - - /// # - /// - Bounded storage read and writes. - /// - Will be slightly heavier if the proposal is approved / disapproved after the vote. - /// # - fn vote(origin, proposal: T::Hash, #[compact] index: ProposalIndex, approve: bool) { - let who = ensure_signed(origin)?; - - ensure!(Self::is_councillor(&who), "voter not on council"); - - let mut voting = Self::voting(&proposal).ok_or("proposal must exist")?; - ensure!(voting.index == index, "mismatched index"); - - let position_yes = voting.ayes.iter().position(|a| a == &who); - let position_no = voting.nays.iter().position(|a| a == &who); - - if approve { - if position_yes.is_none() { - voting.ayes.push(who.clone()); - } else { - return Err("duplicate vote ignored") - } - if let Some(pos) = position_no { - voting.nays.swap_remove(pos); - } - } else { - if position_no.is_none() { - voting.nays.push(who.clone()); - } else { - return Err("duplicate vote ignored") - } - if let Some(pos) = position_yes { - voting.ayes.swap_remove(pos); - } - } - - let yes_votes = voting.ayes.len() as MemberCount; - let no_votes = voting.nays.len() as MemberCount; - Self::deposit_event(RawEvent::Voted(who, proposal, approve, yes_votes, no_votes)); - - let seats = >::active_council().len() as MemberCount; - let approved = yes_votes >= voting.threshold; - let disapproved = seats.saturating_sub(no_votes) < voting.threshold; - if approved || disapproved { - if approved { - Self::deposit_event(RawEvent::Approved(proposal)); - - // execute motion, assuming it exists. - if let Some(p) = >::take(&proposal) { - let origin = RawOrigin::Members(voting.threshold, seats).into(); - let ok = p.dispatch(origin).is_ok(); - Self::deposit_event(RawEvent::Executed(proposal, ok)); - } - } else { - // disapproved - Self::deposit_event(RawEvent::Disapproved(proposal)); - } - - // remove vote - >::remove(&proposal); - >::mutate(|proposals| proposals.retain(|h| h != &proposal)); - } else { - // update voting - >::insert(&proposal, voting); - } - } - } -} - -impl Module { - pub fn is_councillor(who: &T::AccountId) -> bool { - >::active_council().iter() - .any(|&(ref a, _)| a == who) - } -} - -impl OnMembersChanged for Module { - fn on_members_changed(_new: &[T::AccountId], old: &[T::AccountId]) { - // remove accounts from all current voting in motions. - let mut old = old.to_vec(); - old.sort_unstable(); - for h in Self::proposals().into_iter() { - >::mutate(h, |v| - if let Some(mut votes) = v.take() { - votes.ayes = votes.ayes.into_iter() - .filter(|i| old.binary_search(i).is_err()) - .collect(); - votes.nays = votes.nays.into_iter() - .filter(|i| old.binary_search(i).is_err()) - .collect(); - *v = Some(votes); - } - ); - } - } -} - -/// Ensure that the origin `o` represents at least `n` council members. Returns `Ok` or an `Err` -/// otherwise. -pub fn ensure_council_members(o: OuterOrigin, n: MemberCount) - -> result::Result - where OuterOrigin: Into, OuterOrigin>> -{ - match o.into() { - Ok(RawOrigin::Members(x, _)) if x >= n => Ok(n), - _ => Err("bad origin: expected to be a threshold number of council members"), - } -} - -pub struct EnsureMember(::rstd::marker::PhantomData); -impl< - O: Into, O>> + From>, - AccountId -> EnsureOrigin for EnsureMember { - type Success = AccountId; - fn try_origin(o: O) -> Result { - o.into().and_then(|o| match o { - RawOrigin::Member(id) => Ok(id), - r => Err(O::from(r)), - }) - } -} - -pub struct EnsureMembers(::rstd::marker::PhantomData<(N, AccountId)>); -impl< - O: Into, O>> + From>, - N: U32, - AccountId, -> EnsureOrigin for EnsureMembers { - type Success = (MemberCount, MemberCount); - fn try_origin(o: O) -> Result { - o.into().and_then(|o| match o { - RawOrigin::Members(n, m) if n >= N::VALUE => Ok((n, m)), - r => Err(O::from(r)), - }) - } -} - -pub struct EnsureProportionMoreThan( - ::rstd::marker::PhantomData<(N, D, AccountId)> -); -impl< - O: Into, O>> + From>, - N: U32, - D: U32, - AccountId, -> EnsureOrigin for EnsureProportionMoreThan { - type Success = (); - fn try_origin(o: O) -> Result { - o.into().and_then(|o| match o { - RawOrigin::Members(n, m) if n * D::VALUE > N::VALUE * m => Ok(()), - r => Err(O::from(r)), - }) - } -} - -pub struct EnsureProportionAtLeast( - ::rstd::marker::PhantomData<(N, D, AccountId)> -); -impl< - O: Into, O>> + From>, - N: U32, - D: U32, - AccountId, -> EnsureOrigin for EnsureProportionAtLeast { - type Success = (); - fn try_origin(o: O) -> Result { - o.into().and_then(|o| match o { - RawOrigin::Members(n, m) if n * D::VALUE >= N::VALUE * m => Ok(()), - r => Err(O::from(r)), - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use super::RawEvent; - use crate::tests::*; - use crate::tests::{Call, Origin, Event as OuterEvent}; - use primitives::traits::BlakeTwo256; - use srml_support::{Hashable, assert_ok, assert_noop}; - use system::{EventRecord, Phase}; - use hex_literal::hex; - - #[test] - fn motions_basic_environment_works() { - with_externalities(&mut ExtBuilder::default().with_council(true).build(), || { - System::set_block_number(1); - assert_eq!(Balances::free_balance(&42), 0); - assert_eq!(CouncilMotions::proposals(), Vec::::new()); - }); - } - - fn set_balance_proposal(value: u64) -> Call { - Call::Balances(balances::Call::set_balance(42, value.into(), 0)) - } - - #[test] - fn removal_of_old_voters_votes_works() { - with_externalities(&mut ExtBuilder::default().with_council(true).build(), || { - System::set_block_number(1); - let proposal = set_balance_proposal(42); - let hash = BlakeTwo256::hash_of(&proposal); - assert_ok!(CouncilMotions::propose(Origin::signed(1), 3, Box::new(proposal.clone()))); - assert_ok!(CouncilMotions::vote(Origin::signed(2), hash.clone(), 0, true)); - assert_eq!( - CouncilMotions::voting(&hash), - Some(Votes { index: 0, threshold: 3, ayes: vec![1, 2], nays: vec![] }) - ); - CouncilMotions::on_members_changed(&[], &[1]); - assert_eq!( - CouncilMotions::voting(&hash), - Some(Votes { index: 0, threshold: 3, ayes: vec![2], nays: vec![] }) - ); - - let proposal = set_balance_proposal(69); - let hash = BlakeTwo256::hash_of(&proposal); - assert_ok!(CouncilMotions::propose(Origin::signed(2), 2, Box::new(proposal.clone()))); - assert_ok!(CouncilMotions::vote(Origin::signed(3), hash.clone(), 1, false)); - assert_eq!( - CouncilMotions::voting(&hash), - Some(Votes { index: 1, threshold: 2, ayes: vec![2], nays: vec![3] }) - ); - CouncilMotions::on_members_changed(&[], &[3]); - assert_eq!( - CouncilMotions::voting(&hash), - Some(Votes { index: 1, threshold: 2, ayes: vec![2], nays: vec![] }) - ); - }); - } - - #[test] - fn propose_works() { - with_externalities(&mut ExtBuilder::default().with_council(true).build(), || { - System::set_block_number(1); - let proposal = set_balance_proposal(42); - let hash = proposal.blake2_256().into(); - assert_ok!(CouncilMotions::propose(Origin::signed(1), 3, Box::new(proposal.clone()))); - assert_eq!(CouncilMotions::proposals(), vec![hash]); - assert_eq!(CouncilMotions::proposal_of(&hash), Some(proposal)); - assert_eq!( - CouncilMotions::voting(&hash), - Some(Votes { index: 0, threshold: 3, ayes: vec![1], nays: vec![] }) - ); - - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: OuterEvent::motions(RawEvent::Proposed( - 1, - 0, - hex!["cd0b662a49f004093b80600415cf4126399af0d27ed6c185abeb1469c17eb5bf"].into(), - 3, - )), - topics: vec![], - } - ]); - }); - } - - #[test] - fn motions_ignoring_non_council_proposals_works() { - with_externalities(&mut ExtBuilder::default().with_council(true).build(), || { - System::set_block_number(1); - let proposal = set_balance_proposal(42); - assert_noop!( - CouncilMotions::propose(Origin::signed(42), 3, Box::new(proposal.clone())), - "proposer not on council" - ); - }); - } - - #[test] - fn motions_ignoring_non_council_votes_works() { - with_externalities(&mut ExtBuilder::default().with_council(true).build(), || { - System::set_block_number(1); - let proposal = set_balance_proposal(42); - let hash: H256 = proposal.blake2_256().into(); - assert_ok!(CouncilMotions::propose(Origin::signed(1), 3, Box::new(proposal.clone()))); - assert_noop!(CouncilMotions::vote(Origin::signed(42), hash.clone(), 0, true), "voter not on council"); - }); - } - - #[test] - fn motions_ignoring_bad_index_council_vote_works() { - with_externalities(&mut ExtBuilder::default().with_council(true).build(), || { - System::set_block_number(3); - let proposal = set_balance_proposal(42); - let hash: H256 = proposal.blake2_256().into(); - assert_ok!(CouncilMotions::propose(Origin::signed(1), 3, Box::new(proposal.clone()))); - assert_noop!(CouncilMotions::vote(Origin::signed(2), hash.clone(), 1, true), "mismatched index"); - }); - } - - #[test] - fn motions_revoting_works() { - with_externalities(&mut ExtBuilder::default().with_council(true).build(), || { - System::set_block_number(1); - let proposal = set_balance_proposal(42); - let hash: H256 = proposal.blake2_256().into(); - assert_ok!(CouncilMotions::propose(Origin::signed(1), 2, Box::new(proposal.clone()))); - assert_eq!( - CouncilMotions::voting(&hash), - Some(Votes { index: 0, threshold: 2, ayes: vec![1], nays: vec![] }) - ); - assert_noop!(CouncilMotions::vote(Origin::signed(1), hash.clone(), 0, true), "duplicate vote ignored"); - assert_ok!(CouncilMotions::vote(Origin::signed(1), hash.clone(), 0, false)); - assert_eq!( - CouncilMotions::voting(&hash), - Some(Votes { index: 0, threshold: 2, ayes: vec![], nays: vec![1] }) - ); - assert_noop!(CouncilMotions::vote(Origin::signed(1), hash.clone(), 0, false), "duplicate vote ignored"); - - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: OuterEvent::motions(RawEvent::Proposed( - 1, - 0, - hex!["cd0b662a49f004093b80600415cf4126399af0d27ed6c185abeb1469c17eb5bf"].into(), - 2, - )), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: OuterEvent::motions(RawEvent::Voted( - 1, - hex!["cd0b662a49f004093b80600415cf4126399af0d27ed6c185abeb1469c17eb5bf"].into(), - false, - 0, - 1, - )), - topics: vec![], - } - ]); - }); - } - - #[test] - fn motions_disapproval_works() { - with_externalities(&mut ExtBuilder::default().with_council(true).build(), || { - System::set_block_number(1); - let proposal = set_balance_proposal(42); - let hash: H256 = proposal.blake2_256().into(); - assert_ok!(CouncilMotions::propose(Origin::signed(1), 3, Box::new(proposal.clone()))); - assert_ok!(CouncilMotions::vote(Origin::signed(2), hash.clone(), 0, false)); - - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: OuterEvent::motions( - RawEvent::Proposed( - 1, - 0, - hex!["cd0b662a49f004093b80600415cf4126399af0d27ed6c185abeb1469c17eb5bf"].into(), - 3, - )), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: OuterEvent::motions(RawEvent::Voted( - 2, - hex!["cd0b662a49f004093b80600415cf4126399af0d27ed6c185abeb1469c17eb5bf"].into(), - false, - 1, - 1, - )), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: OuterEvent::motions(RawEvent::Disapproved( - hex!["cd0b662a49f004093b80600415cf4126399af0d27ed6c185abeb1469c17eb5bf"].into(), - )), - topics: vec![], - } - ]); - }); - } - - #[test] - fn motions_approval_works() { - with_externalities(&mut ExtBuilder::default().with_council(true).build(), || { - System::set_block_number(1); - let proposal = set_balance_proposal(42); - let hash: H256 = proposal.blake2_256().into(); - assert_ok!(CouncilMotions::propose(Origin::signed(1), 2, Box::new(proposal.clone()))); - assert_ok!(CouncilMotions::vote(Origin::signed(2), hash.clone(), 0, true)); - - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: OuterEvent::motions(RawEvent::Proposed( - 1, - 0, - hex!["cd0b662a49f004093b80600415cf4126399af0d27ed6c185abeb1469c17eb5bf"].into(), - 2, - )), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: OuterEvent::motions(RawEvent::Voted( - 2, - hex!["cd0b662a49f004093b80600415cf4126399af0d27ed6c185abeb1469c17eb5bf"].into(), - true, - 2, - 0, - )), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: OuterEvent::motions(RawEvent::Approved( - hex!["cd0b662a49f004093b80600415cf4126399af0d27ed6c185abeb1469c17eb5bf"].into(), - )), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: OuterEvent::motions(RawEvent::Executed( - hex!["cd0b662a49f004093b80600415cf4126399af0d27ed6c185abeb1469c17eb5bf"].into(), - false, - )), - topics: vec![], - } - ]); - }); - } -} diff --git a/srml/council/src/seats.rs b/srml/council/src/seats.rs deleted file mode 100644 index 84b6f388f29fc61cac7595dd11496ea6b0145eee..0000000000000000000000000000000000000000 --- a/srml/council/src/seats.rs +++ /dev/null @@ -1,2580 +0,0 @@ -// Copyright 2017-2019 Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate 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. - -// Substrate 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 Substrate. If not, see . - -//! Council system: Handles the voting in and maintenance of council members. - -use rstd::prelude::*; -use primitives::traits::{Zero, One, StaticLookup, Bounded, Saturating}; -use runtime_io::print; -use srml_support::{ - StorageValue, StorageMap, - dispatch::Result, decl_storage, decl_event, ensure, decl_module, - traits::{ - Currency, ReservableCurrency, OnUnbalanced, LockIdentifier, - LockableCurrency, WithdrawReasons, WithdrawReason, ExistenceRequirement - } -}; -use democracy; -use parity_codec::{Encode, Decode}; -use system::{self, ensure_signed}; -use super::OnMembersChanged; - -// no polynomial attacks: -// -// all unbonded public operations should be constant time. -// all other public operations must be linear time in terms of prior public operations and: -// - those "valid" ones that cost nothing be limited to a constant number per single protected operation -// - the rest costing the same order as the computational complexity -// all protected operations must complete in at most O(public operations) -// -// we assume "beneficial" transactions will have the same access as attack transactions. -// -// any storage requirements should be bonded by the same order as the volume. - -// public operations: -// - express approvals (you pay in a "voter" bond the first time you do this; O(1); one extra DB entry, one DB change) -// - remove active voter (you get your "voter" bond back; O(1); one fewer DB entry, one DB change) -// - remove inactive voter (either you or the target is removed; if the target, you get their "voter" bond back; O(1); one fewer DB entry, one DB change) -// - submit candidacy (you pay a "candidate" bond; O(1); one extra DB entry, two DB changes) -// - present winner/runner-up (you may pay a "presentation" bond of O(voters) if the presentation is invalid; O(voters) compute; ) -// protected operations: -// - remove candidacy (remove all votes for a candidate) (one fewer DB entry, two DB changes) - -// to avoid a potentially problematic case of not-enough approvals prior to voting causing a -// back-to-back votes that have no way of ending, then there's a forced grace period between votes. -// to keep the system as stateless as possible (making it a bit easier to reason about), we just -// restrict when votes can begin to blocks that lie on boundaries (`voting_period`). - -// for an approval vote of C councillors: - -// top K runners-up are maintained between votes. all others are discarded. -// - candidate removed & bond returned when elected. -// - candidate removed & bond burned when discarded. - -// at the point that the vote ends (), all voters' balances are snapshotted. - -// for B blocks following, there's a counting period whereby each of the candidates that believe -// they fall in the top K+C voted can present themselves. they get the total stake -// recorded (based on the snapshot); an ordered list is maintained (the leaderboard). Noone may -// present themselves that, if elected, would result in being included twice on the council -// (important since existing councillors will have their approval votes as it may be that they -// don't get removed), nor if existing presenters would mean they're not in the top K+C. - -// following B blocks, the top C candidates are elected and have their bond returned. the top C -// candidates and all other candidates beyond the top C+K are cleared. - -// vote-clearing happens lazily; for an approval to count, the most recent vote at the time of the -// voter's most recent vote must be no later than the most recent vote at the time that the -// candidate in the approval position was registered there. as candidates are removed from the -// register and others join in their place, this prevents an approval meant for an earlier candidate -// being used to elect a new candidate. - -// the candidate list increases as needed, but the contents (though not really the capacity) reduce -// after each vote as all but K entries are cleared. newly registering candidates must use cleared -// entries before they increase the capacity. - - -/// The activity status of a voter. -#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, Default)] -#[cfg_attr(feature = "std", derive(Debug))] -pub struct VoterInfo { - /// Last VoteIndex in which this voter assigned (or initialized) approvals. - last_active: VoteIndex, - /// Last VoteIndex in which one of this voter's approvals won. - /// Note that `last_win = N` indicates a last win at index `N-1`, hence `last_win = 0` means no win ever. - last_win: VoteIndex, - /// The amount of stored weight as a result of not winning but changing approvals. - pot: Balance, - /// Current staked amount. A lock equal to this value always exists. - stake: Balance, -} - -/// Used to demonstrate the status of a particular index in the global voter list. -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] -pub enum CellStatus { - /// Any out of bound index. Means a push a must happen to the chunk pointed by `NextVoterSet`. - /// Voting fee is applied in case a new chunk is created. - Head, - /// Already occupied by another voter. Voting fee is applied. - Occupied, - /// Empty hole which should be filled. No fee will be applied. - Hole, -} - -const COUNCIL_SEATS_ID: LockIdentifier = *b"councils"; - -pub const VOTER_SET_SIZE: usize = 64; -pub const APPROVAL_SET_SIZE: usize = 8; - -type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; -type NegativeImbalanceOf = <::Currency as Currency<::AccountId>>::NegativeImbalance; - -type SetIndex = u32; -pub type VoteIndex = u32; - -// all three must be in sync. -type ApprovalFlag = u32; -pub const APPROVAL_FLAG_MASK: ApprovalFlag = 0x8000_0000; -pub const APPROVAL_FLAG_LEN: usize = 32; - -pub trait Trait: democracy::Trait { - type Event: From> + Into<::Event>; - - /// Handler for the unbalanced reduction when slashing a validator. - type BadPresentation: OnUnbalanced>; - - /// Handler for the unbalanced reduction when slashing an invalid reaping attempt. - type BadReaper: OnUnbalanced>; - - /// Handler for the unbalanced reduction when submitting a bad `voter_index`. - type BadVoterIndex: OnUnbalanced>; - - /// Handler for the unbalanced reduction when a candidate has lost (and is not a runner up) - type LoserCandidate: OnUnbalanced>; - /// What to do when the members change. - type OnMembersChanged: OnMembersChanged; -} - -decl_module! { - pub struct Module for enum Call where origin: T::Origin { - fn deposit_event() = default; - - /// Set candidate approvals. Approval slots stay valid as long as candidates in those slots - /// are registered. - /// - /// Locks the total balance of caller indefinitely. - /// Only [`retract_voter`] or [`reap_inactive_voter`] can unlock the balance. - /// - /// `hint` argument is interpreted differently based on: - /// - if `origin` is setting approvals for the first time: The index will be checked - /// for being a valid _hole_ in the voter list. - /// - if the hint is correctly pointing to a hole, no fee is deducted from `origin`. - /// - Otherwise, the call will succeed but the index is ignored and simply a push to the last chunk - /// with free space happens. If the new push causes a new chunk to be created, a fee indicated by - /// [`VotingFee`] is deducted. - /// - if `origin` is already a voter: the index __must__ be valid and point to the correct - /// position of the `origin` in the current voters list. - /// - /// Note that any trailing `false` votes in `votes` is ignored; In approval voting, not voting for a candidate - /// and voting false, are equal. - /// - /// # - /// - O(1). - /// - Two extra DB entries, one DB change. - /// - Argument `votes` is limited in length to number of candidates. - /// # - fn set_approvals(origin, votes: Vec, #[compact] index: VoteIndex, hint: SetIndex) -> Result { - let who = ensure_signed(origin)?; - Self::do_set_approvals(who, votes, index, hint) - } - - /// Set candidate approvals from a proxy. Approval slots stay valid as long as candidates in those slots - /// are registered. - /// - /// # - /// - Same as `set_approvals` with one additional storage read. - /// # - fn proxy_set_approvals(origin, votes: Vec, #[compact] index: VoteIndex, hint: SetIndex) -> Result { - let who = >::proxy(ensure_signed(origin)?).ok_or("not a proxy")?; - Self::do_set_approvals(who, votes, index, hint) - } - - /// Remove a voter. For it not to be a bond-consuming no-op, all approved candidate indices - /// must now be either unregistered or registered to a candidate that registered the slot after - /// the voter gave their last approval set. - /// - /// Both indices must be provided as explained in [`voter_at`] function. - /// - /// May be called by anyone. Returns the voter deposit to `signed`. - /// - /// # - /// - O(1). - /// - Two fewer DB entries, one DB change. - /// # - fn reap_inactive_voter( - origin, - #[compact] reporter_index: u32, - who: ::Source, - #[compact] who_index: u32, - #[compact] assumed_vote_index: VoteIndex - ) { - let reporter = ensure_signed(origin)?; - let who = T::Lookup::lookup(who)?; - - ensure!(!Self::presentation_active(), "cannot reap during presentation period"); - ensure!(Self::voter_info(&reporter).is_some(), "reporter must be a voter"); - - let info = Self::voter_info(&who).ok_or("target for inactivity cleanup must be active")?; - let last_active = info.last_active; - - ensure!(assumed_vote_index == Self::vote_index(), "vote index not current"); - ensure!( - assumed_vote_index > last_active+ Self::inactivity_grace_period(), - "cannot reap during grace period" - ); - - let reporter_index = reporter_index as usize; - let who_index = who_index as usize; - let assumed_reporter = Self::voter_at(reporter_index).ok_or("invalid reporter index")?; - let assumed_who = Self::voter_at(who_index).ok_or("invalid target index")?; - - ensure!(assumed_reporter == reporter, "bad reporter index"); - ensure!(assumed_who == who, "bad target index"); - - // will definitely kill one of reporter or who now. - - let valid = !Self::all_approvals_of(&who).iter() - .zip(Self::candidates().iter()) - .any(|(&appr, addr)| - appr && - *addr != T::AccountId::default() && - // defensive only: all items in candidates list are registered - Self::candidate_reg_info(addr).map_or(false, |x| x.0 <= last_active) - ); - - Self::remove_voter( - if valid { &who } else { &reporter }, - if valid { who_index } else { reporter_index } - ); - - T::Currency::remove_lock( - COUNCIL_SEATS_ID, - if valid { &who } else { &reporter } - ); - - if valid { - // This only fails if `reporter` doesn't exist, which it clearly must do since its the origin. - // Still, it's no more harmful to propagate any error at this point. - T::Currency::repatriate_reserved(&who, &reporter, Self::voting_bond())?; - Self::deposit_event(RawEvent::VoterReaped(who, reporter)); - } else { - let imbalance = T::Currency::slash_reserved(&reporter, Self::voting_bond()).0; - T::BadReaper::on_unbalanced(imbalance); - Self::deposit_event(RawEvent::BadReaperSlashed(reporter)); - } - } - - /// Remove a voter. All votes are cancelled and the voter deposit is returned. - /// - /// The index must be provided as explained in [`voter_at`] function. - /// - /// Also removes the lock on the balance of the voter. See [`do_set_approvals()`]. - /// - /// # - /// - O(1). - /// - Two fewer DB entries, one DB change. - /// # - fn retract_voter(origin, #[compact] index: u32) { - let who = ensure_signed(origin)?; - - ensure!(!Self::presentation_active(), "cannot retract when presenting"); - ensure!(>::exists(&who), "cannot retract non-voter"); - let index = index as usize; - let voter = Self::voter_at(index).ok_or("retraction index invalid")?; - ensure!(voter == who, "retraction index mismatch"); - - Self::remove_voter(&who, index); - T::Currency::unreserve(&who, Self::voting_bond()); - T::Currency::remove_lock(COUNCIL_SEATS_ID, &who); - } - - /// Submit oneself for candidacy. - /// - /// Account must have enough transferrable funds in it to pay the bond. - /// - /// NOTE: if `origin` has already assigned approvals via [`set_approvals`], - /// it will NOT have any usable funds to pass candidacy bond and must first retract. - /// Note that setting approvals will lock the entire balance of the voter until - /// retraction or being reported. - /// - /// # - /// - Independent of input. - /// - Three DB changes. - /// # - fn submit_candidacy(origin, #[compact] slot: u32) { - let who = ensure_signed(origin)?; - - ensure!(!Self::is_a_candidate(&who), "duplicate candidate submission"); - let slot = slot as usize; - let count = Self::candidate_count() as usize; - let candidates = Self::candidates(); - ensure!( - (slot == count && count == candidates.len()) || - (slot < candidates.len() && candidates[slot] == T::AccountId::default()), - "invalid candidate slot" - ); - // NOTE: This must be last as it has side-effects. - T::Currency::reserve(&who, Self::candidacy_bond()) - .map_err(|_| "candidate has not enough funds")?; - - >::insert(&who, (Self::vote_index(), slot as u32)); - let mut candidates = candidates; - if slot == candidates.len() { - candidates.push(who); - } else { - candidates[slot] = who; - } - >::put(candidates); - >::put(count as u32 + 1); - } - - /// Claim that `signed` is one of the top Self::carry_count() + current_vote().1 candidates. - /// Only works if the `block_number >= current_vote().0` and `< current_vote().0 + presentation_duration()` - /// `signed` should have at least - /// - /// # - /// - O(voters) compute. - /// - One DB change. - /// # - fn present_winner( - origin, - candidate: ::Source, - #[compact] total: BalanceOf, - #[compact] index: VoteIndex - ) -> Result { - let who = ensure_signed(origin)?; - ensure!( - !total.is_zero(), - "stake deposited to present winner and be added to leaderboard should be non-zero" - ); - - let candidate = T::Lookup::lookup(candidate)?; - ensure!(index == Self::vote_index(), "index not current"); - let (_, _, expiring) = Self::next_finalize().ok_or("cannot present outside of presentation period")?; - let bad_presentation_punishment = - Self::present_slash_per_voter() - * BalanceOf::::from(Self::voter_count() as u32); - ensure!( - T::Currency::can_slash(&who, bad_presentation_punishment), - "presenter must have sufficient slashable funds" - ); - - let mut leaderboard = Self::leaderboard().ok_or("leaderboard must exist while present phase active")?; - ensure!(total > leaderboard[0].0, "candidate not worthy of leaderboard"); - - if let Some(p) = Self::active_council().iter().position(|&(ref c, _)| c == &candidate) { - ensure!(p < expiring.len(), "candidate must not form a duplicated member if elected"); - } - - let voters = Self::all_voters(); - let (registered_since, candidate_index): (VoteIndex, u32) = - Self::candidate_reg_info(&candidate).ok_or("presented candidate must be current")?; - let actual_total = voters.iter() - .filter_map(|maybe_voter| maybe_voter.as_ref()) - .filter_map(|voter| match Self::voter_info(voter) { - Some(b) if b.last_active >= registered_since => { - let last_win = b.last_win; - let now = Self::vote_index(); - let stake = b.stake; - let offset = Self::get_offset(stake, now - last_win); - let weight = stake + offset + b.pot; - if Self::approvals_of_at(voter, candidate_index as usize) { - Some(weight) - } else { None } - }, - _ => None, - }) - .fold(Zero::zero(), |acc, n| acc + n); - let dupe = leaderboard.iter().find(|&&(_, ref c)| c == &candidate).is_some(); - if total == actual_total && !dupe { - // insert into leaderboard - leaderboard[0] = (total, candidate); - leaderboard.sort_by_key(|&(t, _)| t); - >::put(leaderboard); - Ok(()) - } else { - // we can rest assured it will be Ok since we checked `can_slash` earlier; still - // better safe than sorry. - let imbalance = T::Currency::slash(&who, bad_presentation_punishment).0; - T::BadPresentation::on_unbalanced(imbalance); - Err(if dupe { "duplicate presentation" } else { "incorrect total" }) - } - } - - /// Set the desired member count; if lower than the current count, then seats will not be up - /// election when they expire. If more, then a new vote will be started if one is not - /// already in progress. - fn set_desired_seats(#[compact] count: u32) { - >::put(count); - } - - /// Remove a particular member from the council. This is effective immediately. - /// - /// Note: A tally should happen instantly (if not already in a presentation - /// period) to fill the seat if removal means that the desired members are not met. - fn remove_member(who: ::Source) { - let who = T::Lookup::lookup(who)?; - let new_council: Vec<(T::AccountId, T::BlockNumber)> = Self::active_council() - .into_iter() - .filter(|i| i.0 != who) - .collect(); - >::put(new_council); - T::OnMembersChanged::on_members_changed(&[], &[who]); - } - - /// Set the presentation duration. If there is currently a vote being presented for, will - /// invoke `finalize_vote`. - fn set_presentation_duration(#[compact] count: T::BlockNumber) { - >::put(count); - } - - /// Set the presentation duration. If there is current a vote being presented for, will - /// invoke `finalize_vote`. - fn set_term_duration(#[compact] count: T::BlockNumber) { - >::put(count); - } - - fn on_initialize(n: T::BlockNumber) { - if let Err(e) = Self::end_block(n) { - print("Guru meditation"); - print(e); - } - } - } -} - -decl_storage! { - trait Store for Module as Council { - - // ---- parameters - /// How much should be locked up in order to submit one's candidacy. - pub CandidacyBond get(candidacy_bond) config(): BalanceOf = 9.into(); - /// How much should be locked up in order to be able to submit votes. - pub VotingBond get(voting_bond) config(voter_bond): BalanceOf; - /// The amount of fee paid upon each vote submission, unless if they submit a _hole_ index and replace it. - pub VotingFee get(voting_fee) config(voting_fee): BalanceOf; - /// The punishment, per voter, if you provide an invalid presentation. - pub PresentSlashPerVoter get(present_slash_per_voter) config(): BalanceOf = 1.into(); - /// How many runners-up should have their approvals persist until the next vote. - pub CarryCount get(carry_count) config(): u32 = 2; - /// How long to give each top candidate to present themselves after the vote ends. - pub PresentationDuration get(presentation_duration) config(): T::BlockNumber = 1000.into(); - /// How many vote indices need to go by after a target voter's last vote before they can be reaped if their - /// approvals are moot. - pub InactiveGracePeriod get(inactivity_grace_period) config(inactive_grace_period): VoteIndex = 1; - /// How often (in blocks) to check for new votes. - pub VotingPeriod get(voting_period) config(approval_voting_period): T::BlockNumber = 1000.into(); - /// How long each position is active for. - pub TermDuration get(term_duration) config(): T::BlockNumber = 5.into(); - /// Number of accounts that should be sitting on the council. - pub DesiredSeats get(desired_seats) config(): u32; - /// Decay factor of weight when being accumulated. It should typically be set to - /// __at least__ `council_size -1` to keep the council secure. - /// When set to `N`, it indicates `(1/N)^t` of staked is decayed at weight increment step `t`. - /// 0 will result in no weight being added at all (normal approval voting). - pub DecayRatio get(decay_ratio) config(decay_ratio): u32 = 24; - - // ---- permanent state (always relevant, changes only at the finalization of voting) - /// The current council. When there's a vote going on, this should still be used for executive - /// matters. The block number (second element in the tuple) is the block that their position is - /// active until (calculated by the sum of the block number when the council member was elected - /// and their term duration). - pub ActiveCouncil get(active_council) config(): Vec<(T::AccountId, T::BlockNumber)>; - /// The total number of vote rounds that have happened or are in progress. - pub VoteCount get(vote_index): VoteIndex; - - // ---- persistent state (always relevant, changes constantly) - /// A list of votes for each voter. The votes are stored as numeric values and parsed in a bit-wise manner. - /// - /// In order to get a human-readable representation (`Vec`), use [`all_approvals_of`]. - /// - /// Furthermore, each vector of scalars is chunked with the cap of `APPROVAL_SET_SIZE`. - pub ApprovalsOf get(approvals_of): map (T::AccountId, SetIndex) => Vec; - /// The vote index and list slot that the candidate `who` was registered or `None` if they are not - /// currently registered. - pub RegisterInfoOf get(candidate_reg_info): map T::AccountId => Option<(VoteIndex, u32)>; - /// Basic information about a voter. - pub VoterInfoOf get(voter_info): map T::AccountId => Option>>; - /// The present voter list (chunked and capped at [`VOTER_SET_SIZE`]). - pub Voters get(voters): map SetIndex => Vec>; - /// the next free set to store a voter in. This will keep growing. - pub NextVoterSet get(next_nonfull_voter_set): SetIndex = 0; - /// Current number of Voters. - pub VoterCount get(voter_count): SetIndex = 0; - /// The present candidate list. - pub Candidates get(candidates): Vec; // has holes - /// Current number of active candidates - pub CandidateCount get(candidate_count): u32; - - // ---- temporary state (only relevant during finalization/presentation) - /// The accounts holding the seats that will become free on the next tally. - pub NextFinalize get(next_finalize): Option<(T::BlockNumber, u32, Vec)>; - /// Get the leaderboard if we're in the presentation phase. The first element is the weight of each entry; - /// It may be the direct summed approval stakes, or a weighted version of it. - pub Leaderboard get(leaderboard): Option, T::AccountId)> >; // ORDERED low -> high - } -} - -decl_event!( - pub enum Event where ::AccountId { - /// reaped voter, reaper - VoterReaped(AccountId, AccountId), - /// slashed reaper - BadReaperSlashed(AccountId), - /// A tally (for approval votes of council seat(s)) has started. - TallyStarted(u32), - /// A tally (for approval votes of council seat(s)) has ended (with one or more new members). - TallyFinalized(Vec, Vec), - } -); - -impl Module { - // exposed immutables. - - /// True if we're currently in a presentation period. - pub fn presentation_active() -> bool { - >::exists() - } - - /// If `who` a candidate at the moment? - pub fn is_a_candidate(who: &T::AccountId) -> bool { - >::exists(who) - } - - /// Iff the councillor `who` still has a seat at blocknumber `n` returns `true`. - pub fn will_still_be_councillor_at(who: &T::AccountId, n: T::BlockNumber) -> bool { - Self::active_council().iter() - .find(|&&(ref a, _)| a == who) - .map(|&(_, expires)| expires > n) - .unwrap_or(false) - } - - /// Determine the block that a vote can happen on which is no less than `n`. - pub fn next_vote_from(n: T::BlockNumber) -> T::BlockNumber { - let voting_period = Self::voting_period(); - (n + voting_period - One::one()) / voting_period * voting_period - } - - /// The block number on which the tally for the next election will happen. `None` only if the - /// desired seats of the council is zero. - pub fn next_tally() -> Option { - let desired_seats = Self::desired_seats(); - if desired_seats == 0 { - None - } else { - let c = Self::active_council(); - let (next_possible, count, coming) = - if let Some((tally_end, comers, leavers)) = Self::next_finalize() { - // if there's a tally in progress, then next tally can begin immediately afterwards - (tally_end, c.len() - leavers.len() + comers as usize, comers) - } else { - (>::block_number(), c.len(), 0) - }; - if count < desired_seats as usize { - Some(next_possible) - } else { - // next tally begins once enough council members expire to bring members below desired. - if desired_seats <= coming { - // the entire amount of desired seats is less than those new members - we'll have - // to wait until they expire. - Some(next_possible + Self::term_duration()) - } else { - Some(c[c.len() - (desired_seats - coming) as usize].1) - } - }.map(Self::next_vote_from) - } - } - - // Private - /// Check there's nothing to do this block - fn end_block(block_number: T::BlockNumber) -> Result { - if (block_number % Self::voting_period()).is_zero() { - if let Some(number) = Self::next_tally() { - if block_number == number { - Self::start_tally(); - } - } - } - if let Some((number, _, _)) = Self::next_finalize() { - if block_number == number { - Self::finalize_tally()? - } - } - Ok(()) - } - - /// Remove a voter at a specified index from the system. - fn remove_voter(voter: &T::AccountId, index: usize) { - let (set_index, vec_index) = Self::split_index(index, VOTER_SET_SIZE); - let mut set = Self::voters(set_index); - set[vec_index] = None; - >::insert(set_index, set); - >::mutate(|c| *c = *c - 1); - Self::remove_all_approvals_of(voter); - >::remove(voter); - } - - /// Actually do the voting. - /// - /// The voter index must be provided as explained in [`voter_at`] function. - fn do_set_approvals(who: T::AccountId, votes: Vec, index: VoteIndex, hint: SetIndex) -> Result { - let candidates = Self::candidates(); - - ensure!(!Self::presentation_active(), "no approval changes during presentation period"); - ensure!(index == Self::vote_index(), "incorrect vote index"); - ensure!(!candidates.is_empty(), "amount of candidates to receive approval votes should be non-zero"); - // Prevent a vote from voters that provide a list of votes that exceeds the candidates length - // since otherwise an attacker may be able to submit a very long list of `votes` that far exceeds - // the amount of candidates and waste more computation than a reasonable voting bond would cover. - ensure!(candidates.len() >= votes.len(), "amount of candidate votes cannot exceed amount of candidates"); - - // Amount to be locked up. - let mut locked_balance = T::Currency::total_balance(&who); - let mut pot_to_set = Zero::zero(); - let hint = hint as usize; - - if let Some(info) = Self::voter_info(&who) { - // already a voter. Index must be valid. No fee. update pot. O(1) - let voter = Self::voter_at(hint).ok_or("invalid voter index")?; - ensure!(voter == who, "wrong voter index"); - - // write new accumulated offset. - let last_win = info.last_win; - let now = index; - let offset = Self::get_offset(info.stake, now - last_win); - pot_to_set = info.pot + offset; - } else { - // not yet a voter. Index _could be valid_. Fee might apply. Bond will be reserved O(1). - ensure!( - T::Currency::free_balance(&who) > Self::voting_bond(), - "new voter must have sufficient funds to pay the bond" - ); - - let (set_index, vec_index) = Self::split_index(hint, VOTER_SET_SIZE); - match Self::cell_status(set_index, vec_index) { - CellStatus::Hole => { - // requested cell was a valid hole. - >::mutate(set_index, |set| set[vec_index] = Some(who.clone())); - }, - CellStatus::Head | CellStatus::Occupied => { - // Either occupied or out-of-range. - let next = Self::next_nonfull_voter_set(); - let mut set = Self::voters(next); - // Caused a new set to be created. Pay for it. - // This is the last potential error. Writes will begin afterwards. - if set.is_empty() { - let imbalance = T::Currency::withdraw( - &who, - Self::voting_fee(), - WithdrawReason::Fee, - ExistenceRequirement::KeepAlive, - )?; - T::BadVoterIndex::on_unbalanced(imbalance); - // NOTE: this is safe since the `withdraw()` will check this. - locked_balance -= Self::voting_fee(); - } - Self::checked_push_voter(&mut set, who.clone(), next); - >::insert(next, set); - } - } - - T::Currency::reserve(&who, Self::voting_bond())?; - >::mutate(|c| *c = *c + 1); - } - - T::Currency::set_lock( - COUNCIL_SEATS_ID, - &who, - locked_balance, - T::BlockNumber::max_value(), - WithdrawReasons::all() - ); - - >::insert( - &who, - VoterInfo::> { - last_active: index, - last_win: index, - stake: locked_balance, - pot: pot_to_set, - } - ); - Self::set_approvals_chunked(&who, votes); - - Ok(()) - } - - /// Close the voting, record the number of seats that are actually up for grabs. - fn start_tally() { - let active_council = Self::active_council(); - let desired_seats = Self::desired_seats() as usize; - let number = >::block_number(); - let expiring = active_council.iter().take_while(|i| i.1 <= number).map(|i| i.0.clone()).collect::>(); - let retaining_seats = active_council.len() - expiring.len(); - if retaining_seats < desired_seats { - let empty_seats = desired_seats - retaining_seats; - >::put((number + Self::presentation_duration(), empty_seats as u32, expiring)); - - // initialize leaderboard. - let leaderboard_size = empty_seats + Self::carry_count() as usize; - >::put(vec![(Zero::zero(), T::AccountId::default()); leaderboard_size]); - - Self::deposit_event(RawEvent::TallyStarted(empty_seats as u32)); - } - } - - /// Finalize the vote, removing each of the `removals` and inserting `seats` of the most approved - /// candidates in their place. If the total council members is less than the desired membership - /// a new vote is started. - /// Clears all presented candidates, returning the bond of the elected ones. - fn finalize_tally() -> Result { - let (_, coming, expiring): (T::BlockNumber, u32, Vec) = - >::take().ok_or("finalize can only be called after a tally is started.")?; - let leaderboard: Vec<(BalanceOf, T::AccountId)> = >::take().unwrap_or_default(); - let new_expiry = >::block_number() + Self::term_duration(); - - // return bond to winners. - let candidacy_bond = Self::candidacy_bond(); - let incoming: Vec<_> = leaderboard.iter() - .rev() - .take_while(|&&(b, _)| !b.is_zero()) - .take(coming as usize) - .map(|(_, a)| a) - .cloned() - .inspect(|a| { T::Currency::unreserve(a, candidacy_bond); }) - .collect(); - - // Update last win index for anyone voted for any of the incomings. - incoming.iter().filter_map(|i| Self::candidate_reg_info(i)).for_each(|r| { - let index = r.1 as usize; - Self::all_voters() - .iter() - .filter_map(|mv| mv.as_ref()) - .filter(|v| Self::approvals_of_at(*v, index)) - .for_each(|v| >::mutate(v, |a| { - if let Some(activity) = a { activity.last_win = Self::vote_index() + 1; } - })); - }); - let active_council = Self::active_council(); - let outgoing: Vec<_> = active_council.iter() - .take(expiring.len()) - .map(|a| a.0.clone()).collect(); - - // set the new council. - let mut new_council: Vec<_> = active_council - .into_iter() - .skip(expiring.len()) - .chain(incoming.iter().cloned().map(|a| (a, new_expiry))) - .collect(); - new_council.sort_by_key(|&(_, expiry)| expiry); - >::put(new_council); - - T::OnMembersChanged::on_members_changed(&incoming, &outgoing); - - // clear all except runners-up from candidate list. - let candidates = Self::candidates(); - let mut new_candidates = vec![T::AccountId::default(); candidates.len()]; // shrink later. - let runners_up = leaderboard.into_iter() - .rev() - .take_while(|&(b, _)| !b.is_zero()) - .skip(coming as usize) - .filter_map(|(_, a)| Self::candidate_reg_info(&a).map(|i| (a, i.1))); - let mut count = 0u32; - for (address, slot) in runners_up { - new_candidates[slot as usize] = address; - count += 1; - } - for (old, new) in candidates.iter().zip(new_candidates.iter()) { - if old != new { - // removed - kill it - >::remove(old); - } - } - // discard any superfluous slots. - if let Some(last_index) = new_candidates.iter().rposition(|c| *c != T::AccountId::default()) { - new_candidates.truncate(last_index + 1); - } - - Self::deposit_event(RawEvent::TallyFinalized(incoming, outgoing)); - - >::put(new_candidates); - >::put(count); - >::put(Self::vote_index() + 1); - Ok(()) - } - - fn checked_push_voter(set: &mut Vec>, who: T::AccountId, index: u32) { - let len = set.len(); - - // Defensive only: this should never happen. Don't push since it will break more things. - if len == VOTER_SET_SIZE { return; } - - set.push(Some(who)); - if len + 1 == VOTER_SET_SIZE { - >::put(index + 1); - } - } - - /// Get the set and vector index of a global voter index. - /// - /// Note that this function does not take holes into account. - /// See [`voter_at`]. - fn split_index(index: usize, scale: usize) -> (SetIndex, usize) { - let set_index = (index / scale) as u32; - let vec_index = index % scale; - (set_index, vec_index) - } - - /// Return a concatenated vector over all voter sets. - fn all_voters() -> Vec> { - let mut all = >::get(0); - let mut index = 1; - // NOTE: we could also use `Self::next_nonfull_voter_set()` here but that might change based - // on how we do chunking. This is more generic. - loop { - let next_set = >::get(index); - if next_set.is_empty() { - break; - } else { - index += 1; - all.extend(next_set); - } - } - all - } - - /// Shorthand for fetching a voter at a specific (global) index. - /// - /// NOTE: this function is used for checking indices. Yet, it does not take holes into account. - /// This means that any account submitting an index at any point in time should submit: - /// `VOTER_SET_SIZE * set_index + local_index`, meaning that you are ignoring all holes in the - /// first `set_index` sets. - fn voter_at(index: usize) -> Option { - let (set_index, vec_index) = Self::split_index(index, VOTER_SET_SIZE); - let set = Self::voters(set_index); - if vec_index < set.len() { - set[vec_index].clone() - } else { - None - } - } - - /// A more sophisticated version of `voter_at`. Will be kept separate as most often it is an overdue - /// compared to `voter_at`. Only used when setting approvals. - fn cell_status(set_index: SetIndex, vec_index: usize) -> CellStatus { - let set = Self::voters(set_index); - if vec_index < set.len() { - if let Some(_) = set[vec_index] { - CellStatus::Occupied - } else { - CellStatus::Hole - } - } else { - CellStatus::Head - } - } - - /// Sets the approval of a voter in a chunked manner. - fn set_approvals_chunked(who: &T::AccountId, approvals: Vec) { - let approvals_flag_vec = Self::bool_to_flag(approvals); - approvals_flag_vec - .chunks(APPROVAL_SET_SIZE) - .enumerate() - .for_each(|(index, slice)| >::insert((who.clone(), index as SetIndex), slice.to_vec())); - } - - /// shorthand for fetching a specific approval of a voter at a specific (global) index. - /// - /// Using this function to read a vote is preferred as it reads `APPROVAL_SET_SIZE` items of type - /// `ApprovalFlag` from storage at most; not all of them. - /// - /// Note that false is returned in case of no-vote or an explicit `false`. - fn approvals_of_at(who: &T::AccountId, index: usize) -> bool { - let (flag_index, bit) = Self::split_index(index, APPROVAL_FLAG_LEN); - let (set_index, vec_index) = Self::split_index(flag_index as usize, APPROVAL_SET_SIZE); - let set = Self::approvals_of((who.clone(), set_index)); - if vec_index < set.len() { - // This is because bit_at treats numbers in lsb -> msb order. - let reversed_index = set.len() - 1 - vec_index; - Self::bit_at(set[reversed_index], bit) - } else { - false - } - } - - /// Return true of the bit `n` of scalar `x` is set to `1` and false otherwise. - fn bit_at(x: ApprovalFlag, n: usize) -> bool { - if n < APPROVAL_FLAG_LEN { - // x & ( APPROVAL_FLAG_MASK >> n ) != 0 - x & ( 1 << n ) != 0 - } else { - false - } - } - - /// Convert a vec of boolean approval flags to a vec of integers, as denoted by - /// the type `ApprovalFlag`. see `bool_to_flag_should_work` test for examples. - pub fn bool_to_flag(x: Vec) -> Vec { - let mut result: Vec = Vec::with_capacity(x.len() / APPROVAL_FLAG_LEN); - if x.is_empty() { - return result; - } - result.push(0); - let mut index = 0; - let mut counter = 0; - loop { - let shl_index = counter % APPROVAL_FLAG_LEN; - result[index] += (if x[counter] { 1 } else { 0 }) << shl_index; - counter += 1; - if counter > x.len() - 1 { break; } - if counter % APPROVAL_FLAG_LEN == 0 { - result.push(0); - index += 1; - } - } - result - } - - /// Convert a vec of flags (u32) to boolean. - pub fn flag_to_bool(chunk: Vec) -> Vec { - let mut result = Vec::with_capacity(chunk.len()); - if chunk.is_empty() { return vec![] } - chunk.into_iter() - .map(|num| (0..APPROVAL_FLAG_LEN).map(|bit| Self::bit_at(num, bit)).collect::>()) - .for_each(|c| { - let last_approve = match c.iter().rposition(|n| *n) { - Some(index) => index + 1, - None => 0 - }; - result.extend(c.into_iter().take(last_approve)); - }); - result - } - - /// Return a concatenated vector over all approvals of a voter as boolean. - /// The trailing zeros are removed. - fn all_approvals_of(who: &T::AccountId) -> Vec { - let mut all: Vec = vec![]; - let mut index = 0_u32; - loop { - let chunk = Self::approvals_of((who.clone(), index)); - if chunk.is_empty() { break; } - all.extend(Self::flag_to_bool(chunk)); - index += 1; - } - all - } - - /// Remove all approvals associated with one account. - fn remove_all_approvals_of(who: &T::AccountId) { - let mut index = 0; - loop { - let set = Self::approvals_of((who.clone(), index)); - if set.len() > 0 { - >::remove((who.clone(), index)); - index += 1; - } else { - break - } - } - } - - /// Calculates the offset value (stored pot) of a stake, based on the distance - /// to the last win_index, `t`. Regardless of the internal implementation, - /// it should always be used with the following structure: - /// - /// Given Stake of voter `V` being `x` and distance to last_win index `t`, the new weight - /// of `V` is `x + get_offset(x, t)`. - /// - /// In other words, this function returns everything extra that should be added - /// to a voter's stake value to get the correct weight. Indeed, zero is - /// returned if `t` is zero. - fn get_offset(stake: BalanceOf, t: VoteIndex) -> BalanceOf { - let decay_ratio: BalanceOf = Self::decay_ratio().into(); - if t > 150 { return stake * decay_ratio } - let mut offset = stake; - let mut r = Zero::zero(); - let decay = decay_ratio + One::one(); - for _ in 0..t { - offset = offset.saturating_sub(offset / decay); - r += offset - } - r - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::tests::*; - use srml_support::{assert_ok, assert_noop, assert_err}; - - fn voter_ids() -> Vec { - Council::all_voters().iter().map(|v| v.unwrap_or(0) ).collect::>() - } - - fn vote(i: u64, l: usize) { - let _ = Balances::make_free_balance_be(&i, 20); - assert_ok!(Council::set_approvals(Origin::signed(i), (0..l).map(|_| true).collect::>(), 0, 0)); - } - - fn vote_at(i: u64, l: usize, index: VoteIndex) { - let _ = Balances::make_free_balance_be(&i, 20); - assert_ok!(Council::set_approvals(Origin::signed(i), (0..l).map(|_| true).collect::>(), 0, index)); - } - - fn create_candidate(i: u64, index: u32) { - let _ = Balances::make_free_balance_be(&i, 20); - assert_ok!(Council::submit_candidacy(Origin::signed(i), index)); - } - - fn bond() -> u64 { - Council::voting_bond() - } - - - #[test] - fn bool_to_flag_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - assert_eq!(Council::bool_to_flag(vec![]), vec![]); - assert_eq!(Council::bool_to_flag(vec![false]), vec![0]); - assert_eq!(Council::bool_to_flag(vec![true]), vec![1]); - assert_eq!(Council::bool_to_flag(vec![true, true, true, true]), vec![15]); - assert_eq!(Council::bool_to_flag(vec![true, true, true, true, true]), vec![15 + 16]); - - let set_1 = vec![ - true, false, false, false, // 0x1 - false, true, true, true, // 0xE - ]; - assert_eq!( - Council::bool_to_flag(set_1.clone()), - vec![0x00_00_00_E1_u32] - ); - assert_eq!( - Council::flag_to_bool(vec![0x00_00_00_E1_u32]), - set_1 - ); - - let set_2 = vec![ - false, false, false, true, // 0x8 - false, true, false, true, // 0xA - ]; - assert_eq!( - Council::bool_to_flag(set_2.clone()), - vec![0x00_00_00_A8_u32] - ); - assert_eq!( - Council::flag_to_bool(vec![0x00_00_00_A8_u32]), - set_2 - ); - - let mut rhs = (0..100/APPROVAL_FLAG_LEN).map(|_| 0xFFFFFFFF_u32).collect::>(); - // NOTE: this might be need change based on `APPROVAL_FLAG_LEN`. - rhs.extend(vec![0x00_00_00_0F]); - assert_eq!( - Council::bool_to_flag((0..100).map(|_| true).collect()), - rhs - ) - }) - } - - #[test] - fn params_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(1); - assert_eq!(Council::next_vote_from(1), 4); - assert_eq!(Council::next_vote_from(4), 4); - assert_eq!(Council::next_vote_from(5), 8); - assert_eq!(Council::vote_index(), 0); - assert_eq!(Council::candidacy_bond(), 3); - assert_eq!(Council::voting_bond(), 0); - assert_eq!(Council::voting_fee(), 0); - assert_eq!(Council::present_slash_per_voter(), 1); - assert_eq!(Council::presentation_duration(), 2); - assert_eq!(Council::inactivity_grace_period(), 1); - assert_eq!(Council::voting_period(), 4); - assert_eq!(Council::term_duration(), 5); - assert_eq!(Council::desired_seats(), 2); - assert_eq!(Council::carry_count(), 2); - - assert_eq!(Council::active_council(), vec![]); - assert_eq!(Council::next_tally(), Some(4)); - assert_eq!(Council::presentation_active(), false); - assert_eq!(Council::next_finalize(), None); - - assert_eq!(Council::candidates(), Vec::::new()); - assert_eq!(Council::is_a_candidate(&1), false); - assert_eq!(Council::candidate_reg_info(1), None); - - assert_eq!(Council::voters(0), Vec::>::new()); - assert_eq!(Council::voter_info(1), None); - assert_eq!(Council::all_approvals_of(&1), vec![]); - }); - } - - #[test] - fn voter_set_growth_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(3), 1)); - - // create 65. 64 (set0) + 1 (set1) - (1..=63).for_each(|i| vote(i, 2)); - assert_eq!(Council::next_nonfull_voter_set(), 0); - vote(64, 2); - assert_eq!(Council::next_nonfull_voter_set(), 1); - vote(65, 2); - - let set1 = Council::voters(0); - let set2 = Council::voters(1); - - assert_eq!(set1.len(), 64); - assert_eq!(set2.len(), 1); - - assert_eq!(set1[0], Some(1)); - assert_eq!(set1[10], Some(11)); - assert_eq!(set2[0], Some(65)); - }) - } - - #[test] - fn voter_set_reclaim_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(3), 1)); - - (1..=129).for_each(|i| vote(i, 2)); - assert_eq!(Council::next_nonfull_voter_set(), 2); - - assert_ok!(Council::retract_voter(Origin::signed(11), 10)); - - assert_ok!(Council::retract_voter(Origin::signed(66), 65)); - assert_ok!(Council::retract_voter(Origin::signed(67), 66)); - - // length does not show it but holes do exist. - assert_eq!(Council::voters(0).len(), 64); - assert_eq!(Council::voters(1).len(), 64); - assert_eq!(Council::voters(2).len(), 1); - - assert_eq!(Council::voters(0)[10], None); - assert_eq!(Council::voters(1)[1], None); - assert_eq!(Council::voters(1)[2], None); - // Next set with capacity is 2. - assert_eq!(Council::next_nonfull_voter_set(), 2); - - // But we can fill a hole. - vote_at(130, 2, 10); - - // Nothing added to set 2. A hole was filled. - assert_eq!(Council::voters(0).len(), 64); - assert_eq!(Council::voters(1).len(), 64); - assert_eq!(Council::voters(2).len(), 1); - - // and the next two (scheduled) to the second set. - assert_eq!(Council::next_nonfull_voter_set(), 2); - }) - } - - #[test] - fn approvals_set_growth_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - // create candidates and voters. - (1..=250).for_each(|i| create_candidate(i, (i-1) as u32)); - (1..=250).for_each(|i| vote(i, i as usize)); - - // all approvals of should return the exact expected vector. - assert_eq!(Council::all_approvals_of(&180), (0..180).map(|_| true).collect::>()); - - assert_eq!(Council::all_approvals_of(&32), (0..32).map(|_| true).collect::>()); - assert_eq!(Council::all_approvals_of(&8), (0..8).map(|_| true).collect::>()); - assert_eq!(Council::all_approvals_of(&64), (0..64).map(|_| true).collect::>()); - assert_eq!(Council::all_approvals_of(&65), (0..65).map(|_| true).collect::>()); - assert_eq!(Council::all_approvals_of(&63), (0..63).map(|_| true).collect::>()); - - // NOTE: assuming that APPROVAL_SET_SIZE is more or less small-ish. Might fail otherwise. - let full_sets = (180 / APPROVAL_FLAG_LEN) / APPROVAL_SET_SIZE; - let left_over = (180 / APPROVAL_FLAG_LEN) / APPROVAL_SET_SIZE; - let rem = 180 % APPROVAL_FLAG_LEN; - - // grab and check the last full set, if it exists. - if full_sets > 0 { - assert_eq!( - Council::approvals_of((180, (full_sets-1) as SetIndex )), - Council::bool_to_flag((0..APPROVAL_SET_SIZE * APPROVAL_FLAG_LEN).map(|_| true).collect::>()) - ); - } - - // grab and check the last, half-empty, set. - if left_over > 0 { - assert_eq!( - Council::approvals_of((180, full_sets as SetIndex)), - Council::bool_to_flag((0..left_over * APPROVAL_FLAG_LEN + rem).map(|_| true).collect::>()) - ); - } - }) - } - - - #[test] - fn cell_status_works() { - with_externalities(&mut ExtBuilder::default().build(), || { - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(3), 1)); - - (1..=63).for_each(|i| vote(i, 2)); - - assert_ok!(Council::retract_voter(Origin::signed(11), 10)); - assert_ok!(Council::retract_voter(Origin::signed(21), 20)); - - assert_eq!(Council::cell_status(0, 10), CellStatus::Hole); - assert_eq!(Council::cell_status(0, 0), CellStatus::Occupied); - assert_eq!(Council::cell_status(0, 20), CellStatus::Hole); - assert_eq!(Council::cell_status(0, 63), CellStatus::Head); - assert_eq!(Council::cell_status(1, 0), CellStatus::Head); - assert_eq!(Council::cell_status(1, 10), CellStatus::Head); - }) - } - - #[test] - fn initial_set_approvals_ignores_voter_index() { - with_externalities(&mut ExtBuilder::default().build(), || { - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - - // Last argument is essentially irrelevant. You might get or miss a tip. - assert_ok!(Council::set_approvals(Origin::signed(3), vec![true], 0, 0)); - assert_ok!(Council::set_approvals(Origin::signed(4), vec![true], 0, 5)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![true], 0, 100)); - - // indices are more or less ignored. all is pushed. - assert_eq!(voter_ids(), vec![3, 4, 5]); - }) - } - - #[test] - fn bad_approval_index_slashes_voters_and_bond_reduces_stake() { - with_externalities(&mut ExtBuilder::default().voting_fee(5).voter_bond(2).build(), || { - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(3), 1)); - - (1..=63).for_each(|i| vote(i, 2)); - assert_eq!(Balances::free_balance(&1), 20 - 5 - 2); // -5 fee -2 bond - assert_eq!(Balances::free_balance(&10), 20 - 2); - assert_eq!(Balances::free_balance(&60), 20 - 2); - - // still no fee - vote(64, 2); - assert_eq!(Balances::free_balance(&64), 20 - 2); // -2 bond - assert_eq!( - Council::voter_info(&64).unwrap(), - VoterInfo { last_win: 0, last_active: 0, stake: 20, pot:0 } - ); - - assert_eq!(Council::next_nonfull_voter_set(), 1); - - // now we charge the next voter. - vote(65, 2); - assert_eq!(Balances::free_balance(&65), 20 - 5 - 2); - assert_eq!( - Council::voter_info(&65).unwrap(), - VoterInfo { last_win: 0, last_active: 0, stake: 15, pot:0 } - ); - }); - } - - #[test] - fn subsequent_set_approvals_checks_voter_index() { - with_externalities(&mut ExtBuilder::default().build(), || { - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - - assert_ok!(Council::set_approvals(Origin::signed(3), vec![true], 0, 0)); - assert_ok!(Council::set_approvals(Origin::signed(4), vec![true], 0, 5)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![true], 0, 100)); - - // invalid index - assert_noop!(Council::set_approvals(Origin::signed(4), vec![true], 0, 5), "invalid voter index"); - // wrong index - assert_noop!(Council::set_approvals(Origin::signed(4), vec![true], 0, 0), "wrong voter index"); - // correct - assert_ok!(Council::set_approvals(Origin::signed(4), vec![true], 0, 1)); - }) - } - - #[test] - fn voter_index_does_not_take_holes_into_account() { - with_externalities(&mut ExtBuilder::default().build(), || { - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(3), 1)); - - // create 65. 64 (set0) + 1 (set1) - (1..=65).for_each(|i| vote(i, 2)); - - // account 65 has global index 65. - assert_eq!(Council::voter_at(64).unwrap(), 65); - - assert_ok!(Council::retract_voter(Origin::signed(1), 0)); - assert_ok!(Council::retract_voter(Origin::signed(2), 1)); - - // still the same. These holes are in some other set. - assert_eq!(Council::voter_at(64).unwrap(), 65); - // proof: can submit a new approval with the old index. - assert_noop!(Council::set_approvals(Origin::signed(65), vec![false, true], 0, 64 - 2), "wrong voter index"); - assert_ok!(Council::set_approvals(Origin::signed(65), vec![false, true], 0, 64)); - }) - } - - #[test] - fn simple_candidate_submission_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(1); - assert_eq!(Council::candidates(), Vec::::new()); - assert_eq!(Council::candidate_reg_info(1), None); - assert_eq!(Council::candidate_reg_info(2), None); - assert_eq!(Council::is_a_candidate(&1), false); - assert_eq!(Council::is_a_candidate(&2), false); - - assert_ok!(Council::submit_candidacy(Origin::signed(1), 0)); - assert_eq!(Council::candidates(), vec![1]); - assert_eq!(Council::candidate_reg_info(1), Some((0, 0))); - assert_eq!(Council::candidate_reg_info(2), None); - assert_eq!(Council::is_a_candidate(&1), true); - assert_eq!(Council::is_a_candidate(&2), false); - - assert_ok!(Council::submit_candidacy(Origin::signed(2), 1)); - assert_eq!(Council::candidates(), vec![1, 2]); - assert_eq!(Council::candidate_reg_info(1), Some((0, 0))); - assert_eq!(Council::candidate_reg_info(2), Some((0, 1))); - assert_eq!(Council::is_a_candidate(&1), true); - assert_eq!(Council::is_a_candidate(&2), true); - }); - } - - fn new_test_ext_with_candidate_holes() -> runtime_io::TestExternalities { - let mut t = ExtBuilder::default().build(); - with_externalities(&mut t, || { - >::put(vec![0, 0, 1]); - >::put(1); - >::insert(1, (0, 2)); - }); - t - } - - #[test] - fn candidate_submission_using_free_slot_should_work() { - let mut t = new_test_ext_with_candidate_holes(); - - with_externalities(&mut t, || { - System::set_block_number(1); - assert_eq!(Council::candidates(), vec![0, 0, 1]); - - assert_ok!(Council::submit_candidacy(Origin::signed(2), 1)); - assert_eq!(Council::candidates(), vec![0, 2, 1]); - - assert_ok!(Council::submit_candidacy(Origin::signed(3), 0)); - assert_eq!(Council::candidates(), vec![3, 2, 1]); - }); - } - - #[test] - fn candidate_submission_using_alternative_free_slot_should_work() { - let mut t = new_test_ext_with_candidate_holes(); - - with_externalities(&mut t, || { - System::set_block_number(1); - assert_eq!(Council::candidates(), vec![0, 0, 1]); - - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - assert_eq!(Council::candidates(), vec![2, 0, 1]); - - assert_ok!(Council::submit_candidacy(Origin::signed(3), 1)); - assert_eq!(Council::candidates(), vec![2, 3, 1]); - }); - } - - #[test] - fn candidate_submission_not_using_free_slot_should_not_work() { - let mut t = new_test_ext_with_candidate_holes(); - - with_externalities(&mut t, || { - System::set_block_number(1); - assert_noop!(Council::submit_candidacy(Origin::signed(4), 3), "invalid candidate slot"); - }); - } - - #[test] - fn bad_candidate_slot_submission_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(1); - assert_eq!(Council::candidates(), Vec::::new()); - assert_noop!(Council::submit_candidacy(Origin::signed(1), 1), "invalid candidate slot"); - }); - } - - #[test] - fn non_free_candidate_slot_submission_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(1); - assert_eq!(Council::candidates(), Vec::::new()); - assert_ok!(Council::submit_candidacy(Origin::signed(1), 0)); - assert_eq!(Council::candidates(), vec![1]); - assert_noop!(Council::submit_candidacy(Origin::signed(2), 0), "invalid candidate slot"); - }); - } - - #[test] - fn dupe_candidate_submission_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(1); - assert_eq!(Council::candidates(), Vec::::new()); - assert_ok!(Council::submit_candidacy(Origin::signed(1), 0)); - assert_eq!(Council::candidates(), vec![1]); - assert_noop!(Council::submit_candidacy(Origin::signed(1), 1), "duplicate candidate submission"); - }); - } - - #[test] - fn poor_candidate_submission_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(1); - assert_eq!(Council::candidates(), Vec::::new()); - assert_noop!(Council::submit_candidacy(Origin::signed(7), 0), "candidate has not enough funds"); - }); - } - - #[test] - fn balance_should_lock_to_the_maximum() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(1); - assert_eq!(Council::candidates(), Vec::::new()); - assert_eq!(Balances::free_balance(&2), 20); - - assert_ok!(Council::submit_candidacy(Origin::signed(5), 0)); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![true], 0, 0)); - - assert_eq!(Balances::free_balance(&2), 20 - bond() ); - assert_noop!(Balances::reserve(&2, 1), "account liquidity restrictions prevent withdrawal"); // locked. - - // deposit a bit more. - let _ = Balances::deposit_creating(&2, 100); - assert_ok!(Balances::reserve(&2, 1)); // locked but now has enough. - - assert_ok!(Council::set_approvals(Origin::signed(2), vec![true], 0, 0)); - assert_noop!(Balances::reserve(&2, 1), "account liquidity restrictions prevent withdrawal"); // locked. - assert_eq!(Balances::locks(&2).len(), 1); - assert_eq!(Balances::locks(&2)[0].amount, 100 + 20); - - assert_ok!(Council::retract_voter(Origin::signed(2), 0)); - - assert_eq!(Balances::locks(&2).len(), 0); - assert_eq!(Balances::free_balance(&2), 120 - 1); // 1 ok call to .reserve() happened. - assert_ok!(Balances::reserve(&2, 1)); // unlocked. - }); - } - - #[test] - fn balance_should_lock_on_submit_approvals_unlock_on_retract() { - with_externalities(&mut ExtBuilder::default().voter_bond(8).voting_fee(0).build(), || { - System::set_block_number(1); - assert_eq!(Council::candidates(), Vec::::new()); - assert_eq!(Balances::free_balance(&2), 20); - - assert_ok!(Council::submit_candidacy(Origin::signed(5), 0)); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![true], 0, 0)); - - assert_eq!(Balances::free_balance(&2), 12); // 20 - 8 (bond) - assert_noop!(Balances::reserve(&2, 10), "account liquidity restrictions prevent withdrawal"); // locked. - - assert_ok!(Council::retract_voter(Origin::signed(2), 0)); - - assert_eq!(Balances::free_balance(&2), 20); - assert_ok!(Balances::reserve(&2, 10)); // unlocked. - }); - } - - #[test] - fn accumulating_weight_and_decaying_should_work() { - with_externalities(&mut ExtBuilder::default().balance_factor(10).build(), || { - System::set_block_number(4); - assert!(!Council::presentation_active()); - - assert_ok!(Council::submit_candidacy(Origin::signed(6), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Council::submit_candidacy(Origin::signed(1), 2)); - - assert_ok!(Council::set_approvals(Origin::signed(6), vec![true, false, false], 0, 0)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![false, true, false], 0, 0)); - assert_ok!(Council::set_approvals(Origin::signed(1), vec![false, false, true], 0, 0)); - - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert!(Council::presentation_active()); - - assert_eq!(Council::present_winner(Origin::signed(6), 6, 600, 0), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(5), 5, 500, 0), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(1), 1, 100, 0), Ok(())); - assert_eq!(Council::leaderboard(), Some(vec![(0, 0), (100, 1), (500, 5), (600, 6)])); - assert_ok!(Council::end_block(System::block_number())); - - assert_eq!(Council::active_council(), vec![(6, 11), (5, 11)]); - assert_eq!(Council::voter_info(6).unwrap(), VoterInfo { last_win: 1, last_active: 0, stake: 600, pot: 0}); - assert_eq!(Council::voter_info(5).unwrap(), VoterInfo { last_win: 1, last_active: 0, stake: 500, pot: 0}); - assert_eq!(Council::voter_info(1).unwrap(), VoterInfo { last_win: 0, last_active: 0, stake: 100, pot: 0}); - - System::set_block_number(12); - // retract needed to unlock approval funds => submit candidacy again. - assert_ok!(Council::retract_voter(Origin::signed(6), 0)); - assert_ok!(Council::retract_voter(Origin::signed(5), 1)); - assert_ok!(Council::submit_candidacy(Origin::signed(6), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Council::set_approvals(Origin::signed(6), vec![true, false, false], 1, 0)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![false, true, false], 1, 1)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(14); - assert!(Council::presentation_active()); - assert_eq!(Council::present_winner(Origin::signed(6), 6, 600, 1), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(5), 5, 500, 1), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(1), 1, 100 + Council::get_offset(100, 1), 1), Ok(())); - assert_eq!(Council::leaderboard(), Some(vec![(0, 0), (100 + 96, 1), (500, 5), (600, 6)])); - assert_ok!(Council::end_block(System::block_number())); - - assert_eq!(Council::active_council(), vec![(6, 19), (5, 19)]); - assert_eq!( - Council::voter_info(6).unwrap(), - VoterInfo { last_win: 2, last_active: 1, stake: 600, pot:0 } - ); - assert_eq!(Council::voter_info(5).unwrap(), VoterInfo { last_win: 2, last_active: 1, stake: 500, pot:0 }); - assert_eq!(Council::voter_info(1).unwrap(), VoterInfo { last_win: 0, last_active: 0, stake: 100, pot:0 }); - - System::set_block_number(20); - assert_ok!(Council::retract_voter(Origin::signed(6), 0)); - assert_ok!(Council::retract_voter(Origin::signed(5), 1)); - assert_ok!(Council::submit_candidacy(Origin::signed(6), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Council::set_approvals(Origin::signed(6), vec![true, false, false], 2, 0)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![false, true, false], 2, 1)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(22); - assert!(Council::presentation_active()); - assert_eq!(Council::present_winner(Origin::signed(6), 6, 600, 2), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(5), 5, 500, 2), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(1), 1, 100 + Council::get_offset(100, 2), 2), Ok(())); - assert_eq!(Council::leaderboard(), Some(vec![(0, 0), (100 + 96 + 93, 1), (500, 5), (600, 6)])); - assert_ok!(Council::end_block(System::block_number())); - - assert_eq!(Council::active_council(), vec![(6, 27), (5, 27)]); - assert_eq!( - Council::voter_info(6).unwrap(), - VoterInfo { last_win: 3, last_active: 2, stake: 600, pot: 0} - ); - assert_eq!(Council::voter_info(5).unwrap(), VoterInfo { last_win: 3, last_active: 2, stake: 500, pot: 0}); - assert_eq!(Council::voter_info(1).unwrap(), VoterInfo { last_win: 0, last_active: 0, stake: 100, pot: 0}); - - - System::set_block_number(28); - assert_ok!(Council::retract_voter(Origin::signed(6), 0)); - assert_ok!(Council::retract_voter(Origin::signed(5), 1)); - assert_ok!(Council::submit_candidacy(Origin::signed(6), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Council::set_approvals(Origin::signed(6), vec![true, false, false], 3, 0)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![false, true, false], 3, 1)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(30); - assert!(Council::presentation_active()); - assert_eq!(Council::present_winner(Origin::signed(6), 6, 600, 3), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(5), 5, 500, 3), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(1), 1, 100 + Council::get_offset(100, 3), 3), Ok(())); - assert_eq!(Council::leaderboard(), Some(vec![(0, 0), (100 + 96 + 93 + 90, 1), (500, 5), (600, 6)])); - assert_ok!(Council::end_block(System::block_number())); - - assert_eq!(Council::active_council(), vec![(6, 35), (5, 35)]); - assert_eq!( - Council::voter_info(6).unwrap(), - VoterInfo { last_win: 4, last_active: 3, stake: 600, pot: 0} - ); - assert_eq!(Council::voter_info(5).unwrap(), VoterInfo { last_win: 4, last_active: 3, stake: 500, pot: 0}); - assert_eq!(Council::voter_info(1).unwrap(), VoterInfo { last_win: 0, last_active: 0, stake: 100, pot: 0}); - }) - } - - #[test] - fn winning_resets_accumulated_pot() { - with_externalities(&mut ExtBuilder::default().balance_factor(10).build(), || { - System::set_block_number(4); - assert!(!Council::presentation_active()); - - assert_ok!(Council::submit_candidacy(Origin::signed(6), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(4), 1)); - assert_ok!(Council::submit_candidacy(Origin::signed(3), 2)); - assert_ok!(Council::submit_candidacy(Origin::signed(2), 3)); - - assert_ok!(Council::set_approvals(Origin::signed(6), vec![true, false, false, false], 0, 0)); - assert_ok!(Council::set_approvals(Origin::signed(4), vec![false, true, false, false], 0, 1)); - assert_ok!(Council::set_approvals(Origin::signed(3), vec![false, false, true, true], 0, 2)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert!(Council::presentation_active()); - assert_eq!(Council::present_winner(Origin::signed(6), 6, 600, 0), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(4), 4, 400, 0), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(3), 3, 300, 0), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(2), 2, 300, 0), Ok(())); - assert_eq!(Council::leaderboard(), Some(vec![(300, 2), (300, 3), (400, 4), (600, 6)])); - assert_ok!(Council::end_block(System::block_number())); - - assert_eq!(Council::active_council(), vec![(6, 11), (4, 11)]); - - System::set_block_number(12); - assert_ok!(Council::retract_voter(Origin::signed(6), 0)); - assert_ok!(Council::retract_voter(Origin::signed(4), 1)); - assert_ok!(Council::submit_candidacy(Origin::signed(6), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(4), 1)); - assert_ok!(Council::set_approvals(Origin::signed(6), vec![true, false, false, false], 1, 0)); - assert_ok!(Council::set_approvals(Origin::signed(4), vec![false, true, false, false], 1, 1)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(14); - assert!(Council::presentation_active()); - assert_eq!(Council::present_winner(Origin::signed(6), 6, 600, 1), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(4), 4, 400, 1), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(3), 3, 300 + Council::get_offset(300, 1), 1), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(2), 2, 300 + Council::get_offset(300, 1), 1), Ok(())); - assert_eq!(Council::leaderboard(), Some(vec![(400, 4), (588, 2), (588, 3), (600, 6)])); - assert_ok!(Council::end_block(System::block_number())); - - assert_eq!(Council::active_council(), vec![(6, 19), (3, 19)]); - - System::set_block_number(20); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(22); - // 2 will not get re-elected with 300 + 288, instead just 300. - // because one of 3's candidates (3) won in previous round - // 4 on the other hand will get extra weight since it was unlucky. - assert_eq!(Council::present_winner(Origin::signed(3), 2, 300, 2), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(4), 4, 400 + Council::get_offset(400, 1), 2), Ok(())); - assert_ok!(Council::end_block(System::block_number())); - - assert_eq!(Council::active_council(), vec![(4, 27), (2, 27)]); - }) - } - - #[test] - fn resubmitting_approvals_stores_pot() { - with_externalities(&mut ExtBuilder::default() - .voter_bond(0) - .voting_fee(0) - .balance_factor(10) - .build(), - || { System::set_block_number(4); - assert!(!Council::presentation_active()); - - assert_ok!(Council::submit_candidacy(Origin::signed(6), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Council::submit_candidacy(Origin::signed(1), 2)); - - assert_ok!(Council::set_approvals(Origin::signed(6), vec![true, false, false], 0, 0)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![false, true, false], 0, 1)); - assert_ok!(Council::set_approvals(Origin::signed(1), vec![false, false, true], 0, 2)); - - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert!(Council::presentation_active()); - - assert_eq!(Council::present_winner(Origin::signed(6), 6, 600, 0), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(5), 5, 500, 0), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(1), 1, 100, 0), Ok(())); - assert_eq!(Council::leaderboard(), Some(vec![(0, 0), (100, 1), (500, 5), (600, 6)])); - assert_ok!(Council::end_block(System::block_number())); - - assert_eq!(Council::active_council(), vec![(6, 11), (5, 11)]); - - System::set_block_number(12); - assert_ok!(Council::retract_voter(Origin::signed(6), 0)); - assert_ok!(Council::retract_voter(Origin::signed(5), 1)); - assert_ok!(Council::submit_candidacy(Origin::signed(6), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Council::set_approvals(Origin::signed(6), vec![true, false, false], 1, 0)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![false, true, false], 1, 1)); - // give 1 some new high balance - let _ = Balances::make_free_balance_be(&1, 997); - assert_ok!(Council::set_approvals(Origin::signed(1), vec![false, false, true], 1, 2)); - assert_eq!(Council::voter_info(1).unwrap(), - VoterInfo { - stake: 1000, // 997 + 3 which is candidacy bond. - pot: Council::get_offset(100, 1), - last_active: 1, - last_win: 1, - } - ); - assert_ok!(Council::end_block(System::block_number())); - - assert_eq!(Council::active_council(), vec![(6, 11), (5, 11)]); - - System::set_block_number(14); - assert!(Council::presentation_active()); - assert_eq!(Council::present_winner(Origin::signed(6), 6, 600, 1), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(5), 5, 500, 1), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(1), 1, 1000 + 96 /* pot */, 1), Ok(())); - assert_eq!(Council::leaderboard(), Some(vec![(0, 0), (500, 5), (600, 6), (1096, 1)])); - assert_ok!(Council::end_block(System::block_number())); - - assert_eq!(Council::active_council(), vec![(1, 19), (6, 19)]); - }) - } - - #[test] - fn get_offset_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - assert_eq!(Council::get_offset(100, 0), 0); - assert_eq!(Council::get_offset(100, 1), 96); - assert_eq!(Council::get_offset(100, 2), 96 + 93); - assert_eq!(Council::get_offset(100, 3), 96 + 93 + 90); - assert_eq!(Council::get_offset(100, 4), 96 + 93 + 90 + 87); - // limit - assert_eq!(Council::get_offset(100, 1000), 100 * 24); - - assert_eq!(Council::get_offset(50_000_000_000, 0), 0); - assert_eq!(Council::get_offset(50_000_000_000, 1), 48_000_000_000); - assert_eq!(Council::get_offset(50_000_000_000, 2), 48_000_000_000 + 46_080_000_000); - assert_eq!(Council::get_offset(50_000_000_000, 3), 48_000_000_000 + 46_080_000_000 + 44_236_800_000); - assert_eq!( - Council::get_offset(50_000_000_000, 4), - 48_000_000_000 + 46_080_000_000 + 44_236_800_000 + 42_467_328_000 - ); - // limit - assert_eq!(Council::get_offset(50_000_000_000, 1000), 50_000_000_000 * 24); - }) - } - - #[test] - fn get_offset_with_zero_decay() { - with_externalities(&mut ExtBuilder::default().decay_ratio(0).build(), || { - assert_eq!(Council::get_offset(100, 0), 0); - assert_eq!(Council::get_offset(100, 1), 0); - assert_eq!(Council::get_offset(100, 2), 0); - assert_eq!(Council::get_offset(100, 3), 0); - // limit - assert_eq!(Council::get_offset(100, 1000), 0); - }) - } - - #[test] - fn voting_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(1); - - assert_ok!(Council::submit_candidacy(Origin::signed(5), 0)); - - assert_ok!(Council::set_approvals(Origin::signed(1), vec![true], 0, 0)); - assert_ok!(Council::set_approvals(Origin::signed(4), vec![true], 0, 1)); - - assert_eq!(Council::all_approvals_of(&1), vec![true]); - assert_eq!(Council::all_approvals_of(&4), vec![true]); - assert_eq!(voter_ids(), vec![1, 4]); - - assert_ok!(Council::submit_candidacy(Origin::signed(2), 1)); - assert_ok!(Council::submit_candidacy(Origin::signed(3), 2)); - - assert_ok!(Council::set_approvals(Origin::signed(2), vec![false, true, true], 0, 2)); - assert_ok!(Council::set_approvals(Origin::signed(3), vec![false, true, true], 0, 3)); - - assert_eq!(Council::all_approvals_of(&1), vec![true]); - assert_eq!(Council::all_approvals_of(&4), vec![true]); - assert_eq!(Council::all_approvals_of(&2), vec![false, true, true]); - assert_eq!(Council::all_approvals_of(&3), vec![false, true, true]); - - assert_eq!(voter_ids(), vec![1, 4, 2, 3]); - }); - } - - #[test] - fn proxy_voting_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(1); - - assert_ok!(Council::submit_candidacy(Origin::signed(5), 0)); - - Democracy::force_proxy(1, 11); - Democracy::force_proxy(2, 12); - Democracy::force_proxy(3, 13); - Democracy::force_proxy(4, 14); - assert_ok!(Council::proxy_set_approvals(Origin::signed(11), vec![true], 0, 0)); - assert_ok!(Council::proxy_set_approvals(Origin::signed(14), vec![true], 0, 1)); - - assert_eq!(Council::all_approvals_of(&1), vec![true]); - assert_eq!(Council::all_approvals_of(&4), vec![true]); - assert_eq!(voter_ids(), vec![1, 4]); - - assert_ok!(Council::submit_candidacy(Origin::signed(2), 1)); - assert_ok!(Council::submit_candidacy(Origin::signed(3), 2)); - - assert_ok!(Council::proxy_set_approvals(Origin::signed(12), vec![false, true, true], 0, 2)); - assert_ok!(Council::proxy_set_approvals(Origin::signed(13), vec![false, true, true], 0, 3)); - - assert_eq!(Council::all_approvals_of(&1), vec![true]); - assert_eq!(Council::all_approvals_of(&4), vec![true]); - assert_eq!(Council::all_approvals_of(&2), vec![false, true, true]); - assert_eq!(Council::all_approvals_of(&3), vec![false, true, true]); - - assert_eq!(voter_ids(), vec![1, 4, 2, 3]); - }); - } - - #[test] - fn setting_any_approval_vote_count_without_any_candidate_count_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(1); - - assert_eq!(Council::candidates().len(), 0); - - assert_noop!( - Council::set_approvals(Origin::signed(4), vec![], 0, 0), - "amount of candidates to receive approval votes should be non-zero" - ); - }); - } - - #[test] - fn setting_an_approval_vote_count_more_than_candidate_count_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(1); - - assert_ok!(Council::submit_candidacy(Origin::signed(5), 0)); - assert_eq!(Council::candidates().len(), 1); - - assert_noop!( - Council::set_approvals(Origin::signed(4),vec![true, true], 0, 0), - "amount of candidate votes cannot exceed amount of candidates" - ); - }); - } - - #[test] - fn resubmitting_voting_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(1); - - assert_ok!(Council::submit_candidacy(Origin::signed(5), 0)); - assert_ok!(Council::set_approvals(Origin::signed(4), vec![true], 0, 0)); - - assert_eq!(Council::all_approvals_of(&4), vec![true]); - - assert_ok!(Council::submit_candidacy(Origin::signed(2), 1)); - assert_ok!(Council::submit_candidacy(Origin::signed(3), 2)); - assert_eq!(Council::candidates().len(), 3); - assert_ok!(Council::set_approvals(Origin::signed(4), vec![true, false, true], 0, 0)); - - assert_eq!(Council::all_approvals_of(&4), vec![true, false, true]); - }); - } - - #[test] - fn retracting_voter_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(1); - - assert_ok!(Council::submit_candidacy(Origin::signed(5), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(2), 1)); - assert_ok!(Council::submit_candidacy(Origin::signed(3), 2)); - assert_eq!(Council::candidates().len(), 3); - - assert_ok!(Council::set_approvals(Origin::signed(1), vec![true], 0, 0)); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![false, true, true], 0, 1)); - assert_ok!(Council::set_approvals(Origin::signed(3), vec![false, true, true], 0, 2)); - assert_ok!(Council::set_approvals(Origin::signed(4), vec![true, false, true], 0, 3)); - - assert_eq!(voter_ids(), vec![1, 2, 3, 4]); - assert_eq!(Council::all_approvals_of(&1), vec![true]); - assert_eq!(Council::all_approvals_of(&2), vec![false, true, true]); - assert_eq!(Council::all_approvals_of(&3), vec![false, true, true]); - assert_eq!(Council::all_approvals_of(&4), vec![true, false, true]); - - assert_ok!(Council::retract_voter(Origin::signed(1), 0)); - - assert_eq!(voter_ids(), vec![0, 2, 3, 4]); - assert_eq!(Council::all_approvals_of(&1), Vec::::new()); - assert_eq!(Council::all_approvals_of(&2), vec![false, true, true]); - assert_eq!(Council::all_approvals_of(&3), vec![false, true, true]); - assert_eq!(Council::all_approvals_of(&4), vec![true, false, true]); - - assert_ok!(Council::retract_voter(Origin::signed(2), 1)); - - assert_eq!(voter_ids(), vec![0, 0, 3, 4]); - assert_eq!(Council::all_approvals_of(&1), Vec::::new()); - assert_eq!(Council::all_approvals_of(&2), Vec::::new()); - assert_eq!(Council::all_approvals_of(&3), vec![false, true, true]); - assert_eq!(Council::all_approvals_of(&4), vec![true, false, true]); - - assert_ok!(Council::retract_voter(Origin::signed(3), 2)); - - assert_eq!(voter_ids(), vec![0, 0, 0, 4]); - assert_eq!(Council::all_approvals_of(&1), Vec::::new()); - assert_eq!(Council::all_approvals_of(&2), Vec::::new()); - assert_eq!(Council::all_approvals_of(&3), Vec::::new()); - assert_eq!(Council::all_approvals_of(&4), vec![true, false, true]); - }); - } - - #[test] - fn invalid_retraction_index_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(1); - assert_ok!(Council::submit_candidacy(Origin::signed(3), 0)); - assert_ok!(Council::set_approvals(Origin::signed(1), vec![true], 0, 0)); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![true], 0, 0)); - assert_eq!(voter_ids(), vec![1, 2]); - assert_noop!(Council::retract_voter(Origin::signed(1), 1), "retraction index mismatch"); - }); - } - - #[test] - fn overflow_retraction_index_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(1); - assert_ok!(Council::submit_candidacy(Origin::signed(3), 0)); - assert_ok!(Council::set_approvals(Origin::signed(1), vec![true], 0, 0)); - assert_noop!(Council::retract_voter(Origin::signed(1), 1), "retraction index invalid"); - }); - } - - #[test] - fn non_voter_retraction_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(1); - assert_ok!(Council::submit_candidacy(Origin::signed(3), 0)); - assert_ok!(Council::set_approvals(Origin::signed(1), vec![true], 0, 0)); - assert_noop!(Council::retract_voter(Origin::signed(2), 0), "cannot retract non-voter"); - }); - } - - #[test] - fn approval_storage_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(3), 1)); - - assert_ok!(Council::set_approvals(Origin::signed(2), vec![true, false], 0, 0)); - assert_ok!(Council::set_approvals(Origin::signed(3), vec![false, false], 0, 0)); - assert_ok!(Council::set_approvals(Origin::signed(4), vec![], 0, 0)); - - assert_eq!(Council::all_approvals_of(&2), vec![true]); - // NOTE: these two are stored in mem differently though. - assert_eq!(Council::all_approvals_of(&3), vec![]); - assert_eq!(Council::all_approvals_of(&4), vec![]); - - assert_eq!(Council::approvals_of((3, 0)), vec![0]); - assert_eq!(Council::approvals_of((4, 0)), vec![]); - }); - } - - #[test] - fn simple_tally_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(4); - assert!(!Council::presentation_active()); - - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![true], 0, 0)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![false, true], 0, 0)); - assert_eq!(voter_ids(), vec![2, 5]); - assert_eq!(Council::all_approvals_of(&2), vec![true]); - assert_eq!(Council::all_approvals_of(&5), vec![false, true]); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert!(Council::presentation_active()); - assert_eq!(Council::present_winner(Origin::signed(4), 2, 20, 0), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(4), 5, 50, 0), Ok(())); - assert_eq!(Council::leaderboard(), Some(vec![(0, 0), (0, 0), (20, 2), (50, 5)])); - - assert_ok!(Council::end_block(System::block_number())); - - assert!(!Council::presentation_active()); - assert_eq!(Council::active_council(), vec![(5, 11), (2, 11)]); - - assert!(!Council::is_a_candidate(&2)); - assert!(!Council::is_a_candidate(&5)); - assert_eq!(Council::vote_index(), 1); - assert_eq!(Council::voter_info(2), Some(VoterInfo { last_win: 1, last_active: 0, stake: 20, pot: 0 })); - assert_eq!(Council::voter_info(5), Some(VoterInfo { last_win: 1, last_active: 0, stake: 50, pot: 0 })); - }); - } - - #[test] - fn seats_should_be_released() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(4); - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![true, false], 0, 0)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![false, true], 0, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert!(Council::presentation_active()); - assert_eq!(Council::present_winner(Origin::signed(4), 2, 20, 0), Ok(())); - assert_eq!(Council::present_winner(Origin::signed(4), 5, 50, 0), Ok(())); - assert_eq!(Council::leaderboard(), Some(vec![(0, 0), (0, 0), (20, 2), (50, 5)])); - assert_ok!(Council::end_block(System::block_number())); - - assert_eq!(Council::active_council(), vec![(5, 11), (2, 11)]); - let mut current = System::block_number(); - let free_block; - loop { - current += 1; - System::set_block_number(current); - assert_ok!(Council::end_block(System::block_number())); - if Council::active_council().len() == 0 { - free_block = current; - break; - } - } - // 11 + 2 which is the next voting period. - assert_eq!(free_block, 14); - }); - } - - #[test] - fn presentations_with_zero_staked_deposit_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(4); - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![true], 0, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert_noop!( - Council::present_winner(Origin::signed(4), 2, 0, 0), - "stake deposited to present winner and be added to leaderboard should be non-zero" - ); - }); - } - - #[test] - fn double_presentations_should_be_punished() { - with_externalities(&mut ExtBuilder::default().build(), || { - assert!(Balances::can_slash(&4, 10)); - - System::set_block_number(4); - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![true, false], 0, 0)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![false, true], 0, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Council::present_winner(Origin::signed(4), 2, 20, 0)); - assert_ok!(Council::present_winner(Origin::signed(4), 5, 50, 0)); - assert_eq!(Council::present_winner(Origin::signed(4), 5, 50, 0), Err("duplicate presentation")); - assert_ok!(Council::end_block(System::block_number())); - - assert_eq!(Council::active_council(), vec![(5, 11), (2, 11)]); - assert_eq!(Balances::total_balance(&4), 38); - }); - } - - #[test] - fn retracting_inactive_voter_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(4); - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![true], 0, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Council::present_winner(Origin::signed(4), 2, 20, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(8); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 0)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![true], 1, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(10); - assert_ok!(Council::present_winner(Origin::signed(4), 5, 50, 1)); - assert_ok!(Council::end_block(System::block_number())); - - assert_ok!(Council::reap_inactive_voter(Origin::signed(5), - (voter_ids().iter().position(|&i| i == 5).unwrap() as u32).into(), - 2, (voter_ids().iter().position(|&i| i == 2).unwrap() as u32).into(), - 2 - )); - - assert_eq!(voter_ids(), vec![0, 5]); - assert_eq!(Council::all_approvals_of(&2).len(), 0); - assert_eq!(Balances::total_balance(&2), 20); - assert_eq!(Balances::total_balance(&5), 50); - }); - } - - #[test] - fn presenting_for_double_election_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(4); - assert_eq!(Council::submit_candidacy(Origin::signed(2), 0), Ok(())); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![true], 0, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Council::present_winner(Origin::signed(4), 2, 20, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(8); - // NOTE: This is now mandatory to disable the lock - assert_ok!(Council::retract_voter(Origin::signed(2), 0)); - assert_eq!(Council::submit_candidacy(Origin::signed(2), 0), Ok(())); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![true], 1, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(10); - assert_noop!( - Council::present_winner(Origin::signed(4), 2, 20, 1), - "candidate must not form a duplicated member if elected" - ); - }); - } - - #[test] - fn retracting_inactive_voter_with_other_candidates_in_slots_should_work() { - with_externalities(&mut ExtBuilder::default().voter_bond(2).build(), || { - System::set_block_number(4); - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![true], 0, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Council::present_winner(Origin::signed(4), 2, 20, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(8); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 0)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![true], 1, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(10); - assert_ok!(Council::present_winner(Origin::signed(4), 5, 50, 1)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(11); - assert_ok!(Council::submit_candidacy(Origin::signed(1), 0)); - - assert_ok!(Council::reap_inactive_voter(Origin::signed(5), - (voter_ids().iter().position(|&i| i == 5).unwrap() as u32).into(), - 2, (voter_ids().iter().position(|&i| i == 2).unwrap() as u32).into(), - 2 - )); - - assert_eq!(voter_ids(), vec![0, 5]); - assert_eq!(Council::all_approvals_of(&2).len(), 0); - assert_eq!(Balances::total_balance(&2), 18); - assert_eq!(Balances::total_balance(&5), 52); - }); - } - - #[test] - fn retracting_inactive_voter_with_bad_reporter_index_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(4); - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![true], 0, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Council::present_winner(Origin::signed(4), 2, 20, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(8); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 0)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![true], 1, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(10); - assert_ok!(Council::present_winner(Origin::signed(4), 5, 50, 1)); - assert_ok!(Council::end_block(System::block_number())); - - assert_noop!(Council::reap_inactive_voter(Origin::signed(2), - 42, - 2, (voter_ids().iter().position(|&i| i == 2).unwrap() as u32).into(), - 2 - ), "invalid reporter index"); - }); - } - - #[test] - fn retracting_inactive_voter_with_bad_target_index_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(4); - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![true], 0, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Council::present_winner(Origin::signed(4), 2, 20, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(8); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 0)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![true], 1, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(10); - assert_ok!(Council::present_winner(Origin::signed(4), 5, 50, 1)); - assert_ok!(Council::end_block(System::block_number())); - - assert_noop!(Council::reap_inactive_voter(Origin::signed(2), - (voter_ids().iter().position(|&i| i == 2).unwrap() as u32).into(), - 2, 42, - 2 - ), "invalid target index"); - }); - } - - #[test] - fn attempting_to_retract_active_voter_should_slash_reporter() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(4); - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(3), 1)); - assert_ok!(Council::submit_candidacy(Origin::signed(4), 2)); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 3)); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![true, false, false, false], 0, 0)); - assert_ok!(Council::set_approvals(Origin::signed(3), vec![false, true, false, false], 0, 0)); - assert_ok!(Council::set_approvals(Origin::signed(4), vec![false, false, true, false], 0, 0)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![false, false, false, true], 0, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Council::present_winner(Origin::signed(4), 2, 20, 0)); - assert_ok!(Council::present_winner(Origin::signed(4), 3, 30, 0)); - assert_ok!(Council::present_winner(Origin::signed(4), 4, 40, 0)); - assert_ok!(Council::present_winner(Origin::signed(4), 5, 50, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(8); - assert_ok!(Council::set_desired_seats(3)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(10); - assert_ok!(Council::present_winner(Origin::signed(4), 2, 20 + Council::get_offset(20, 1), 1)); - assert_ok!(Council::present_winner(Origin::signed(4), 3, 30 + Council::get_offset(30, 1), 1)); - assert_ok!(Council::end_block(System::block_number())); - - assert_eq!(Council::vote_index(), 2); - assert_eq!(Council::inactivity_grace_period(), 1); - assert_eq!(Council::voting_period(), 4); - assert_eq!(Council::voter_info(4), Some(VoterInfo { last_win: 1, last_active: 0, stake: 40, pot: 0 })); - - assert_ok!(Council::reap_inactive_voter(Origin::signed(4), - (voter_ids().iter().position(|&i| i == 4).unwrap() as u32).into(), - 2, - (voter_ids().iter().position(|&i| i == 2).unwrap() as u32).into(), - 2 - )); - - assert_eq!(voter_ids(), vec![2, 3, 0, 5]); - assert_eq!(Council::all_approvals_of(&4).len(), 0); - assert_eq!(Balances::total_balance(&4), 40); - }); - } - - #[test] - fn attempting_to_retract_inactive_voter_by_nonvoter_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(4); - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![true], 0, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Council::present_winner(Origin::signed(4), 2, 20, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(8); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 0)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![true], 1, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(10); - assert_ok!(Council::present_winner(Origin::signed(4), 5, 50, 1)); - assert_ok!(Council::end_block(System::block_number())); - - assert_noop!(Council::reap_inactive_voter(Origin::signed(4), - 0, - 2, (voter_ids().iter().position(|&i| i == 2).unwrap() as u32).into(), - 2 - ), "reporter must be a voter"); - }); - } - - #[test] - fn presenting_loser_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(4); - assert_ok!(Council::submit_candidacy(Origin::signed(1), 0)); - assert_ok!(Council::set_approvals(Origin::signed(6), vec![true], 0, 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(2), 1)); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![false, true], 0, 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(3), 2)); - assert_ok!(Council::set_approvals(Origin::signed(3), vec![false, false, true], 0, 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(4), 3)); - assert_ok!(Council::set_approvals(Origin::signed(4), vec![false, false, false, true], 0, 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 4)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![false, false, false, false, true], 0, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Council::present_winner(Origin::signed(4), 1, 60, 0)); - assert_ok!(Council::present_winner(Origin::signed(4), 3, 30, 0)); - assert_ok!(Council::present_winner(Origin::signed(4), 4, 40, 0)); - assert_ok!(Council::present_winner(Origin::signed(4), 5, 50, 0)); - - assert_eq!(Council::leaderboard(), Some(vec![ - (30, 3), - (40, 4), - (50, 5), - (60, 1) - ])); - - assert_noop!(Council::present_winner(Origin::signed(4), 2, 20, 0), "candidate not worthy of leaderboard"); - }); - } - - #[test] - fn presenting_loser_first_should_not_matter() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(4); - assert_ok!(Council::submit_candidacy(Origin::signed(1), 0)); - assert_ok!(Council::set_approvals(Origin::signed(6), vec![true], 0, 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(2), 1)); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![false, true], 0, 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(3), 2)); - assert_ok!(Council::set_approvals(Origin::signed(3), vec![false, false, true], 0, 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(4), 3)); - assert_ok!(Council::set_approvals(Origin::signed(4), vec![false, false, false, true], 0, 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 4)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![false, false, false, false, true], 0, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Council::present_winner(Origin::signed(4), 2, 20, 0)); - assert_ok!(Council::present_winner(Origin::signed(4), 1, 60, 0)); - assert_ok!(Council::present_winner(Origin::signed(4), 3, 30, 0)); - assert_ok!(Council::present_winner(Origin::signed(4), 4, 40, 0)); - assert_ok!(Council::present_winner(Origin::signed(4), 5, 50, 0)); - - assert_eq!(Council::leaderboard(), Some(vec![ - (30, 3), - (40, 4), - (50, 5), - (60, 1) - ])); - }); - } - - #[test] - fn present_outside_of_presentation_period_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(4); - assert!(!Council::presentation_active()); - assert_noop!( - Council::present_winner(Origin::signed(5), 5, 1, 0), - "cannot present outside of presentation period" - ); - }); - } - - #[test] - fn present_with_invalid_vote_index_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(4); - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![true, false], 0, 0)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![false, true], 0, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert_noop!(Council::present_winner(Origin::signed(4), 2, 20, 1), "index not current"); - }); - } - - #[test] - fn present_when_presenter_is_poor_should_not_work() { - let test_present = |p| { - with_externalities(&mut ExtBuilder::default() - .voting_fee(5) - .voter_bond(2) - .bad_presentation_punishment(p) - .build(), - || { - System::set_block_number(4); - let _ = Balances::make_free_balance_be(&1, 15); - assert!(!Council::presentation_active()); - - assert_ok!(Council::submit_candidacy(Origin::signed(1), 0)); // -3 - assert_eq!(Balances::free_balance(&1), 12); - assert_ok!(Council::set_approvals(Origin::signed(1), vec![true], 0, 0)); // -2 -5 - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert_eq!(Balances::free_balance(&1), 5); - assert_eq!(Balances::reserved_balance(&1), 5); - if p > 5 { - assert_noop!(Council::present_winner( - Origin::signed(1), 1, 10, 0), - "presenter must have sufficient slashable funds" - ); - } else { - assert_ok!(Council::present_winner(Origin::signed(1), 1, 10, 0)); - } - }); - }; - test_present(4); - test_present(6); - } - - #[test] - fn invalid_present_tally_should_slash() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(4); - assert!(!Council::presentation_active()); - assert_eq!(Balances::total_balance(&4), 40); - - assert_ok!(Council::submit_candidacy(Origin::signed(2), 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![true, false], 0, 0)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![false, true], 0, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert_err!(Council::present_winner(Origin::signed(4), 2, 80, 0), "incorrect total"); - - assert_eq!(Balances::total_balance(&4), 38); - }); - } - - #[test] - fn runners_up_should_be_kept() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(4); - assert!(!Council::presentation_active()); - - assert_ok!(Council::submit_candidacy(Origin::signed(1), 0)); - assert_ok!(Council::set_approvals(Origin::signed(6), vec![true], 0, 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(2), 1)); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![false, true], 0, 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(3), 2)); - assert_ok!(Council::set_approvals(Origin::signed(3), vec![false, false, true], 0, 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(4), 3)); - assert_ok!(Council::set_approvals(Origin::signed(4), vec![false, false, false, true], 0, 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 4)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![false, false, false, false, true], 0, 0)); - - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert!(Council::presentation_active()); - assert_ok!(Council::present_winner(Origin::signed(4), 1, 60, 0)); - // leaderboard length is the empty seats plus the carry count (i.e. 5 + 2), where those - // to be carried are the lowest and stored in lowest indices - assert_eq!(Council::leaderboard(), Some(vec![ - (0, 0), - (0, 0), - (0, 0), - (60, 1) - ])); - assert_ok!(Council::present_winner(Origin::signed(4), 3, 30, 0)); - assert_ok!(Council::present_winner(Origin::signed(4), 4, 40, 0)); - assert_ok!(Council::present_winner(Origin::signed(4), 5, 50, 0)); - assert_eq!(Council::leaderboard(), Some(vec![ - (30, 3), - (40, 4), - (50, 5), - (60, 1) - ])); - - assert_ok!(Council::end_block(System::block_number())); - - assert!(!Council::presentation_active()); - assert_eq!(Council::active_council(), vec![(1, 11), (5, 11)]); - - assert!(!Council::is_a_candidate(&1)); - assert!(!Council::is_a_candidate(&5)); - assert!(!Council::is_a_candidate(&2)); - assert!(Council::is_a_candidate(&3)); - assert!(Council::is_a_candidate(&4)); - assert_eq!(Council::vote_index(), 1); - assert_eq!(Council::voter_info(2), Some(VoterInfo { last_win: 0, last_active: 0, stake: 20, pot: 0 })); - assert_eq!(Council::voter_info(3), Some(VoterInfo { last_win: 0, last_active: 0, stake: 30, pot: 0 })); - assert_eq!(Council::voter_info(4), Some(VoterInfo { last_win: 0, last_active: 0, stake: 40, pot: 0 })); - assert_eq!(Council::voter_info(5), Some(VoterInfo { last_win: 1, last_active: 0, stake: 50, pot: 0 })); - assert_eq!(Council::voter_info(6), Some(VoterInfo { last_win: 1, last_active: 0, stake: 60, pot: 0 })); - assert_eq!(Council::candidate_reg_info(3), Some((0, 2))); - assert_eq!(Council::candidate_reg_info(4), Some((0, 3))); - }); - } - - #[test] - fn second_tally_should_use_runners_up() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_block_number(4); - assert_ok!(Council::submit_candidacy(Origin::signed(1), 0)); - assert_ok!(Council::set_approvals(Origin::signed(6), vec![true], 0, 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(2), 1)); - assert_ok!(Council::set_approvals(Origin::signed(2), vec![false, true], 0, 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(3), 2)); - assert_ok!(Council::set_approvals(Origin::signed(3), vec![false, false, true], 0, 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(4), 3)); - assert_ok!(Council::set_approvals(Origin::signed(4), vec![false, false, false, true], 0, 0)); - assert_ok!(Council::submit_candidacy(Origin::signed(5), 4)); - assert_ok!(Council::set_approvals(Origin::signed(5), vec![false, false, false, false, true], 0, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(6); - assert_ok!(Council::present_winner(Origin::signed(4), 1, 60, 0)); - assert_ok!(Council::present_winner(Origin::signed(4), 3, 30, 0)); - assert_ok!(Council::present_winner(Origin::signed(4), 4, 40, 0)); - assert_ok!(Council::present_winner(Origin::signed(4), 5, 50, 0)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(8); - assert_ok!(Council::set_approvals(Origin::signed(6), vec![false, false, true, false], 1, 0)); - assert_ok!(Council::set_desired_seats(3)); - assert_ok!(Council::end_block(System::block_number())); - - System::set_block_number(10); - assert_ok!(Council::present_winner(Origin::signed(4), 3, 30 + Council::get_offset(30, 1) + 60, 1)); - assert_ok!(Council::present_winner(Origin::signed(4), 4, 40 + Council::get_offset(40, 1), 1)); - assert_ok!(Council::end_block(System::block_number())); - - assert!(!Council::presentation_active()); - assert_eq!(Council::active_council(), vec![(1, 11), (5, 11), (3, 15)]); - - assert!(!Council::is_a_candidate(&1)); - assert!(!Council::is_a_candidate(&2)); - assert!(!Council::is_a_candidate(&3)); - assert!(!Council::is_a_candidate(&5)); - assert!(Council::is_a_candidate(&4)); - assert_eq!(Council::vote_index(), 2); - assert_eq!(Council::voter_info(2), Some( VoterInfo { last_win: 0, last_active: 0, stake: 20, pot: 0})); - assert_eq!(Council::voter_info(3), Some( VoterInfo { last_win: 2, last_active: 0, stake: 30, pot: 0})); - assert_eq!(Council::voter_info(4), Some( VoterInfo { last_win: 0, last_active: 0, stake: 40, pot: 0})); - assert_eq!(Council::voter_info(5), Some( VoterInfo { last_win: 1, last_active: 0, stake: 50, pot: 0})); - assert_eq!( - Council::voter_info(6), - Some(VoterInfo { last_win: 2, last_active: 1, stake: 60, pot: 0}) - ); - - assert_eq!(Council::candidate_reg_info(4), Some((0, 3))); - }); - } -} diff --git a/srml/democracy/Cargo.toml b/srml/democracy/Cargo.toml index 88d1da1a8cb24008e61a87d3b39323b0f1bd4460..e7b06ca5975c16c230fe5c2d5fdcfbba4b6f58d5 100644 --- a/srml/democracy/Cargo.toml +++ b/srml/democracy/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] serde = { version = "1.0", optional = true, features = ["derive"] } safe-mix = { version = "1.0", default-features = false} -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } runtime_io = { package = "sr-io", path = "../../core/sr-io", default-features = false } primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } diff --git a/srml/democracy/src/lib.rs b/srml/democracy/src/lib.rs index 0fead411c8796d6c460c8f2a0c8f91557ff6e8a3..d13feb4db531d9e804aba97d53b9257ed82f2f6d 100644 --- a/srml/democracy/src/lib.rs +++ b/srml/democracy/src/lib.rs @@ -165,8 +165,15 @@ impl Decode for Vote { type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +pub const DEFAULT_ENACTMENT_PERIOD: u32 = 0; +pub const DEFAULT_LAUNCH_PERIOD: u32 = 0; +pub const DEFAULT_VOTING_PERIOD: u32 = 0; +pub const DEFAULT_MINIMUM_DEPOSIT: u32 = 0; +pub const DEFAULT_EMERGENCY_VOTING_PERIOD: u32 = 0; +pub const DEFAULT_COOLOFF_PERIOD: u32 = 0; + pub trait Trait: system::Trait + Sized { - type Proposal: Parameter + Dispatchable + IsSubType>; + type Proposal: Parameter + Dispatchable + IsSubType, Self>; type Event: From> + Into<::Event>; /// Currency type for this module. @@ -197,6 +204,11 @@ pub trait Trait: system::Trait + Sized { /// a majority-carries referendum. type ExternalMajorityOrigin: EnsureOrigin; + /// Origin from which the next referendum proposed by the external majority may be immediately + /// tabled to vote asynchronously in a similar manner to the emergency origin. It remains a + /// majority-carries vote. + type ExternalPushOrigin: EnsureOrigin; + /// Origin from which emergency referenda may be scheduled. type EmergencyOrigin: EnsureOrigin; @@ -241,7 +253,6 @@ impl ReferendumInfo as Democracy { - /// The number of (public) proposals that have been made so far. pub PublicPropCount get(public_prop_count) build(|_| 0 as PropIndex) : PropIndex; /// The public proposals. Unsorted. @@ -318,6 +329,28 @@ decl_event!( decl_module! { pub struct Module for enum Call where origin: T::Origin { + /// The minimum period of locking and the period between a proposal being approved and enacted. + /// + /// It should generally be a little more than the unstake period to ensure that + /// voting stakers have an opportunity to remove themselves from the system in the case where + /// they are on the losing side of a vote. + const EnactmentPeriod: T::BlockNumber = T::EnactmentPeriod::get(); + + /// How often (in blocks) new public referenda are launched. + const LaunchPeriod: T::BlockNumber = T::LaunchPeriod::get(); + + /// How often (in blocks) to check for new votes. + const VotingPeriod: T::BlockNumber = T::VotingPeriod::get(); + + /// The minimum amount to be used as a deposit for a public referendum proposal. + const MinimumDeposit: BalanceOf = T::MinimumDeposit::get(); + + /// Minimum voting period allowed for an emergency referendum. + const EmergencyVotingPeriod: T::BlockNumber = T::EmergencyVotingPeriod::get(); + + /// Period in blocks where an external proposal may not be re-submitted after being vetoed. + const CooloffPeriod: T::BlockNumber = T::CooloffPeriod::get(); + fn deposit_event() = default; /// Propose a sensitive action to be taken. @@ -337,7 +370,7 @@ decl_module! { .map_err(|_| "proposer's balance too low")?; let index = Self::public_prop_count(); - >::put(index + 1); + PublicPropCount::put(index + 1); >::insert(index, (value, vec![who.clone()])); let mut props = Self::public_props(); @@ -415,12 +448,7 @@ decl_module! { // resubmission in the case of a mistakenly low `vote_period`; better to just let the // referendum take place with the lowest valid value. let period = voting_period.max(T::EmergencyVotingPeriod::get()); - Self::inject_referendum( - now + period, - *proposal, - threshold, - delay, - ).map(|_| ())?; + Self::inject_referendum(now + period, *proposal, threshold, delay).map(|_| ())?; } /// Schedule an emergency cancellation of a referendum. Cannot happen twice to the same @@ -460,6 +488,31 @@ decl_module! { >::put((*proposal, VoteThreshold::SimpleMajority)); } + /// Schedule the currently externally-proposed majority-carries referendum to be tabled + /// immediately. If there is no externally-proposed referendum currently, or if there is one + /// but it is not a majority-carries referendum then it fails. + /// + /// - `proposal_hash`: The hash of the current external proposal. + /// - `voting_period`: The period that is allowed for voting on this proposal. + /// - `delay`: The number of block after voting has ended in approval and this should be + /// enacted. Increased to `EmergencyVotingPeriod` if too low. + fn external_push(origin, + proposal_hash: T::Hash, + voting_period: T::BlockNumber, + delay: T::BlockNumber + ) { + T::ExternalPushOrigin::ensure_origin(origin)?; + let (proposal, threshold) = >::get().ok_or("no proposal made")?; + ensure!(threshold == VoteThreshold::SimpleMajority, "next external proposal not simple majority"); + ensure!(proposal_hash == T::Hashing::hash_of(&proposal), "invalid hash"); + + >::kill(); + let now = >::block_number(); + // We don't consider it an error if `vote_period` is too low, like `emergency_propose`. + let period = voting_period.max(T::EmergencyVotingPeriod::get()); + Self::inject_referendum(now + period, proposal, threshold, delay).map(|_| ())?; + } + /// Veto and blacklist the external proposal hash. fn veto_external(origin, proposal_hash: T::Hash) { let who = T::VetoOrigin::ensure_origin(origin)?; @@ -485,16 +538,19 @@ decl_module! { } /// Remove a referendum. - fn cancel_referendum(#[compact] ref_index: ReferendumIndex) { + fn cancel_referendum(origin, #[compact] ref_index: ReferendumIndex) { + ensure_root(origin)?; Self::clear_referendum(ref_index); } /// Cancel a proposal queued for enactment. fn cancel_queued( + origin, #[compact] when: T::BlockNumber, #[compact] which: u32, #[compact] what: ReferendumIndex ) { + ensure_root(origin)?; let which = which as usize; let mut items = >::get(when); if items.get(which).and_then(Option::as_ref).map_or(false, |x| x.1 == what) { @@ -703,7 +759,7 @@ impl Module { >::insert(proxy, stash) } - /// Start a referendum. Can be called directly by the council. + /// Start a referendum. pub fn internal_start_referendum( proposal: T::Proposal, threshold: VoteThreshold, @@ -717,7 +773,7 @@ impl Module { ) } - /// Remove a referendum. Can be called directly by the council. + /// Remove a referendum. pub fn internal_cancel_referendum(ref_index: ReferendumIndex) { Self::deposit_event(RawEvent::Cancelled(ref_index)); >::clear_referendum(ref_index); @@ -751,7 +807,7 @@ impl Module { Err("Cannot inject a referendum that ends earlier than preceeding referendum")? } - >::put(ref_index + 1); + ReferendumCount::put(ref_index + 1); let item = ReferendumInfo { end, proposal, threshold, delay }; >::insert(ref_index, item); Self::deposit_event(RawEvent::Started(ref_index, threshold)); @@ -775,7 +831,7 @@ impl Module { /// Table the next waiting proposal for a vote. fn launch_next(now: T::BlockNumber) -> Result { - if >::take() { + if LastTabledWasExternal::take() { Self::launch_public(now).or_else(|_| Self::launch_external(now)) } else { Self::launch_external(now).or_else(|_| Self::launch_public(now)) @@ -785,7 +841,7 @@ impl Module { /// Table the waiting external proposal for a vote, if there is one. fn launch_external(now: T::BlockNumber) -> Result { if let Some((proposal, threshold)) = >::take() { - >::put(true); + LastTabledWasExternal::put(true); Self::deposit_event(RawEvent::ExternalTabled); Self::inject_referendum( now + T::VotingPeriod::get(), @@ -875,7 +931,7 @@ impl Module { } else { Self::deposit_event(RawEvent::NotPassed(index)); } - >::put(index + 1); + NextTally::put(index + 1); Ok(()) } @@ -917,9 +973,7 @@ mod tests { traits::Contains }; use substrate_primitives::{H256, Blake2Hasher}; - use primitives::BuildStorage; - use primitives::traits::{BlakeTwo256, IdentityLookup, Bounded}; - use primitives::testing::Header; + use primitives::{traits::{BlakeTwo256, IdentityLookup, Bounded}, testing::Header}; use balances::BalanceLock; use system::EnsureSignedBy; @@ -942,6 +996,9 @@ mod tests { // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, Eq, PartialEq, Debug)] pub struct Test; + parameter_types! { + pub const BlockHashCount: u64 = 250; + } impl system::Trait for Test { type Origin = Origin; type Index = u64; @@ -952,6 +1009,14 @@ mod tests { type Lookup = IdentityLookup; type Header = Header; type Event = (); + type BlockHashCount = BlockHashCount; + } + parameter_types! { + pub const ExistentialDeposit: u64 = 0; + pub const TransferFee: u64 = 0; + pub const CreationFee: u64 = 0; + pub const TransactionBaseFee: u64 = 0; + pub const TransactionByteFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; @@ -961,6 +1026,11 @@ mod tests { type TransactionPayment = (); type TransferPayment = (); type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type TransferFee = TransferFee; + type CreationFee = CreationFee; + type TransactionBaseFee = TransactionBaseFee; + type TransactionByteFee = TransactionByteFee; } parameter_types! { pub const LaunchPeriod: u64 = 2; @@ -993,24 +1063,20 @@ mod tests { type EmergencyOrigin = EnsureSignedBy; type ExternalOrigin = EnsureSignedBy; type ExternalMajorityOrigin = EnsureSignedBy; + type ExternalPushOrigin = EnsureSignedBy; type CancellationOrigin = EnsureSignedBy; type VetoOrigin = EnsureSignedBy; type CooloffPeriod = CooloffPeriod; } fn new_test_ext() -> runtime_io::TestExternalities { - let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; - t.extend(balances::GenesisConfig::{ - transaction_base_fee: 0, - transaction_byte_fee: 0, + let mut t = system::GenesisConfig::default().build_storage::().unwrap(); + balances::GenesisConfig::{ balances: vec![(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)], - existential_deposit: 0, - transfer_fee: 0, - creation_fee: 0, vesting: vec![], - }.build_storage().unwrap().0); - t.extend(GenesisConfig::::default().build_storage().unwrap().0); - runtime_io::TestExternalities::new(t) + }.assimilate_storage(&mut t.0, &mut t.1).unwrap(); + GenesisConfig::default().assimilate_storage(&mut t.0, &mut t.1).unwrap(); + runtime_io::TestExternalities::new_with_children(t) } type System = system::Module; @@ -1363,6 +1429,46 @@ mod tests { }); } + #[test] + fn external_push_referendum_works() { + with_externalities(&mut new_test_ext(), || { + System::set_block_number(0); + let h = BlakeTwo256::hash_of(&set_balance_proposal(2)); + assert_noop!(Democracy::external_push(Origin::signed(5), h, 3, 2), "no proposal made"); + assert_ok!(Democracy::external_propose_majority( + Origin::signed(3), + Box::new(set_balance_proposal(2)) + )); + assert_noop!(Democracy::external_push(Origin::signed(1), h, 3, 2), "Invalid origin"); + assert_ok!(Democracy::external_push(Origin::signed(5), h, 0, 0)); + assert_eq!( + Democracy::referendum_info(0), + Some(ReferendumInfo { + end: 1, + proposal: set_balance_proposal(2), + threshold: VoteThreshold::SimpleMajority, + delay: 0, + }) + ); + }); + } + + #[test] + fn external_push_referendum_fails_when_no_simple_majority() { + with_externalities(&mut new_test_ext(), || { + System::set_block_number(0); + let h = BlakeTwo256::hash_of(&set_balance_proposal(2)); + assert_ok!(Democracy::external_propose( + Origin::signed(2), + Box::new(set_balance_proposal(2)) + )); + assert_noop!( + Democracy::external_push(Origin::signed(5), h, 3, 2), + "next external proposal not simple majority" + ); + }); + } + #[test] fn locked_for_should_work() { with_externalities(&mut new_test_ext(), || { @@ -1440,9 +1546,9 @@ mod tests { Some((set_balance_proposal(2), 0)) ]); - assert_noop!(Democracy::cancel_queued(3, 0, 0), "proposal not found"); - assert_noop!(Democracy::cancel_queued(4, 1, 0), "proposal not found"); - assert_ok!(Democracy::cancel_queued(4, 0, 0)); + assert_noop!(Democracy::cancel_queued(Origin::ROOT, 3, 0, 0), "proposal not found"); + assert_noop!(Democracy::cancel_queued(Origin::ROOT, 4, 1, 0), "proposal not found"); + assert_ok!(Democracy::cancel_queued(Origin::ROOT, 4, 0, 0)); assert_eq!(Democracy::dispatch_queue(4), vec![None]); }); } @@ -1741,7 +1847,7 @@ mod tests { 0 ).unwrap(); assert_ok!(Democracy::vote(Origin::signed(1), r, AYE)); - assert_ok!(Democracy::cancel_referendum(r.into())); + assert_ok!(Democracy::cancel_referendum(Origin::ROOT, r.into())); next_block(); next_block(); diff --git a/srml/elections/Cargo.toml b/srml/elections/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..cd0a43aeb53945958fc7f860f2da54632dc817e8 --- /dev/null +++ b/srml/elections/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "srml-elections" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +serde = { version = "1.0", optional = true } +safe-mix = { version = "1.0", default-features = false} +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } +substrate-primitives = { path = "../../core/primitives", default-features = false } +rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } +runtime_io = { package = "sr-io", path = "../../core/sr-io", default-features = false } +primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } +srml-support = { path = "../support", default-features = false } +system = { package = "srml-system", path = "../system", default-features = false } + +[dev-dependencies] +hex-literal = "0.2.0" +balances = { package = "srml-balances", path = "../balances" } + +[features] +default = ["std"] +std = [ + "safe-mix/std", + "parity-codec/std", + "substrate-primitives/std", + "rstd/std", + "serde", + "runtime_io/std", + "srml-support/std", + "primitives/std", + "system/std", +] diff --git a/srml/elections/src/lib.rs b/srml/elections/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..80324ecefbdaf76b41dab4be9e5913ef3c627ffe --- /dev/null +++ b/srml/elections/src/lib.rs @@ -0,0 +1,2851 @@ +// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +//! Election module for stake-weighted membership selection of a collective. +//! +//! The composition of a set of account IDs works according to one or more approval votes +//! weighted by stake. There is a partial carry-over facility to give greater weight to those +//! whose voting is serially unsuccessful. + +#![cfg_attr(not(feature = "std"), no_std)] +#![recursion_limit="128"] + +use rstd::prelude::*; +use primitives::traits::{Zero, One, StaticLookup, Bounded, Saturating}; +use runtime_io::print; +use srml_support::{ + StorageValue, StorageMap, + dispatch::Result, decl_storage, decl_event, ensure, decl_module, + traits::{ + Currency, ExistenceRequirement, Get, LockableCurrency, LockIdentifier, + OnUnbalanced, ReservableCurrency, WithdrawReason, WithdrawReasons, ChangeMembers + } +}; +use parity_codec::{Encode, Decode}; +use system::{self, ensure_signed, ensure_root}; + +// no polynomial attacks: +// +// all unbonded public operations should be constant time. +// all other public operations must be linear time in terms of prior public operations and: +// - those "valid" ones that cost nothing be limited to a constant number per single protected +// operation +// - the rest costing the same order as the computational complexity +// all protected operations must complete in at most O(public operations) +// +// we assume "beneficial" transactions will have the same access as attack transactions. +// +// any storage requirements should be bonded by the same order as the volume. + +// public operations: +// - express approvals (you pay in a "voter" bond the first time you do this; O(1); one extra DB +// entry, one DB change) +// - remove active voter (you get your "voter" bond back; O(1); one fewer DB entry, one DB change) +// - remove inactive voter (either you or the target is removed; if the target, you get their +// "voter" bond back; O(1); one fewer DB entry, one DB change) +// - submit candidacy (you pay a "candidate" bond; O(1); one extra DB entry, two DB changes) +// - present winner/runner-up (you may pay a "presentation" bond of O(voters) if the presentation +// is invalid; O(voters) compute; ) protected operations: +// - remove candidacy (remove all votes for a candidate) (one fewer DB entry, two DB changes) + +// to avoid a potentially problematic case of not-enough approvals prior to voting causing a +// back-to-back votes that have no way of ending, then there's a forced grace period between votes. +// to keep the system as stateless as possible (making it a bit easier to reason about), we just +// restrict when votes can begin to blocks that lie on boundaries (`voting_period`). + +// for an approval vote of C members: + +// top K runners-up are maintained between votes. all others are discarded. +// - candidate removed & bond returned when elected. +// - candidate removed & bond burned when discarded. + +// at the point that the vote ends (), all voters' balances are snapshotted. + +// for B blocks following, there's a counting period whereby each of the candidates that believe +// they fall in the top K+C voted can present themselves. they get the total stake +// recorded (based on the snapshot); an ordered list is maintained (the leaderboard). Noone may +// present themselves that, if elected, would result in being included twice in the collective +// (important since existing members will have their approval votes as it may be that they +// don't get removed), nor if existing presenters would mean they're not in the top K+C. + +// following B blocks, the top C candidates are elected and have their bond returned. the top C +// candidates and all other candidates beyond the top C+K are cleared. + +// vote-clearing happens lazily; for an approval to count, the most recent vote at the time of the +// voter's most recent vote must be no later than the most recent vote at the time that the +// candidate in the approval position was registered there. as candidates are removed from the +// register and others join in their place, this prevents an approval meant for an earlier candidate +// being used to elect a new candidate. + +// the candidate list increases as needed, but the contents (though not really the capacity) reduce +// after each vote as all but K entries are cleared. newly registering candidates must use cleared +// entries before they increase the capacity. + +/// The activity status of a voter. +#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, Default)] +#[cfg_attr(feature = "std", derive(Debug))] +pub struct VoterInfo { + /// Last VoteIndex in which this voter assigned (or initialized) approvals. + last_active: VoteIndex, + /// Last VoteIndex in which one of this voter's approvals won. + /// Note that `last_win = N` indicates a last win at index `N-1`, hence `last_win = 0` means no + /// win ever. + last_win: VoteIndex, + /// The amount of stored weight as a result of not winning but changing approvals. + pot: Balance, + /// Current staked amount. A lock equal to this value always exists. + stake: Balance, +} + +/// Used to demonstrate the status of a particular index in the global voter list. +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "std", derive(Debug))] +pub enum CellStatus { + /// Any out of bound index. Means a push a must happen to the chunk pointed by `NextVoterSet`. + /// Voting fee is applied in case a new chunk is created. + Head, + /// Already occupied by another voter. Voting fee is applied. + Occupied, + /// Empty hole which should be filled. No fee will be applied. + Hole, +} + +const MODULE_ID: LockIdentifier = *b"py/elect"; + +pub const VOTER_SET_SIZE: usize = 64; +pub const APPROVAL_SET_SIZE: usize = 8; + +type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +type NegativeImbalanceOf = + <::Currency as Currency<::AccountId>>::NegativeImbalance; + +type SetIndex = u32; +pub type VoteIndex = u32; + +// all three must be in sync. +type ApprovalFlag = u32; +pub const APPROVAL_FLAG_MASK: ApprovalFlag = 0x8000_0000; +pub const APPROVAL_FLAG_LEN: usize = 32; + +pub const DEFAULT_CANDIDACY_BOND: u32 = 9; +pub const DEFAULT_VOTING_BOND: u32 = 0; +pub const DEFAULT_VOTING_FEE: u32 = 0; +pub const DEFAULT_PRESENT_SLASH_PER_VOTER: u32 = 1; +pub const DEFAULT_CARRY_COUNT: u32 = 2; +pub const DEFAULT_INACTIVE_GRACE_PERIOD: u32 = 1; +pub const DEFAULT_VOTING_PERIOD: u32 = 1000; +pub const DEFAULT_DECAY_RATIO: u32 = 24; + +pub trait Trait: system::Trait { + type Event: From> + Into<::Event>; + + /// The currency that people are electing with. + type Currency: + LockableCurrency + + ReservableCurrency; + + /// Handler for the unbalanced reduction when slashing a validator. + type BadPresentation: OnUnbalanced>; + + /// Handler for the unbalanced reduction when slashing an invalid reaping attempt. + type BadReaper: OnUnbalanced>; + + /// Handler for the unbalanced reduction when submitting a bad `voter_index`. + type BadVoterIndex: OnUnbalanced>; + + /// Handler for the unbalanced reduction when a candidate has lost (and is not a runner up) + type LoserCandidate: OnUnbalanced>; + + /// What to do when the members change. + type ChangeMembers: ChangeMembers; + + /// How much should be locked up in order to submit one's candidacy. A reasonable + /// default value is 9. + type CandidacyBond: Get>; + + /// How much should be locked up in order to be able to submit votes. + type VotingBond: Get>; + + /// The amount of fee paid upon each vote submission, unless if they submit a + /// _hole_ index and replace it. + type VotingFee: Get>; + + /// The punishment, per voter, if you provide an invalid presentation. A + /// reasonable default value is 1. + type PresentSlashPerVoter: Get>; + + /// How many runners-up should have their approvals persist until the next + /// vote. A reasonable default value is 2. + type CarryCount: Get; + + /// How many vote indices need to go by after a target voter's last vote before + /// they can be reaped if their approvals are moot. A reasonable default value + /// is 1. + type InactiveGracePeriod: Get; + + /// How often (in blocks) to check for new votes. A reasonable default value + /// is 1000. + type VotingPeriod: Get; + + /// Decay factor of weight when being accumulated. It should typically be set to + /// __at least__ `membership_size -1` to keep the collective secure. + /// When set to `N`, it indicates `(1/N)^t` of staked is decayed at weight + /// increment step `t`. 0 will result in no weight being added at all (normal + /// approval voting). A reasonable default value is 24. + type DecayRatio: Get; +} + +decl_storage! { + trait Store for Module as Council { + // ---- parameters + /// How long to give each top candidate to present themselves after the vote ends. + pub PresentationDuration get(presentation_duration) config(): T::BlockNumber; + /// How long each position is active for. + pub TermDuration get(term_duration) config(): T::BlockNumber; + /// Number of accounts that should constitute the collective. + pub DesiredSeats get(desired_seats) config(): u32; + + // ---- permanent state (always relevant, changes only at the finalization of voting) + /// The current membership. When there's a vote going on, this should still be used for executive + /// matters. The block number (second element in the tuple) is the block that their position is + /// active until (calculated by the sum of the block number when the member was elected + /// and their term duration). + pub Members get(members) config(): Vec<(T::AccountId, T::BlockNumber)>; + /// The total number of vote rounds that have happened or are in progress. + pub VoteCount get(vote_index): VoteIndex; + + // ---- persistent state (always relevant, changes constantly) + /// A list of votes for each voter. The votes are stored as numeric values and parsed in a bit-wise manner. + /// + /// In order to get a human-readable representation (`Vec`), use [`all_approvals_of`]. + /// + /// Furthermore, each vector of scalars is chunked with the cap of `APPROVAL_SET_SIZE`. + pub ApprovalsOf get(approvals_of): map (T::AccountId, SetIndex) => Vec; + /// The vote index and list slot that the candidate `who` was registered or `None` if they are not + /// currently registered. + pub RegisterInfoOf get(candidate_reg_info): map T::AccountId => Option<(VoteIndex, u32)>; + /// Basic information about a voter. + pub VoterInfoOf get(voter_info): map T::AccountId => Option>>; + /// The present voter list (chunked and capped at [`VOTER_SET_SIZE`]). + pub Voters get(voters): map SetIndex => Vec>; + /// the next free set to store a voter in. This will keep growing. + pub NextVoterSet get(next_nonfull_voter_set): SetIndex = 0; + /// Current number of Voters. + pub VoterCount get(voter_count): SetIndex = 0; + /// The present candidate list. + pub Candidates get(candidates): Vec; // has holes + /// Current number of active candidates + pub CandidateCount get(candidate_count): u32; + + // ---- temporary state (only relevant during finalization/presentation) + /// The accounts holding the seats that will become free on the next tally. + pub NextFinalize get(next_finalize): Option<(T::BlockNumber, u32, Vec)>; + /// Get the leaderboard if we're in the presentation phase. The first element is the weight of each entry; + /// It may be the direct summed approval stakes, or a weighted version of it. + pub Leaderboard get(leaderboard): Option, T::AccountId)> >; // ORDERED low -> high + + /// Who is able to vote for whom. Value is the fund-holding account, key is the + /// vote-transaction-sending account. + pub Proxy get(proxy): map T::AccountId => Option; + } +} + +decl_module! { + pub struct Module for enum Call where origin: T::Origin { + /// How much should be locked up in order to submit one's candidacy. A reasonable + /// default value is 9. + const CandidacyBond: BalanceOf = T::CandidacyBond::get(); + + /// How much should be locked up in order to be able to submit votes. + const VotingBond: BalanceOf = T::VotingBond::get(); + + /// The amount of fee paid upon each vote submission, unless if they submit a + /// _hole_ index and replace it. + const VotingFee: BalanceOf = T::VotingFee::get(); + + /// The punishment, per voter, if you provide an invalid presentation. A + /// reasonable default value is 1. + const PresentSlashPerVoter: BalanceOf = T::PresentSlashPerVoter::get(); + + /// How many runners-up should have their approvals persist until the next + /// vote. A reasonable default value is 2. + const CarryCount: u32 = T::CarryCount::get(); + + /// How many vote indices need to go by after a target voter's last vote before + /// they can be reaped if their approvals are moot. A reasonable default value + /// is 1. + const InactiveGracePeriod: VoteIndex = T::InactiveGracePeriod::get(); + + /// How often (in blocks) to check for new votes. A reasonable default value + /// is 1000. + const VotingPeriod: T::BlockNumber = T::VotingPeriod::get(); + + /// Decay factor of weight when being accumulated. It should typically be set to + /// __at least__ `membership_size -1` to keep the collective secure. + /// When set to `N`, it indicates `(1/N)^t` of staked is decayed at weight + /// increment step `t`. 0 will result in no weight being added at all (normal + /// approval voting). A reasonable default value is 24. + const DecayRatio: u32 = T::DecayRatio::get(); + + fn deposit_event() = default; + + /// Set candidate approvals. Approval slots stay valid as long as candidates in those slots + /// are registered. + /// + /// Locks the total balance of caller indefinitely. + /// Only [`retract_voter`] or [`reap_inactive_voter`] can unlock the balance. + /// + /// `hint` argument is interpreted differently based on: + /// - if `origin` is setting approvals for the first time: The index will be checked + /// for being a valid _hole_ in the voter list. + /// - if the hint is correctly pointing to a hole, no fee is deducted from `origin`. + /// - Otherwise, the call will succeed but the index is ignored and simply a push to the last chunk + /// with free space happens. If the new push causes a new chunk to be created, a fee indicated by + /// [`VotingFee`] is deducted. + /// - if `origin` is already a voter: the index __must__ be valid and point to the correct + /// position of the `origin` in the current voters list. + /// + /// Note that any trailing `false` votes in `votes` is ignored; In approval voting, not voting for a candidate + /// and voting false, are equal. + /// + /// # + /// - O(1). + /// - Two extra DB entries, one DB change. + /// - Argument `votes` is limited in length to number of candidates. + /// # + fn set_approvals(origin, votes: Vec, #[compact] index: VoteIndex, hint: SetIndex) -> Result { + let who = ensure_signed(origin)?; + Self::do_set_approvals(who, votes, index, hint) + } + + /// Set candidate approvals from a proxy. Approval slots stay valid as long as candidates in those slots + /// are registered. + /// + /// # + /// - Same as `set_approvals` with one additional storage read. + /// # + fn proxy_set_approvals(origin, + votes: Vec, + #[compact] index: VoteIndex, + hint: SetIndex + ) -> Result { + let who = Self::proxy(ensure_signed(origin)?).ok_or("not a proxy")?; + Self::do_set_approvals(who, votes, index, hint) + } + + /// Remove a voter. For it not to be a bond-consuming no-op, all approved candidate indices + /// must now be either unregistered or registered to a candidate that registered the slot after + /// the voter gave their last approval set. + /// + /// Both indices must be provided as explained in [`voter_at`] function. + /// + /// May be called by anyone. Returns the voter deposit to `signed`. + /// + /// # + /// - O(1). + /// - Two fewer DB entries, one DB change. + /// # + fn reap_inactive_voter( + origin, + #[compact] reporter_index: u32, + who: ::Source, + #[compact] who_index: u32, + #[compact] assumed_vote_index: VoteIndex + ) { + let reporter = ensure_signed(origin)?; + let who = T::Lookup::lookup(who)?; + + ensure!(!Self::presentation_active(), "cannot reap during presentation period"); + ensure!(Self::voter_info(&reporter).is_some(), "reporter must be a voter"); + + let info = Self::voter_info(&who).ok_or("target for inactivity cleanup must be active")?; + let last_active = info.last_active; + + ensure!(assumed_vote_index == Self::vote_index(), "vote index not current"); + ensure!( + assumed_vote_index > last_active + T::InactiveGracePeriod::get(), + "cannot reap during grace period" + ); + + let reporter_index = reporter_index as usize; + let who_index = who_index as usize; + let assumed_reporter = Self::voter_at(reporter_index).ok_or("invalid reporter index")?; + let assumed_who = Self::voter_at(who_index).ok_or("invalid target index")?; + + ensure!(assumed_reporter == reporter, "bad reporter index"); + ensure!(assumed_who == who, "bad target index"); + + // will definitely kill one of reporter or who now. + + let valid = !Self::all_approvals_of(&who).iter() + .zip(Self::candidates().iter()) + .any(|(&appr, addr)| + appr && + *addr != T::AccountId::default() && + // defensive only: all items in candidates list are registered + Self::candidate_reg_info(addr).map_or(false, |x| x.0 <= last_active) + ); + + Self::remove_voter( + if valid { &who } else { &reporter }, + if valid { who_index } else { reporter_index } + ); + + T::Currency::remove_lock( + MODULE_ID, + if valid { &who } else { &reporter } + ); + + if valid { + // This only fails if `reporter` doesn't exist, which it clearly must do since its the origin. + // Still, it's no more harmful to propagate any error at this point. + T::Currency::repatriate_reserved(&who, &reporter, T::VotingBond::get())?; + Self::deposit_event(RawEvent::VoterReaped(who, reporter)); + } else { + let imbalance = T::Currency::slash_reserved(&reporter, T::VotingBond::get()).0; + T::BadReaper::on_unbalanced(imbalance); + Self::deposit_event(RawEvent::BadReaperSlashed(reporter)); + } + } + + /// Remove a voter. All votes are cancelled and the voter deposit is returned. + /// + /// The index must be provided as explained in [`voter_at`] function. + /// + /// Also removes the lock on the balance of the voter. See [`do_set_approvals()`]. + /// + /// # + /// - O(1). + /// - Two fewer DB entries, one DB change. + /// # + fn retract_voter(origin, #[compact] index: u32) { + let who = ensure_signed(origin)?; + + ensure!(!Self::presentation_active(), "cannot retract when presenting"); + ensure!(>::exists(&who), "cannot retract non-voter"); + let index = index as usize; + let voter = Self::voter_at(index).ok_or("retraction index invalid")?; + ensure!(voter == who, "retraction index mismatch"); + + Self::remove_voter(&who, index); + T::Currency::unreserve(&who, T::VotingBond::get()); + T::Currency::remove_lock(MODULE_ID, &who); + } + + /// Submit oneself for candidacy. + /// + /// Account must have enough transferrable funds in it to pay the bond. + /// + /// NOTE: if `origin` has already assigned approvals via [`set_approvals`], + /// it will NOT have any usable funds to pass candidacy bond and must first retract. + /// Note that setting approvals will lock the entire balance of the voter until + /// retraction or being reported. + /// + /// # + /// - Independent of input. + /// - Three DB changes. + /// # + fn submit_candidacy(origin, #[compact] slot: u32) { + let who = ensure_signed(origin)?; + + ensure!(!Self::is_a_candidate(&who), "duplicate candidate submission"); + let slot = slot as usize; + let count = Self::candidate_count() as usize; + let candidates = Self::candidates(); + ensure!( + (slot == count && count == candidates.len()) || + (slot < candidates.len() && candidates[slot] == T::AccountId::default()), + "invalid candidate slot" + ); + // NOTE: This must be last as it has side-effects. + T::Currency::reserve(&who, T::CandidacyBond::get()) + .map_err(|_| "candidate has not enough funds")?; + + >::insert(&who, (Self::vote_index(), slot as u32)); + let mut candidates = candidates; + if slot == candidates.len() { + candidates.push(who); + } else { + candidates[slot] = who; + } + >::put(candidates); + CandidateCount::put(count as u32 + 1); + } + + /// Claim that `signed` is one of the top Self::carry_count() + current_vote().1 candidates. + /// Only works if the `block_number >= current_vote().0` and `< current_vote().0 + presentation_duration()` + /// `signed` should have at least + /// + /// # + /// - O(voters) compute. + /// - One DB change. + /// # + fn present_winner( + origin, + candidate: ::Source, + #[compact] total: BalanceOf, + #[compact] index: VoteIndex + ) -> Result { + let who = ensure_signed(origin)?; + ensure!( + !total.is_zero(), + "stake deposited to present winner and be added to leaderboard should be non-zero" + ); + + let candidate = T::Lookup::lookup(candidate)?; + ensure!(index == Self::vote_index(), "index not current"); + let (_, _, expiring) = Self::next_finalize().ok_or("cannot present outside of presentation period")?; + let bad_presentation_punishment = + T::PresentSlashPerVoter::get() + * BalanceOf::::from(Self::voter_count() as u32); + ensure!( + T::Currency::can_slash(&who, bad_presentation_punishment), + "presenter must have sufficient slashable funds" + ); + + let mut leaderboard = Self::leaderboard().ok_or("leaderboard must exist while present phase active")?; + ensure!(total > leaderboard[0].0, "candidate not worthy of leaderboard"); + + if let Some(p) = Self::members().iter().position(|&(ref c, _)| c == &candidate) { + ensure!(p < expiring.len(), "candidate must not form a duplicated member if elected"); + } + + let voters = Self::all_voters(); + let (registered_since, candidate_index): (VoteIndex, u32) = + Self::candidate_reg_info(&candidate).ok_or("presented candidate must be current")?; + let actual_total = voters.iter() + .filter_map(|maybe_voter| maybe_voter.as_ref()) + .filter_map(|voter| match Self::voter_info(voter) { + Some(b) if b.last_active >= registered_since => { + let last_win = b.last_win; + let now = Self::vote_index(); + let stake = b.stake; + let offset = Self::get_offset(stake, now - last_win); + let weight = stake + offset + b.pot; + if Self::approvals_of_at(voter, candidate_index as usize) { + Some(weight) + } else { None } + }, + _ => None, + }) + .fold(Zero::zero(), |acc, n| acc + n); + let dupe = leaderboard.iter().find(|&&(_, ref c)| c == &candidate).is_some(); + if total == actual_total && !dupe { + // insert into leaderboard + leaderboard[0] = (total, candidate); + leaderboard.sort_by_key(|&(t, _)| t); + >::put(leaderboard); + Ok(()) + } else { + // we can rest assured it will be Ok since we checked `can_slash` earlier; still + // better safe than sorry. + let imbalance = T::Currency::slash(&who, bad_presentation_punishment).0; + T::BadPresentation::on_unbalanced(imbalance); + Err(if dupe { "duplicate presentation" } else { "incorrect total" }) + } + } + + /// Set the desired member count; if lower than the current count, then seats will not be up + /// election when they expire. If more, then a new vote will be started if one is not + /// already in progress. + fn set_desired_seats(origin, #[compact] count: u32) { + ensure_root(origin)?; + DesiredSeats::put(count); + } + + /// Remove a particular member from the set. This is effective immediately. + /// + /// Note: A tally should happen instantly (if not already in a presentation + /// period) to fill the seat if removal means that the desired members are not met. + fn remove_member(origin, who: ::Source) { + ensure_root(origin)?; + let who = T::Lookup::lookup(who)?; + let new_set: Vec<(T::AccountId, T::BlockNumber)> = Self::members() + .into_iter() + .filter(|i| i.0 != who) + .collect(); + >::put(&new_set); + let new_set = new_set.into_iter().map(|x| x.0).collect::>(); + T::ChangeMembers::change_members(&[], &[who], &new_set[..]); + } + + /// Set the presentation duration. If there is currently a vote being presented for, will + /// invoke `finalize_vote`. + fn set_presentation_duration(origin, #[compact] count: T::BlockNumber) { + ensure_root(origin)?; + >::put(count); + } + + /// Set the presentation duration. If there is current a vote being presented for, will + /// invoke `finalize_vote`. + fn set_term_duration(origin, #[compact] count: T::BlockNumber) { + ensure_root(origin)?; + >::put(count); + } + + fn on_initialize(n: T::BlockNumber) { + if let Err(e) = Self::end_block(n) { + print("Guru meditation"); + print(e); + } + } + } +} + +decl_event!( + pub enum Event where ::AccountId { + /// reaped voter, reaper + VoterReaped(AccountId, AccountId), + /// slashed reaper + BadReaperSlashed(AccountId), + /// A tally (for approval votes of seat(s)) has started. + TallyStarted(u32), + /// A tally (for approval votes of seat(s)) has ended (with one or more new members). + TallyFinalized(Vec, Vec), + } +); + +impl Module { + // exposed immutables. + + /// True if we're currently in a presentation period. + pub fn presentation_active() -> bool { + >::exists() + } + + /// If `who` a candidate at the moment? + pub fn is_a_candidate(who: &T::AccountId) -> bool { + >::exists(who) + } + + /// Iff the member `who` still has a seat at blocknumber `n` returns `true`. + pub fn will_still_be_member_at(who: &T::AccountId, n: T::BlockNumber) -> bool { + Self::members().iter() + .find(|&&(ref a, _)| a == who) + .map(|&(_, expires)| expires > n) + .unwrap_or(false) + } + + /// Determine the block that a vote can happen on which is no less than `n`. + pub fn next_vote_from(n: T::BlockNumber) -> T::BlockNumber { + let voting_period = T::VotingPeriod::get(); + (n + voting_period - One::one()) / voting_period * voting_period + } + + /// The block number on which the tally for the next election will happen. `None` only if the + /// desired seats of the set is zero. + pub fn next_tally() -> Option { + let desired_seats = Self::desired_seats(); + if desired_seats == 0 { + None + } else { + let c = Self::members(); + let (next_possible, count, coming) = + if let Some((tally_end, comers, leavers)) = Self::next_finalize() { + // if there's a tally in progress, then next tally can begin immediately afterwards + (tally_end, c.len() - leavers.len() + comers as usize, comers) + } else { + (>::block_number(), c.len(), 0) + }; + if count < desired_seats as usize { + Some(next_possible) + } else { + // next tally begins once enough members expire to bring members below desired. + if desired_seats <= coming { + // the entire amount of desired seats is less than those new members - we'll have + // to wait until they expire. + Some(next_possible + Self::term_duration()) + } else { + Some(c[c.len() - (desired_seats - coming) as usize].1) + } + }.map(Self::next_vote_from) + } + } + + // Private + /// Check there's nothing to do this block + fn end_block(block_number: T::BlockNumber) -> Result { + if (block_number % T::VotingPeriod::get()).is_zero() { + if let Some(number) = Self::next_tally() { + if block_number == number { + Self::start_tally(); + } + } + } + if let Some((number, _, _)) = Self::next_finalize() { + if block_number == number { + Self::finalize_tally()? + } + } + Ok(()) + } + + /// Remove a voter at a specified index from the system. + fn remove_voter(voter: &T::AccountId, index: usize) { + let (set_index, vec_index) = Self::split_index(index, VOTER_SET_SIZE); + let mut set = Self::voters(set_index); + set[vec_index] = None; + >::insert(set_index, set); + VoterCount::mutate(|c| *c = *c - 1); + Self::remove_all_approvals_of(voter); + >::remove(voter); + } + + /// Actually do the voting. + /// + /// The voter index must be provided as explained in [`voter_at`] function. + fn do_set_approvals(who: T::AccountId, votes: Vec, index: VoteIndex, hint: SetIndex) -> Result { + let candidates = Self::candidates(); + + ensure!(!Self::presentation_active(), "no approval changes during presentation period"); + ensure!(index == Self::vote_index(), "incorrect vote index"); + ensure!(!candidates.is_empty(), "amount of candidates to receive approval votes should be non-zero"); + // Prevent a vote from voters that provide a list of votes that exceeds the candidates length + // since otherwise an attacker may be able to submit a very long list of `votes` that far exceeds + // the amount of candidates and waste more computation than a reasonable voting bond would cover. + ensure!(candidates.len() >= votes.len(), "amount of candidate votes cannot exceed amount of candidates"); + + // Amount to be locked up. + let mut locked_balance = T::Currency::total_balance(&who); + let mut pot_to_set = Zero::zero(); + let hint = hint as usize; + + if let Some(info) = Self::voter_info(&who) { + // already a voter. Index must be valid. No fee. update pot. O(1) + let voter = Self::voter_at(hint).ok_or("invalid voter index")?; + ensure!(voter == who, "wrong voter index"); + + // write new accumulated offset. + let last_win = info.last_win; + let now = index; + let offset = Self::get_offset(info.stake, now - last_win); + pot_to_set = info.pot + offset; + } else { + // not yet a voter. Index _could be valid_. Fee might apply. Bond will be reserved O(1). + ensure!( + T::Currency::free_balance(&who) > T::VotingBond::get(), + "new voter must have sufficient funds to pay the bond" + ); + + let (set_index, vec_index) = Self::split_index(hint, VOTER_SET_SIZE); + match Self::cell_status(set_index, vec_index) { + CellStatus::Hole => { + // requested cell was a valid hole. + >::mutate(set_index, |set| set[vec_index] = Some(who.clone())); + }, + CellStatus::Head | CellStatus::Occupied => { + // Either occupied or out-of-range. + let next = Self::next_nonfull_voter_set(); + let mut set = Self::voters(next); + // Caused a new set to be created. Pay for it. + // This is the last potential error. Writes will begin afterwards. + if set.is_empty() { + let imbalance = T::Currency::withdraw( + &who, + T::VotingFee::get(), + WithdrawReason::Fee, + ExistenceRequirement::KeepAlive, + )?; + T::BadVoterIndex::on_unbalanced(imbalance); + // NOTE: this is safe since the `withdraw()` will check this. + locked_balance -= T::VotingFee::get(); + } + Self::checked_push_voter(&mut set, who.clone(), next); + >::insert(next, set); + } + } + + T::Currency::reserve(&who, T::VotingBond::get())?; + VoterCount::mutate(|c| *c = *c + 1); + } + + T::Currency::set_lock( + MODULE_ID, + &who, + locked_balance, + T::BlockNumber::max_value(), + WithdrawReasons::except(WithdrawReason::TransactionPayment), + ); + + >::insert( + &who, + VoterInfo::> { + last_active: index, + last_win: index, + stake: locked_balance, + pot: pot_to_set, + } + ); + Self::set_approvals_chunked(&who, votes); + + Ok(()) + } + + /// Close the voting, record the number of seats that are actually up for grabs. + fn start_tally() { + let members = Self::members(); + let desired_seats = Self::desired_seats() as usize; + let number = >::block_number(); + let expiring = members.iter().take_while(|i| i.1 <= number).map(|i| i.0.clone()).collect::>(); + let retaining_seats = members.len() - expiring.len(); + if retaining_seats < desired_seats { + let empty_seats = desired_seats - retaining_seats; + >::put((number + Self::presentation_duration(), empty_seats as u32, expiring)); + + // initialize leaderboard. + let leaderboard_size = empty_seats + T::CarryCount::get() as usize; + >::put(vec![(Zero::zero(), T::AccountId::default()); leaderboard_size]); + + Self::deposit_event(RawEvent::TallyStarted(empty_seats as u32)); + } + } + + /// Finalize the vote, removing each of the `removals` and inserting `seats` of the most approved + /// candidates in their place. If the total number of members is less than the desired membership + /// a new vote is started. + /// Clears all presented candidates, returning the bond of the elected ones. + fn finalize_tally() -> Result { + let (_, coming, expiring): (T::BlockNumber, u32, Vec) = + >::take().ok_or("finalize can only be called after a tally is started.")?; + let leaderboard: Vec<(BalanceOf, T::AccountId)> = >::take().unwrap_or_default(); + let new_expiry = >::block_number() + Self::term_duration(); + + // return bond to winners. + let candidacy_bond = T::CandidacyBond::get(); + let incoming: Vec<_> = leaderboard.iter() + .rev() + .take_while(|&&(b, _)| !b.is_zero()) + .take(coming as usize) + .map(|(_, a)| a) + .cloned() + .inspect(|a| { T::Currency::unreserve(a, candidacy_bond); }) + .collect(); + + // Update last win index for anyone voted for any of the incomings. + incoming.iter().filter_map(|i| Self::candidate_reg_info(i)).for_each(|r| { + let index = r.1 as usize; + Self::all_voters() + .iter() + .filter_map(|mv| mv.as_ref()) + .filter(|v| Self::approvals_of_at(*v, index)) + .for_each(|v| >::mutate(v, |a| { + if let Some(activity) = a { activity.last_win = Self::vote_index() + 1; } + })); + }); + let members = Self::members(); + let outgoing: Vec<_> = members.iter() + .take(expiring.len()) + .map(|a| a.0.clone()).collect(); + + // set the new membership set. + let mut new_set: Vec<_> = members + .into_iter() + .skip(expiring.len()) + .chain(incoming.iter().cloned().map(|a| (a, new_expiry))) + .collect(); + new_set.sort_by_key(|&(_, expiry)| expiry); + >::put(&new_set); + + let new_set = new_set.into_iter().map(|x| x.0).collect::>(); + T::ChangeMembers::change_members(&incoming, &outgoing, &new_set[..]); + + // clear all except runners-up from candidate list. + let candidates = Self::candidates(); + let mut new_candidates = vec![T::AccountId::default(); candidates.len()]; // shrink later. + let runners_up = leaderboard.into_iter() + .rev() + .take_while(|&(b, _)| !b.is_zero()) + .skip(coming as usize) + .filter_map(|(_, a)| Self::candidate_reg_info(&a).map(|i| (a, i.1))); + let mut count = 0u32; + for (address, slot) in runners_up { + new_candidates[slot as usize] = address; + count += 1; + } + for (old, new) in candidates.iter().zip(new_candidates.iter()) { + if old != new { + // removed - kill it + >::remove(old); + } + } + // discard any superfluous slots. + if let Some(last_index) = new_candidates.iter().rposition(|c| *c != T::AccountId::default()) { + new_candidates.truncate(last_index + 1); + } + + Self::deposit_event(RawEvent::TallyFinalized(incoming, outgoing)); + + >::put(new_candidates); + CandidateCount::put(count); + VoteCount::put(Self::vote_index() + 1); + Ok(()) + } + + fn checked_push_voter(set: &mut Vec>, who: T::AccountId, index: u32) { + let len = set.len(); + + // Defensive only: this should never happen. Don't push since it will break more things. + if len == VOTER_SET_SIZE { return; } + + set.push(Some(who)); + if len + 1 == VOTER_SET_SIZE { + NextVoterSet::put(index + 1); + } + } + + /// Get the set and vector index of a global voter index. + /// + /// Note that this function does not take holes into account. + /// See [`voter_at`]. + fn split_index(index: usize, scale: usize) -> (SetIndex, usize) { + let set_index = (index / scale) as u32; + let vec_index = index % scale; + (set_index, vec_index) + } + + /// Return a concatenated vector over all voter sets. + fn all_voters() -> Vec> { + let mut all = >::get(0); + let mut index = 1; + // NOTE: we could also use `Self::next_nonfull_voter_set()` here but that might change based + // on how we do chunking. This is more generic. + loop { + let next_set = >::get(index); + if next_set.is_empty() { + break; + } else { + index += 1; + all.extend(next_set); + } + } + all + } + + /// Shorthand for fetching a voter at a specific (global) index. + /// + /// NOTE: this function is used for checking indices. Yet, it does not take holes into account. + /// This means that any account submitting an index at any point in time should submit: + /// `VOTER_SET_SIZE * set_index + local_index`, meaning that you are ignoring all holes in the + /// first `set_index` sets. + fn voter_at(index: usize) -> Option { + let (set_index, vec_index) = Self::split_index(index, VOTER_SET_SIZE); + let set = Self::voters(set_index); + if vec_index < set.len() { + set[vec_index].clone() + } else { + None + } + } + + /// A more sophisticated version of `voter_at`. Will be kept separate as most often it is an overdue + /// compared to `voter_at`. Only used when setting approvals. + fn cell_status(set_index: SetIndex, vec_index: usize) -> CellStatus { + let set = Self::voters(set_index); + if vec_index < set.len() { + if let Some(_) = set[vec_index] { + CellStatus::Occupied + } else { + CellStatus::Hole + } + } else { + CellStatus::Head + } + } + + /// Sets the approval of a voter in a chunked manner. + fn set_approvals_chunked(who: &T::AccountId, approvals: Vec) { + let approvals_flag_vec = Self::bool_to_flag(approvals); + approvals_flag_vec + .chunks(APPROVAL_SET_SIZE) + .enumerate() + .for_each(|(index, slice)| >::insert((who.clone(), index as SetIndex), slice.to_vec())); + } + + /// shorthand for fetching a specific approval of a voter at a specific (global) index. + /// + /// Using this function to read a vote is preferred as it reads `APPROVAL_SET_SIZE` items of type + /// `ApprovalFlag` from storage at most; not all of them. + /// + /// Note that false is returned in case of no-vote or an explicit `false`. + fn approvals_of_at(who: &T::AccountId, index: usize) -> bool { + let (flag_index, bit) = Self::split_index(index, APPROVAL_FLAG_LEN); + let (set_index, vec_index) = Self::split_index(flag_index as usize, APPROVAL_SET_SIZE); + let set = Self::approvals_of((who.clone(), set_index)); + if vec_index < set.len() { + // This is because bit_at treats numbers in lsb -> msb order. + let reversed_index = set.len() - 1 - vec_index; + Self::bit_at(set[reversed_index], bit) + } else { + false + } + } + + /// Return true of the bit `n` of scalar `x` is set to `1` and false otherwise. + fn bit_at(x: ApprovalFlag, n: usize) -> bool { + if n < APPROVAL_FLAG_LEN { + // x & ( APPROVAL_FLAG_MASK >> n ) != 0 + x & ( 1 << n ) != 0 + } else { + false + } + } + + /// Convert a vec of boolean approval flags to a vec of integers, as denoted by + /// the type `ApprovalFlag`. see `bool_to_flag_should_work` test for examples. + pub fn bool_to_flag(x: Vec) -> Vec { + let mut result: Vec = Vec::with_capacity(x.len() / APPROVAL_FLAG_LEN); + if x.is_empty() { + return result; + } + result.push(0); + let mut index = 0; + let mut counter = 0; + loop { + let shl_index = counter % APPROVAL_FLAG_LEN; + result[index] += (if x[counter] { 1 } else { 0 }) << shl_index; + counter += 1; + if counter > x.len() - 1 { break; } + if counter % APPROVAL_FLAG_LEN == 0 { + result.push(0); + index += 1; + } + } + result + } + + /// Convert a vec of flags (u32) to boolean. + pub fn flag_to_bool(chunk: Vec) -> Vec { + let mut result = Vec::with_capacity(chunk.len()); + if chunk.is_empty() { return vec![] } + chunk.into_iter() + .map(|num| (0..APPROVAL_FLAG_LEN).map(|bit| Self::bit_at(num, bit)).collect::>()) + .for_each(|c| { + let last_approve = match c.iter().rposition(|n| *n) { + Some(index) => index + 1, + None => 0 + }; + result.extend(c.into_iter().take(last_approve)); + }); + result + } + + /// Return a concatenated vector over all approvals of a voter as boolean. + /// The trailing zeros are removed. + fn all_approvals_of(who: &T::AccountId) -> Vec { + let mut all: Vec = vec![]; + let mut index = 0_u32; + loop { + let chunk = Self::approvals_of((who.clone(), index)); + if chunk.is_empty() { break; } + all.extend(Self::flag_to_bool(chunk)); + index += 1; + } + all + } + + /// Remove all approvals associated with one account. + fn remove_all_approvals_of(who: &T::AccountId) { + let mut index = 0; + loop { + let set = Self::approvals_of((who.clone(), index)); + if set.len() > 0 { + >::remove((who.clone(), index)); + index += 1; + } else { + break + } + } + } + + /// Calculates the offset value (stored pot) of a stake, based on the distance + /// to the last win_index, `t`. Regardless of the internal implementation, + /// it should always be used with the following structure: + /// + /// Given Stake of voter `V` being `x` and distance to last_win index `t`, the new weight + /// of `V` is `x + get_offset(x, t)`. + /// + /// In other words, this function returns everything extra that should be added + /// to a voter's stake value to get the correct weight. Indeed, zero is + /// returned if `t` is zero. + fn get_offset(stake: BalanceOf, t: VoteIndex) -> BalanceOf { + let decay_ratio: BalanceOf = T::DecayRatio::get().into(); + if t > 150 { return stake * decay_ratio } + let mut offset = stake; + let mut r = Zero::zero(); + let decay = decay_ratio + One::one(); + for _ in 0..t { + offset = offset.saturating_sub(offset / decay); + r += offset + } + r + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::cell::RefCell; + use srml_support::{assert_ok, assert_err, assert_noop, parameter_types}; + use runtime_io::with_externalities; + use substrate_primitives::{H256, Blake2Hasher}; + use primitives::{ + traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, testing::Header, BuildStorage + }; + use crate as elections; + + parameter_types! { + pub const BlockHashCount: u64 = 250; + } + impl system::Trait for Test { + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + } + parameter_types! { + pub const ExistentialDeposit: u64 = 0; + pub const TransferFee: u64 = 0; + pub const CreationFee: u64 = 0; + pub const TransactionBaseFee: u64 = 0; + pub const TransactionByteFee: u64 = 0; + } + impl balances::Trait for Test { + type Balance = u64; + type OnNewAccount = (); + type OnFreeBalanceZero = (); + type Event = Event; + type TransactionPayment = (); + type TransferPayment = (); + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type TransferFee = TransferFee; + type CreationFee = CreationFee; + type TransactionBaseFee = TransactionBaseFee; + type TransactionByteFee = TransactionByteFee; + } + parameter_types! { + pub const CandidacyBond: u64 = 3; + pub const CarryCount: u32 = 2; + pub const InactiveGracePeriod: u32 = 1; + pub const VotingPeriod: u64 = 4; + } + + thread_local! { + static VOTER_BOND: RefCell = RefCell::new(0); + static VOTING_FEE: RefCell = RefCell::new(0); + static PRESENT_SLASH_PER_VOTER: RefCell = RefCell::new(0); + static DECAY_RATIO: RefCell = RefCell::new(0); + static MEMBERS: RefCell> = RefCell::new(vec![]); + } + + pub struct VotingBond; + impl Get for VotingBond { + fn get() -> u64 { VOTER_BOND.with(|v| *v.borrow()) } + } + + pub struct VotingFee; + impl Get for VotingFee { + fn get() -> u64 { VOTING_FEE.with(|v| *v.borrow()) } + } + + pub struct PresentSlashPerVoter; + impl Get for PresentSlashPerVoter { + fn get() -> u64 { PRESENT_SLASH_PER_VOTER.with(|v| *v.borrow()) } + } + + pub struct DecayRatio; + impl Get for DecayRatio { + fn get() -> u32 { DECAY_RATIO.with(|v| *v.borrow()) } + } + + pub struct TestChangeMembers; + impl ChangeMembers for TestChangeMembers { + fn change_members(incoming: &[u64], outgoing: &[u64], new: &[u64]) { + let mut old_plus_incoming = MEMBERS.with(|m| m.borrow().to_vec()); + old_plus_incoming.extend_from_slice(incoming); + old_plus_incoming.sort(); + let mut new_plus_outgoing = new.to_vec(); + new_plus_outgoing.extend_from_slice(outgoing); + new_plus_outgoing.sort(); + assert_eq!(old_plus_incoming, new_plus_outgoing); + + MEMBERS.with(|m| *m.borrow_mut() = new.to_vec()); + } + } + + impl Trait for Test { + type Event = Event; + type Currency = Balances; + type BadPresentation = (); + type BadReaper = (); + type BadVoterIndex = (); + type LoserCandidate = (); + type ChangeMembers = TestChangeMembers; + type CandidacyBond = CandidacyBond; + type VotingBond = VotingBond; + type VotingFee = VotingFee; + type PresentSlashPerVoter = PresentSlashPerVoter; + type CarryCount = CarryCount; + type InactiveGracePeriod = InactiveGracePeriod; + type VotingPeriod = VotingPeriod; + type DecayRatio = DecayRatio; + } + + pub type Block = primitives::generic::Block; + pub type UncheckedExtrinsic = primitives::generic::UncheckedMortalCompactExtrinsic; + + srml_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: system::{Module, Call, Event}, + Balances: balances::{Module, Call, Event, Config}, + Elections: elections::{Module, Call, Event, Config}, + } + ); + + pub struct ExtBuilder { + balance_factor: u64, + decay_ratio: u32, + voting_fee: u64, + voter_bond: u64, + bad_presentation_punishment: u64, + } + + impl Default for ExtBuilder { + fn default() -> Self { + Self { + balance_factor: 1, + decay_ratio: 24, + voting_fee: 0, + voter_bond: 0, + bad_presentation_punishment: 1, + } + } + } + + impl ExtBuilder { + pub fn balance_factor(mut self, factor: u64) -> Self { + self.balance_factor = factor; + self + } + pub fn decay_ratio(mut self, ratio: u32) -> Self { + self.decay_ratio = ratio; + self + } + pub fn voting_fee(mut self, fee: u64) -> Self { + self.voting_fee = fee; + self + } + pub fn bad_presentation_punishment(mut self, fee: u64) -> Self { + self.bad_presentation_punishment = fee; + self + } + pub fn voter_bond(mut self, fee: u64) -> Self { + self.voter_bond = fee; + self + } + pub fn build(self) -> runtime_io::TestExternalities { + VOTER_BOND.with(|v| *v.borrow_mut() = self.voter_bond); + VOTING_FEE.with(|v| *v.borrow_mut() = self.voting_fee); + PRESENT_SLASH_PER_VOTER.with(|v| *v.borrow_mut() = self.bad_presentation_punishment); + DECAY_RATIO.with(|v| *v.borrow_mut() = self.decay_ratio); + GenesisConfig { + balances: Some(balances::GenesisConfig::{ + balances: vec![ + (1, 10 * self.balance_factor), + (2, 20 * self.balance_factor), + (3, 30 * self.balance_factor), + (4, 40 * self.balance_factor), + (5, 50 * self.balance_factor), + (6, 60 * self.balance_factor) + ], + vesting: vec![], + }), + elections: Some(elections::GenesisConfig::{ + members: vec![], + desired_seats: 2, + presentation_duration: 2, + term_duration: 5, + }), + }.build_storage().unwrap().0.into() + } + } + + fn voter_ids() -> Vec { + Elections::all_voters().iter().map(|v| v.unwrap_or(0) ).collect::>() + } + + fn vote(i: u64, l: usize) { + let _ = Balances::make_free_balance_be(&i, 20); + assert_ok!(Elections::set_approvals(Origin::signed(i), (0..l).map(|_| true).collect::>(), 0, 0)); + } + + fn vote_at(i: u64, l: usize, index: VoteIndex) { + let _ = Balances::make_free_balance_be(&i, 20); + assert_ok!(Elections::set_approvals(Origin::signed(i), (0..l).map(|_| true).collect::>(), 0, index)); + } + + fn create_candidate(i: u64, index: u32) { + let _ = Balances::make_free_balance_be(&i, 20); + assert_ok!(Elections::submit_candidacy(Origin::signed(i), index)); + } + + fn bond() -> u64 { + ::VotingBond::get() + } + + #[test] + fn bool_to_flag_should_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + assert_eq!(Elections::bool_to_flag(vec![]), vec![]); + assert_eq!(Elections::bool_to_flag(vec![false]), vec![0]); + assert_eq!(Elections::bool_to_flag(vec![true]), vec![1]); + assert_eq!(Elections::bool_to_flag(vec![true, true, true, true]), vec![15]); + assert_eq!(Elections::bool_to_flag(vec![true, true, true, true, true]), vec![15 + 16]); + + let set_1 = vec![ + true, false, false, false, // 0x1 + false, true, true, true, // 0xE + ]; + assert_eq!( + Elections::bool_to_flag(set_1.clone()), + vec![0x00_00_00_E1_u32] + ); + assert_eq!( + Elections::flag_to_bool(vec![0x00_00_00_E1_u32]), + set_1 + ); + + let set_2 = vec![ + false, false, false, true, // 0x8 + false, true, false, true, // 0xA + ]; + assert_eq!( + Elections::bool_to_flag(set_2.clone()), + vec![0x00_00_00_A8_u32] + ); + assert_eq!( + Elections::flag_to_bool(vec![0x00_00_00_A8_u32]), + set_2 + ); + + let mut rhs = (0..100/APPROVAL_FLAG_LEN).map(|_| 0xFFFFFFFF_u32).collect::>(); + // NOTE: this might be need change based on `APPROVAL_FLAG_LEN`. + rhs.extend(vec![0x00_00_00_0F]); + assert_eq!( + Elections::bool_to_flag((0..100).map(|_| true).collect()), + rhs + ) + }) + } + + #[test] + fn params_should_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(1); + assert_eq!(Elections::next_vote_from(1), 4); + assert_eq!(Elections::next_vote_from(4), 4); + assert_eq!(Elections::next_vote_from(5), 8); + assert_eq!(Elections::vote_index(), 0); + assert_eq!(Elections::presentation_duration(), 2); + assert_eq!(Elections::term_duration(), 5); + assert_eq!(Elections::desired_seats(), 2); + + assert_eq!(Elections::members(), vec![]); + assert_eq!(Elections::next_tally(), Some(4)); + assert_eq!(Elections::presentation_active(), false); + assert_eq!(Elections::next_finalize(), None); + + assert_eq!(Elections::candidates(), Vec::::new()); + assert_eq!(Elections::is_a_candidate(&1), false); + assert_eq!(Elections::candidate_reg_info(1), None); + + assert_eq!(Elections::voters(0), Vec::>::new()); + assert_eq!(Elections::voter_info(1), None); + assert_eq!(Elections::all_approvals_of(&1), vec![]); + }); + } + + #[test] + fn voter_set_growth_should_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 1)); + + // create 65. 64 (set0) + 1 (set1) + (1..=63).for_each(|i| vote(i, 2)); + assert_eq!(Elections::next_nonfull_voter_set(), 0); + vote(64, 2); + assert_eq!(Elections::next_nonfull_voter_set(), 1); + vote(65, 2); + + let set1 = Elections::voters(0); + let set2 = Elections::voters(1); + + assert_eq!(set1.len(), 64); + assert_eq!(set2.len(), 1); + + assert_eq!(set1[0], Some(1)); + assert_eq!(set1[10], Some(11)); + assert_eq!(set2[0], Some(65)); + }) + } + + #[test] + fn voter_set_reclaim_should_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 1)); + + (1..=129).for_each(|i| vote(i, 2)); + assert_eq!(Elections::next_nonfull_voter_set(), 2); + + assert_ok!(Elections::retract_voter(Origin::signed(11), 10)); + + assert_ok!(Elections::retract_voter(Origin::signed(66), 65)); + assert_ok!(Elections::retract_voter(Origin::signed(67), 66)); + + // length does not show it but holes do exist. + assert_eq!(Elections::voters(0).len(), 64); + assert_eq!(Elections::voters(1).len(), 64); + assert_eq!(Elections::voters(2).len(), 1); + + assert_eq!(Elections::voters(0)[10], None); + assert_eq!(Elections::voters(1)[1], None); + assert_eq!(Elections::voters(1)[2], None); + // Next set with capacity is 2. + assert_eq!(Elections::next_nonfull_voter_set(), 2); + + // But we can fill a hole. + vote_at(130, 2, 10); + + // Nothing added to set 2. A hole was filled. + assert_eq!(Elections::voters(0).len(), 64); + assert_eq!(Elections::voters(1).len(), 64); + assert_eq!(Elections::voters(2).len(), 1); + + // and the next two (scheduled) to the second set. + assert_eq!(Elections::next_nonfull_voter_set(), 2); + }) + } + + #[test] + fn approvals_set_growth_should_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + // create candidates and voters. + (1..=250).for_each(|i| create_candidate(i, (i-1) as u32)); + (1..=250).for_each(|i| vote(i, i as usize)); + + // all approvals of should return the exact expected vector. + assert_eq!(Elections::all_approvals_of(&180), (0..180).map(|_| true).collect::>()); + + assert_eq!(Elections::all_approvals_of(&32), (0..32).map(|_| true).collect::>()); + assert_eq!(Elections::all_approvals_of(&8), (0..8).map(|_| true).collect::>()); + assert_eq!(Elections::all_approvals_of(&64), (0..64).map(|_| true).collect::>()); + assert_eq!(Elections::all_approvals_of(&65), (0..65).map(|_| true).collect::>()); + assert_eq!(Elections::all_approvals_of(&63), (0..63).map(|_| true).collect::>()); + + // NOTE: assuming that APPROVAL_SET_SIZE is more or less small-ish. Might fail otherwise. + let full_sets = (180 / APPROVAL_FLAG_LEN) / APPROVAL_SET_SIZE; + let left_over = (180 / APPROVAL_FLAG_LEN) / APPROVAL_SET_SIZE; + let rem = 180 % APPROVAL_FLAG_LEN; + + // grab and check the last full set, if it exists. + if full_sets > 0 { + assert_eq!( + Elections::approvals_of((180, (full_sets-1) as SetIndex )), + Elections::bool_to_flag((0..APPROVAL_SET_SIZE * APPROVAL_FLAG_LEN).map(|_| true).collect::>()) + ); + } + + // grab and check the last, half-empty, set. + if left_over > 0 { + assert_eq!( + Elections::approvals_of((180, full_sets as SetIndex)), + Elections::bool_to_flag((0..left_over * APPROVAL_FLAG_LEN + rem).map(|_| true).collect::>()) + ); + } + }) + } + + + #[test] + fn cell_status_works() { + with_externalities(&mut ExtBuilder::default().build(), || { + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 1)); + + (1..=63).for_each(|i| vote(i, 2)); + + assert_ok!(Elections::retract_voter(Origin::signed(11), 10)); + assert_ok!(Elections::retract_voter(Origin::signed(21), 20)); + + assert_eq!(Elections::cell_status(0, 10), CellStatus::Hole); + assert_eq!(Elections::cell_status(0, 0), CellStatus::Occupied); + assert_eq!(Elections::cell_status(0, 20), CellStatus::Hole); + assert_eq!(Elections::cell_status(0, 63), CellStatus::Head); + assert_eq!(Elections::cell_status(1, 0), CellStatus::Head); + assert_eq!(Elections::cell_status(1, 10), CellStatus::Head); + }) + } + + #[test] + fn initial_set_approvals_ignores_voter_index() { + with_externalities(&mut ExtBuilder::default().build(), || { + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + + // Last argument is essentially irrelevant. You might get or miss a tip. + assert_ok!(Elections::set_approvals(Origin::signed(3), vec![true], 0, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(4), vec![true], 0, 5)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![true], 0, 100)); + + // indices are more or less ignored. all is pushed. + assert_eq!(voter_ids(), vec![3, 4, 5]); + }) + } + + #[test] + fn bad_approval_index_slashes_voters_and_bond_reduces_stake() { + with_externalities(&mut ExtBuilder::default().voting_fee(5).voter_bond(2).build(), || { + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 1)); + + (1..=63).for_each(|i| vote(i, 2)); + assert_eq!(Balances::free_balance(&1), 20 - 5 - 2); // -5 fee -2 bond + assert_eq!(Balances::free_balance(&10), 20 - 2); + assert_eq!(Balances::free_balance(&60), 20 - 2); + + // still no fee + vote(64, 2); + assert_eq!(Balances::free_balance(&64), 20 - 2); // -2 bond + assert_eq!( + Elections::voter_info(&64).unwrap(), + VoterInfo { last_win: 0, last_active: 0, stake: 20, pot:0 } + ); + + assert_eq!(Elections::next_nonfull_voter_set(), 1); + + // now we charge the next voter. + vote(65, 2); + assert_eq!(Balances::free_balance(&65), 20 - 5 - 2); + assert_eq!( + Elections::voter_info(&65).unwrap(), + VoterInfo { last_win: 0, last_active: 0, stake: 15, pot:0 } + ); + }); + } + + #[test] + fn subsequent_set_approvals_checks_voter_index() { + with_externalities(&mut ExtBuilder::default().build(), || { + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + + assert_ok!(Elections::set_approvals(Origin::signed(3), vec![true], 0, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(4), vec![true], 0, 5)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![true], 0, 100)); + + // invalid index + assert_noop!(Elections::set_approvals(Origin::signed(4), vec![true], 0, 5), "invalid voter index"); + // wrong index + assert_noop!(Elections::set_approvals(Origin::signed(4), vec![true], 0, 0), "wrong voter index"); + // correct + assert_ok!(Elections::set_approvals(Origin::signed(4), vec![true], 0, 1)); + }) + } + + #[test] + fn voter_index_does_not_take_holes_into_account() { + with_externalities(&mut ExtBuilder::default().build(), || { + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 1)); + + // create 65. 64 (set0) + 1 (set1) + (1..=65).for_each(|i| vote(i, 2)); + + // account 65 has global index 65. + assert_eq!(Elections::voter_at(64).unwrap(), 65); + + assert_ok!(Elections::retract_voter(Origin::signed(1), 0)); + assert_ok!(Elections::retract_voter(Origin::signed(2), 1)); + + // still the same. These holes are in some other set. + assert_eq!(Elections::voter_at(64).unwrap(), 65); + // proof: can submit a new approval with the old index. + assert_noop!(Elections::set_approvals(Origin::signed(65), vec![false, true], 0, 64 - 2), "wrong voter index"); + assert_ok!(Elections::set_approvals(Origin::signed(65), vec![false, true], 0, 64)); + }) + } + + #[test] + fn simple_candidate_submission_should_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(1); + assert_eq!(Elections::candidates(), Vec::::new()); + assert_eq!(Elections::candidate_reg_info(1), None); + assert_eq!(Elections::candidate_reg_info(2), None); + assert_eq!(Elections::is_a_candidate(&1), false); + assert_eq!(Elections::is_a_candidate(&2), false); + + assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); + assert_eq!(Elections::candidates(), vec![1]); + assert_eq!(Elections::candidate_reg_info(1), Some((0, 0))); + assert_eq!(Elections::candidate_reg_info(2), None); + assert_eq!(Elections::is_a_candidate(&1), true); + assert_eq!(Elections::is_a_candidate(&2), false); + + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 1)); + assert_eq!(Elections::candidates(), vec![1, 2]); + assert_eq!(Elections::candidate_reg_info(1), Some((0, 0))); + assert_eq!(Elections::candidate_reg_info(2), Some((0, 1))); + assert_eq!(Elections::is_a_candidate(&1), true); + assert_eq!(Elections::is_a_candidate(&2), true); + }); + } + + fn new_test_ext_with_candidate_holes() -> runtime_io::TestExternalities { + let mut t = ExtBuilder::default().build(); + with_externalities(&mut t, || { + >::put(vec![0, 0, 1]); + CandidateCount::put(1); + >::insert(1, (0, 2)); + }); + t + } + + #[test] + fn candidate_submission_using_free_slot_should_work() { + let mut t = new_test_ext_with_candidate_holes(); + + with_externalities(&mut t, || { + System::set_block_number(1); + assert_eq!(Elections::candidates(), vec![0, 0, 1]); + + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 1)); + assert_eq!(Elections::candidates(), vec![0, 2, 1]); + + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 0)); + assert_eq!(Elections::candidates(), vec![3, 2, 1]); + }); + } + + #[test] + fn candidate_submission_using_alternative_free_slot_should_work() { + let mut t = new_test_ext_with_candidate_holes(); + + with_externalities(&mut t, || { + System::set_block_number(1); + assert_eq!(Elections::candidates(), vec![0, 0, 1]); + + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + assert_eq!(Elections::candidates(), vec![2, 0, 1]); + + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 1)); + assert_eq!(Elections::candidates(), vec![2, 3, 1]); + }); + } + + #[test] + fn candidate_submission_not_using_free_slot_should_not_work() { + let mut t = new_test_ext_with_candidate_holes(); + + with_externalities(&mut t, || { + System::set_block_number(1); + assert_noop!(Elections::submit_candidacy(Origin::signed(4), 3), "invalid candidate slot"); + }); + } + + #[test] + fn bad_candidate_slot_submission_should_not_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(1); + assert_eq!(Elections::candidates(), Vec::::new()); + assert_noop!(Elections::submit_candidacy(Origin::signed(1), 1), "invalid candidate slot"); + }); + } + + #[test] + fn non_free_candidate_slot_submission_should_not_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(1); + assert_eq!(Elections::candidates(), Vec::::new()); + assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); + assert_eq!(Elections::candidates(), vec![1]); + assert_noop!(Elections::submit_candidacy(Origin::signed(2), 0), "invalid candidate slot"); + }); + } + + #[test] + fn dupe_candidate_submission_should_not_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(1); + assert_eq!(Elections::candidates(), Vec::::new()); + assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); + assert_eq!(Elections::candidates(), vec![1]); + assert_noop!(Elections::submit_candidacy(Origin::signed(1), 1), "duplicate candidate submission"); + }); + } + + #[test] + fn poor_candidate_submission_should_not_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(1); + assert_eq!(Elections::candidates(), Vec::::new()); + assert_noop!(Elections::submit_candidacy(Origin::signed(7), 0), "candidate has not enough funds"); + }); + } + + #[test] + fn balance_should_lock_to_the_maximum() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(1); + assert_eq!(Elections::candidates(), Vec::::new()); + assert_eq!(Balances::free_balance(&2), 20); + + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0)); + + assert_eq!(Balances::free_balance(&2), 20 - bond() ); + assert_noop!(Balances::reserve(&2, 1), "account liquidity restrictions prevent withdrawal"); // locked. + + // deposit a bit more. + let _ = Balances::deposit_creating(&2, 100); + assert_ok!(Balances::reserve(&2, 1)); // locked but now has enough. + + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0)); + assert_noop!(Balances::reserve(&2, 1), "account liquidity restrictions prevent withdrawal"); // locked. + assert_eq!(Balances::locks(&2).len(), 1); + assert_eq!(Balances::locks(&2)[0].amount, 100 + 20); + + assert_ok!(Elections::retract_voter(Origin::signed(2), 0)); + + assert_eq!(Balances::locks(&2).len(), 0); + assert_eq!(Balances::free_balance(&2), 120 - 1); // 1 ok call to .reserve() happened. + assert_ok!(Balances::reserve(&2, 1)); // unlocked. + }); + } + + #[test] + fn balance_should_lock_on_submit_approvals_unlock_on_retract() { + with_externalities(&mut ExtBuilder::default().voter_bond(8).voting_fee(0).build(), || { + System::set_block_number(1); + assert_eq!(Elections::candidates(), Vec::::new()); + assert_eq!(Balances::free_balance(&2), 20); + + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0)); + + assert_eq!(Balances::free_balance(&2), 12); // 20 - 8 (bond) + assert_noop!(Balances::reserve(&2, 10), "account liquidity restrictions prevent withdrawal"); // locked. + + assert_ok!(Elections::retract_voter(Origin::signed(2), 0)); + + assert_eq!(Balances::free_balance(&2), 20); + assert_ok!(Balances::reserve(&2, 10)); // unlocked. + }); + } + + #[test] + fn accumulating_weight_and_decaying_should_work() { + with_externalities(&mut ExtBuilder::default().balance_factor(10).build(), || { + System::set_block_number(4); + assert!(!Elections::presentation_active()); + + assert_ok!(Elections::submit_candidacy(Origin::signed(6), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); + assert_ok!(Elections::submit_candidacy(Origin::signed(1), 2)); + + assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true, false, false], 0, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, true, false], 0, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(1), vec![false, false, true], 0, 0)); + + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert!(Elections::presentation_active()); + + assert_eq!(Elections::present_winner(Origin::signed(6), 6, 600, 0), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(5), 5, 500, 0), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(1), 1, 100, 0), Ok(())); + assert_eq!(Elections::leaderboard(), Some(vec![(0, 0), (100, 1), (500, 5), (600, 6)])); + assert_ok!(Elections::end_block(System::block_number())); + + assert_eq!(Elections::members(), vec![(6, 11), (5, 11)]); + assert_eq!(Elections::voter_info(6).unwrap(), VoterInfo { last_win: 1, last_active: 0, stake: 600, pot: 0}); + assert_eq!(Elections::voter_info(5).unwrap(), VoterInfo { last_win: 1, last_active: 0, stake: 500, pot: 0}); + assert_eq!(Elections::voter_info(1).unwrap(), VoterInfo { last_win: 0, last_active: 0, stake: 100, pot: 0}); + + System::set_block_number(12); + // retract needed to unlock approval funds => submit candidacy again. + assert_ok!(Elections::retract_voter(Origin::signed(6), 0)); + assert_ok!(Elections::retract_voter(Origin::signed(5), 1)); + assert_ok!(Elections::submit_candidacy(Origin::signed(6), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); + assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true, false, false], 1, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, true, false], 1, 1)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(14); + assert!(Elections::presentation_active()); + assert_eq!(Elections::present_winner(Origin::signed(6), 6, 600, 1), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(5), 5, 500, 1), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(1), 1, 100 + Elections::get_offset(100, 1), 1), Ok(())); + assert_eq!(Elections::leaderboard(), Some(vec![(0, 0), (100 + 96, 1), (500, 5), (600, 6)])); + assert_ok!(Elections::end_block(System::block_number())); + + assert_eq!(Elections::members(), vec![(6, 19), (5, 19)]); + assert_eq!( + Elections::voter_info(6).unwrap(), + VoterInfo { last_win: 2, last_active: 1, stake: 600, pot:0 } + ); + assert_eq!(Elections::voter_info(5).unwrap(), VoterInfo { last_win: 2, last_active: 1, stake: 500, pot:0 }); + assert_eq!(Elections::voter_info(1).unwrap(), VoterInfo { last_win: 0, last_active: 0, stake: 100, pot:0 }); + + System::set_block_number(20); + assert_ok!(Elections::retract_voter(Origin::signed(6), 0)); + assert_ok!(Elections::retract_voter(Origin::signed(5), 1)); + assert_ok!(Elections::submit_candidacy(Origin::signed(6), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); + assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true, false, false], 2, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, true, false], 2, 1)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(22); + assert!(Elections::presentation_active()); + assert_eq!(Elections::present_winner(Origin::signed(6), 6, 600, 2), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(5), 5, 500, 2), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(1), 1, 100 + Elections::get_offset(100, 2), 2), Ok(())); + assert_eq!(Elections::leaderboard(), Some(vec![(0, 0), (100 + 96 + 93, 1), (500, 5), (600, 6)])); + assert_ok!(Elections::end_block(System::block_number())); + + assert_eq!(Elections::members(), vec![(6, 27), (5, 27)]); + assert_eq!( + Elections::voter_info(6).unwrap(), + VoterInfo { last_win: 3, last_active: 2, stake: 600, pot: 0} + ); + assert_eq!(Elections::voter_info(5).unwrap(), VoterInfo { last_win: 3, last_active: 2, stake: 500, pot: 0}); + assert_eq!(Elections::voter_info(1).unwrap(), VoterInfo { last_win: 0, last_active: 0, stake: 100, pot: 0}); + + + System::set_block_number(28); + assert_ok!(Elections::retract_voter(Origin::signed(6), 0)); + assert_ok!(Elections::retract_voter(Origin::signed(5), 1)); + assert_ok!(Elections::submit_candidacy(Origin::signed(6), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); + assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true, false, false], 3, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, true, false], 3, 1)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(30); + assert!(Elections::presentation_active()); + assert_eq!(Elections::present_winner(Origin::signed(6), 6, 600, 3), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(5), 5, 500, 3), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(1), 1, 100 + Elections::get_offset(100, 3), 3), Ok(())); + assert_eq!(Elections::leaderboard(), Some(vec![(0, 0), (100 + 96 + 93 + 90, 1), (500, 5), (600, 6)])); + assert_ok!(Elections::end_block(System::block_number())); + + assert_eq!(Elections::members(), vec![(6, 35), (5, 35)]); + assert_eq!( + Elections::voter_info(6).unwrap(), + VoterInfo { last_win: 4, last_active: 3, stake: 600, pot: 0} + ); + assert_eq!(Elections::voter_info(5).unwrap(), VoterInfo { last_win: 4, last_active: 3, stake: 500, pot: 0}); + assert_eq!(Elections::voter_info(1).unwrap(), VoterInfo { last_win: 0, last_active: 0, stake: 100, pot: 0}); + }) + } + + #[test] + fn winning_resets_accumulated_pot() { + with_externalities(&mut ExtBuilder::default().balance_factor(10).build(), || { + System::set_block_number(4); + assert!(!Elections::presentation_active()); + + assert_ok!(Elections::submit_candidacy(Origin::signed(6), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(4), 1)); + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 2)); + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 3)); + + assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true, false, false, false], 0, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(4), vec![false, true, false, false], 0, 1)); + assert_ok!(Elections::set_approvals(Origin::signed(3), vec![false, false, true, true], 0, 2)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert!(Elections::presentation_active()); + assert_eq!(Elections::present_winner(Origin::signed(6), 6, 600, 0), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(4), 4, 400, 0), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(3), 3, 300, 0), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(2), 2, 300, 0), Ok(())); + assert_eq!(Elections::leaderboard(), Some(vec![(300, 2), (300, 3), (400, 4), (600, 6)])); + assert_ok!(Elections::end_block(System::block_number())); + + assert_eq!(Elections::members(), vec![(6, 11), (4, 11)]); + + System::set_block_number(12); + assert_ok!(Elections::retract_voter(Origin::signed(6), 0)); + assert_ok!(Elections::retract_voter(Origin::signed(4), 1)); + assert_ok!(Elections::submit_candidacy(Origin::signed(6), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(4), 1)); + assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true, false, false, false], 1, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(4), vec![false, true, false, false], 1, 1)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(14); + assert!(Elections::presentation_active()); + assert_eq!(Elections::present_winner(Origin::signed(6), 6, 600, 1), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(4), 4, 400, 1), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(3), 3, 300 + Elections::get_offset(300, 1), 1), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(2), 2, 300 + Elections::get_offset(300, 1), 1), Ok(())); + assert_eq!(Elections::leaderboard(), Some(vec![(400, 4), (588, 2), (588, 3), (600, 6)])); + assert_ok!(Elections::end_block(System::block_number())); + + assert_eq!(Elections::members(), vec![(6, 19), (3, 19)]); + + System::set_block_number(20); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(22); + // 2 will not get re-elected with 300 + 288, instead just 300. + // because one of 3's candidates (3) won in previous round + // 4 on the other hand will get extra weight since it was unlucky. + assert_eq!(Elections::present_winner(Origin::signed(3), 2, 300, 2), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(4), 4, 400 + Elections::get_offset(400, 1), 2), Ok(())); + assert_ok!(Elections::end_block(System::block_number())); + + assert_eq!(Elections::members(), vec![(4, 27), (2, 27)]); + }) + } + + #[test] + fn resubmitting_approvals_stores_pot() { + with_externalities(&mut ExtBuilder::default() + .voter_bond(0) + .voting_fee(0) + .balance_factor(10) + .build(), + || { System::set_block_number(4); + assert!(!Elections::presentation_active()); + + assert_ok!(Elections::submit_candidacy(Origin::signed(6), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); + assert_ok!(Elections::submit_candidacy(Origin::signed(1), 2)); + + assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true, false, false], 0, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, true, false], 0, 1)); + assert_ok!(Elections::set_approvals(Origin::signed(1), vec![false, false, true], 0, 2)); + + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert!(Elections::presentation_active()); + + assert_eq!(Elections::present_winner(Origin::signed(6), 6, 600, 0), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(5), 5, 500, 0), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(1), 1, 100, 0), Ok(())); + assert_eq!(Elections::leaderboard(), Some(vec![(0, 0), (100, 1), (500, 5), (600, 6)])); + assert_ok!(Elections::end_block(System::block_number())); + + assert_eq!(Elections::members(), vec![(6, 11), (5, 11)]); + + System::set_block_number(12); + assert_ok!(Elections::retract_voter(Origin::signed(6), 0)); + assert_ok!(Elections::retract_voter(Origin::signed(5), 1)); + assert_ok!(Elections::submit_candidacy(Origin::signed(6), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); + assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true, false, false], 1, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, true, false], 1, 1)); + // give 1 some new high balance + let _ = Balances::make_free_balance_be(&1, 997); + assert_ok!(Elections::set_approvals(Origin::signed(1), vec![false, false, true], 1, 2)); + assert_eq!(Elections::voter_info(1).unwrap(), + VoterInfo { + stake: 1000, // 997 + 3 which is candidacy bond. + pot: Elections::get_offset(100, 1), + last_active: 1, + last_win: 1, + } + ); + assert_ok!(Elections::end_block(System::block_number())); + + assert_eq!(Elections::members(), vec![(6, 11), (5, 11)]); + + System::set_block_number(14); + assert!(Elections::presentation_active()); + assert_eq!(Elections::present_winner(Origin::signed(6), 6, 600, 1), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(5), 5, 500, 1), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(1), 1, 1000 + 96 /* pot */, 1), Ok(())); + assert_eq!(Elections::leaderboard(), Some(vec![(0, 0), (500, 5), (600, 6), (1096, 1)])); + assert_ok!(Elections::end_block(System::block_number())); + + assert_eq!(Elections::members(), vec![(1, 19), (6, 19)]); + }) + } + + #[test] + fn get_offset_should_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + assert_eq!(Elections::get_offset(100, 0), 0); + assert_eq!(Elections::get_offset(100, 1), 96); + assert_eq!(Elections::get_offset(100, 2), 96 + 93); + assert_eq!(Elections::get_offset(100, 3), 96 + 93 + 90); + assert_eq!(Elections::get_offset(100, 4), 96 + 93 + 90 + 87); + // limit + assert_eq!(Elections::get_offset(100, 1000), 100 * 24); + + assert_eq!(Elections::get_offset(50_000_000_000, 0), 0); + assert_eq!(Elections::get_offset(50_000_000_000, 1), 48_000_000_000); + assert_eq!(Elections::get_offset(50_000_000_000, 2), 48_000_000_000 + 46_080_000_000); + assert_eq!(Elections::get_offset(50_000_000_000, 3), 48_000_000_000 + 46_080_000_000 + 44_236_800_000); + assert_eq!( + Elections::get_offset(50_000_000_000, 4), + 48_000_000_000 + 46_080_000_000 + 44_236_800_000 + 42_467_328_000 + ); + // limit + assert_eq!(Elections::get_offset(50_000_000_000, 1000), 50_000_000_000 * 24); + }) + } + + #[test] + fn get_offset_with_zero_decay() { + with_externalities(&mut ExtBuilder::default().decay_ratio(0).build(), || { + assert_eq!(Elections::get_offset(100, 0), 0); + assert_eq!(Elections::get_offset(100, 1), 0); + assert_eq!(Elections::get_offset(100, 2), 0); + assert_eq!(Elections::get_offset(100, 3), 0); + // limit + assert_eq!(Elections::get_offset(100, 1000), 0); + }) + } + + #[test] + fn voting_should_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(1); + + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); + + assert_ok!(Elections::set_approvals(Origin::signed(1), vec![true], 0, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(4), vec![true], 0, 1)); + + assert_eq!(Elections::all_approvals_of(&1), vec![true]); + assert_eq!(Elections::all_approvals_of(&4), vec![true]); + assert_eq!(voter_ids(), vec![1, 4]); + + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 1)); + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 2)); + + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![false, true, true], 0, 2)); + assert_ok!(Elections::set_approvals(Origin::signed(3), vec![false, true, true], 0, 3)); + + assert_eq!(Elections::all_approvals_of(&1), vec![true]); + assert_eq!(Elections::all_approvals_of(&4), vec![true]); + assert_eq!(Elections::all_approvals_of(&2), vec![false, true, true]); + assert_eq!(Elections::all_approvals_of(&3), vec![false, true, true]); + + assert_eq!(voter_ids(), vec![1, 4, 2, 3]); + }); + } + + #[test] + fn proxy_voting_should_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(1); + + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); + + >::insert(11, 1); + >::insert(12, 2); + >::insert(13, 3); + >::insert(14, 4); + assert_ok!(Elections::proxy_set_approvals(Origin::signed(11), vec![true], 0, 0)); + assert_ok!(Elections::proxy_set_approvals(Origin::signed(14), vec![true], 0, 1)); + + assert_eq!(Elections::all_approvals_of(&1), vec![true]); + assert_eq!(Elections::all_approvals_of(&4), vec![true]); + assert_eq!(voter_ids(), vec![1, 4]); + + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 1)); + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 2)); + + assert_ok!(Elections::proxy_set_approvals(Origin::signed(12), vec![false, true, true], 0, 2)); + assert_ok!(Elections::proxy_set_approvals(Origin::signed(13), vec![false, true, true], 0, 3)); + + assert_eq!(Elections::all_approvals_of(&1), vec![true]); + assert_eq!(Elections::all_approvals_of(&4), vec![true]); + assert_eq!(Elections::all_approvals_of(&2), vec![false, true, true]); + assert_eq!(Elections::all_approvals_of(&3), vec![false, true, true]); + + assert_eq!(voter_ids(), vec![1, 4, 2, 3]); + }); + } + + #[test] + fn setting_any_approval_vote_count_without_any_candidate_count_should_not_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(1); + + assert_eq!(Elections::candidates().len(), 0); + + assert_noop!( + Elections::set_approvals(Origin::signed(4), vec![], 0, 0), + "amount of candidates to receive approval votes should be non-zero" + ); + }); + } + + #[test] + fn setting_an_approval_vote_count_more_than_candidate_count_should_not_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(1); + + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); + assert_eq!(Elections::candidates().len(), 1); + + assert_noop!( + Elections::set_approvals(Origin::signed(4),vec![true, true], 0, 0), + "amount of candidate votes cannot exceed amount of candidates" + ); + }); + } + + #[test] + fn resubmitting_voting_should_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(1); + + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(4), vec![true], 0, 0)); + + assert_eq!(Elections::all_approvals_of(&4), vec![true]); + + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 1)); + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 2)); + assert_eq!(Elections::candidates().len(), 3); + assert_ok!(Elections::set_approvals(Origin::signed(4), vec![true, false, true], 0, 0)); + + assert_eq!(Elections::all_approvals_of(&4), vec![true, false, true]); + }); + } + + #[test] + fn retracting_voter_should_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(1); + + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 1)); + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 2)); + assert_eq!(Elections::candidates().len(), 3); + + assert_ok!(Elections::set_approvals(Origin::signed(1), vec![true], 0, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![false, true, true], 0, 1)); + assert_ok!(Elections::set_approvals(Origin::signed(3), vec![false, true, true], 0, 2)); + assert_ok!(Elections::set_approvals(Origin::signed(4), vec![true, false, true], 0, 3)); + + assert_eq!(voter_ids(), vec![1, 2, 3, 4]); + assert_eq!(Elections::all_approvals_of(&1), vec![true]); + assert_eq!(Elections::all_approvals_of(&2), vec![false, true, true]); + assert_eq!(Elections::all_approvals_of(&3), vec![false, true, true]); + assert_eq!(Elections::all_approvals_of(&4), vec![true, false, true]); + + assert_ok!(Elections::retract_voter(Origin::signed(1), 0)); + + assert_eq!(voter_ids(), vec![0, 2, 3, 4]); + assert_eq!(Elections::all_approvals_of(&1), Vec::::new()); + assert_eq!(Elections::all_approvals_of(&2), vec![false, true, true]); + assert_eq!(Elections::all_approvals_of(&3), vec![false, true, true]); + assert_eq!(Elections::all_approvals_of(&4), vec![true, false, true]); + + assert_ok!(Elections::retract_voter(Origin::signed(2), 1)); + + assert_eq!(voter_ids(), vec![0, 0, 3, 4]); + assert_eq!(Elections::all_approvals_of(&1), Vec::::new()); + assert_eq!(Elections::all_approvals_of(&2), Vec::::new()); + assert_eq!(Elections::all_approvals_of(&3), vec![false, true, true]); + assert_eq!(Elections::all_approvals_of(&4), vec![true, false, true]); + + assert_ok!(Elections::retract_voter(Origin::signed(3), 2)); + + assert_eq!(voter_ids(), vec![0, 0, 0, 4]); + assert_eq!(Elections::all_approvals_of(&1), Vec::::new()); + assert_eq!(Elections::all_approvals_of(&2), Vec::::new()); + assert_eq!(Elections::all_approvals_of(&3), Vec::::new()); + assert_eq!(Elections::all_approvals_of(&4), vec![true, false, true]); + }); + } + + #[test] + fn invalid_retraction_index_should_not_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(1); + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(1), vec![true], 0, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0)); + assert_eq!(voter_ids(), vec![1, 2]); + assert_noop!(Elections::retract_voter(Origin::signed(1), 1), "retraction index mismatch"); + }); + } + + #[test] + fn overflow_retraction_index_should_not_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(1); + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(1), vec![true], 0, 0)); + assert_noop!(Elections::retract_voter(Origin::signed(1), 1), "retraction index invalid"); + }); + } + + #[test] + fn non_voter_retraction_should_not_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(1); + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(1), vec![true], 0, 0)); + assert_noop!(Elections::retract_voter(Origin::signed(2), 0), "cannot retract non-voter"); + }); + } + + #[test] + fn approval_storage_should_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 1)); + + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true, false], 0, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(3), vec![false, false], 0, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(4), vec![], 0, 0)); + + assert_eq!(Elections::all_approvals_of(&2), vec![true]); + // NOTE: these two are stored in mem differently though. + assert_eq!(Elections::all_approvals_of(&3), vec![]); + assert_eq!(Elections::all_approvals_of(&4), vec![]); + + assert_eq!(Elections::approvals_of((3, 0)), vec![0]); + assert_eq!(Elections::approvals_of((4, 0)), vec![]); + }); + } + + #[test] + fn simple_tally_should_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(4); + assert!(!Elections::presentation_active()); + + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, true], 0, 0)); + assert_eq!(voter_ids(), vec![2, 5]); + assert_eq!(Elections::all_approvals_of(&2), vec![true]); + assert_eq!(Elections::all_approvals_of(&5), vec![false, true]); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert!(Elections::presentation_active()); + assert_eq!(Elections::present_winner(Origin::signed(4), 2, 20, 0), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(4), 5, 50, 0), Ok(())); + assert_eq!(Elections::leaderboard(), Some(vec![(0, 0), (0, 0), (20, 2), (50, 5)])); + assert_ok!(Elections::end_block(System::block_number())); + + assert!(!Elections::presentation_active()); + assert_eq!(Elections::members(), vec![(5, 11), (2, 11)]); + + assert!(!Elections::is_a_candidate(&2)); + assert!(!Elections::is_a_candidate(&5)); + assert_eq!(Elections::vote_index(), 1); + assert_eq!(Elections::voter_info(2), Some(VoterInfo { last_win: 1, last_active: 0, stake: 20, pot: 0 })); + assert_eq!(Elections::voter_info(5), Some(VoterInfo { last_win: 1, last_active: 0, stake: 50, pot: 0 })); + }); + } + + #[test] + fn seats_should_be_released() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(4); + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true, false], 0, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, true], 0, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert!(Elections::presentation_active()); + assert_eq!(Elections::present_winner(Origin::signed(4), 2, 20, 0), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(4), 5, 50, 0), Ok(())); + assert_eq!(Elections::leaderboard(), Some(vec![(0, 0), (0, 0), (20, 2), (50, 5)])); + assert_ok!(Elections::end_block(System::block_number())); + + assert_eq!(Elections::members(), vec![(5, 11), (2, 11)]); + let mut current = System::block_number(); + let free_block; + loop { + current += 1; + System::set_block_number(current); + assert_ok!(Elections::end_block(System::block_number())); + if Elections::members().len() == 0 { + free_block = current; + break; + } + } + // 11 + 2 which is the next voting period. + assert_eq!(free_block, 14); + }); + } + + #[test] + fn presentations_with_zero_staked_deposit_should_not_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(4); + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert_noop!( + Elections::present_winner(Origin::signed(4), 2, 0, 0), + "stake deposited to present winner and be added to leaderboard should be non-zero" + ); + }); + } + + #[test] + fn double_presentations_should_be_punished() { + with_externalities(&mut ExtBuilder::default().build(), || { + assert!(Balances::can_slash(&4, 10)); + + System::set_block_number(4); + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true, false], 0, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, true], 0, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert_ok!(Elections::present_winner(Origin::signed(4), 2, 20, 0)); + assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 0)); + assert_eq!(Elections::present_winner(Origin::signed(4), 5, 50, 0), Err("duplicate presentation")); + assert_ok!(Elections::end_block(System::block_number())); + + assert_eq!(Elections::members(), vec![(5, 11), (2, 11)]); + assert_eq!(Balances::total_balance(&4), 38); + }); + } + + #[test] + fn retracting_inactive_voter_should_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(4); + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert_ok!(Elections::present_winner(Origin::signed(4), 2, 20, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(8); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![true], 1, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(10); + assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 1)); + assert_ok!(Elections::end_block(System::block_number())); + + assert_ok!(Elections::reap_inactive_voter(Origin::signed(5), + (voter_ids().iter().position(|&i| i == 5).unwrap() as u32).into(), + 2, (voter_ids().iter().position(|&i| i == 2).unwrap() as u32).into(), + 2 + )); + + assert_eq!(voter_ids(), vec![0, 5]); + assert_eq!(Elections::all_approvals_of(&2).len(), 0); + assert_eq!(Balances::total_balance(&2), 20); + assert_eq!(Balances::total_balance(&5), 50); + }); + } + + #[test] + fn presenting_for_double_election_should_not_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(4); + assert_eq!(Elections::submit_candidacy(Origin::signed(2), 0), Ok(())); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert_ok!(Elections::present_winner(Origin::signed(4), 2, 20, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(8); + // NOTE: This is now mandatory to disable the lock + assert_ok!(Elections::retract_voter(Origin::signed(2), 0)); + assert_eq!(Elections::submit_candidacy(Origin::signed(2), 0), Ok(())); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 1, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(10); + assert_noop!( + Elections::present_winner(Origin::signed(4), 2, 20, 1), + "candidate must not form a duplicated member if elected" + ); + }); + } + + #[test] + fn retracting_inactive_voter_with_other_candidates_in_slots_should_work() { + with_externalities(&mut ExtBuilder::default().voter_bond(2).build(), || { + System::set_block_number(4); + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert_ok!(Elections::present_winner(Origin::signed(4), 2, 20, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(8); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![true], 1, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(10); + assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 1)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(11); + assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); + + assert_ok!(Elections::reap_inactive_voter(Origin::signed(5), + (voter_ids().iter().position(|&i| i == 5).unwrap() as u32).into(), + 2, (voter_ids().iter().position(|&i| i == 2).unwrap() as u32).into(), + 2 + )); + + assert_eq!(voter_ids(), vec![0, 5]); + assert_eq!(Elections::all_approvals_of(&2).len(), 0); + assert_eq!(Balances::total_balance(&2), 18); + assert_eq!(Balances::total_balance(&5), 52); + }); + } + + #[test] + fn retracting_inactive_voter_with_bad_reporter_index_should_not_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(4); + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert_ok!(Elections::present_winner(Origin::signed(4), 2, 20, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(8); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![true], 1, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(10); + assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 1)); + assert_ok!(Elections::end_block(System::block_number())); + + assert_noop!(Elections::reap_inactive_voter(Origin::signed(2), + 42, + 2, (voter_ids().iter().position(|&i| i == 2).unwrap() as u32).into(), + 2 + ), "invalid reporter index"); + }); + } + + #[test] + fn retracting_inactive_voter_with_bad_target_index_should_not_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(4); + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert_ok!(Elections::present_winner(Origin::signed(4), 2, 20, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(8); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![true], 1, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(10); + assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 1)); + assert_ok!(Elections::end_block(System::block_number())); + + assert_noop!(Elections::reap_inactive_voter(Origin::signed(2), + (voter_ids().iter().position(|&i| i == 2).unwrap() as u32).into(), + 2, 42, + 2 + ), "invalid target index"); + }); + } + + #[test] + fn attempting_to_retract_active_voter_should_slash_reporter() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(4); + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 1)); + assert_ok!(Elections::submit_candidacy(Origin::signed(4), 2)); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 3)); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true, false, false, false], 0, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(3), vec![false, true, false, false], 0, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(4), vec![false, false, true, false], 0, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, false, false, true], 0, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert_ok!(Elections::present_winner(Origin::signed(4), 2, 20, 0)); + assert_ok!(Elections::present_winner(Origin::signed(4), 3, 30, 0)); + assert_ok!(Elections::present_winner(Origin::signed(4), 4, 40, 0)); + assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(8); + assert_ok!(Elections::set_desired_seats(Origin::ROOT, 3)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(10); + assert_ok!(Elections::present_winner(Origin::signed(4), 2, 20 + Elections::get_offset(20, 1), 1)); + assert_ok!(Elections::present_winner(Origin::signed(4), 3, 30 + Elections::get_offset(30, 1), 1)); + assert_ok!(Elections::end_block(System::block_number())); + + assert_eq!(Elections::vote_index(), 2); + assert_eq!(::InactiveGracePeriod::get(), 1); + assert_eq!(::VotingPeriod::get(), 4); + assert_eq!(Elections::voter_info(4), Some(VoterInfo { last_win: 1, last_active: 0, stake: 40, pot: 0 })); + + assert_ok!(Elections::reap_inactive_voter(Origin::signed(4), + (voter_ids().iter().position(|&i| i == 4).unwrap() as u32).into(), + 2, + (voter_ids().iter().position(|&i| i == 2).unwrap() as u32).into(), + 2 + )); + + assert_eq!(voter_ids(), vec![2, 3, 0, 5]); + assert_eq!(Elections::all_approvals_of(&4).len(), 0); + assert_eq!(Balances::total_balance(&4), 40); + }); + } + + #[test] + fn attempting_to_retract_inactive_voter_by_nonvoter_should_not_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(4); + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert_ok!(Elections::present_winner(Origin::signed(4), 2, 20, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(8); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![true], 1, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(10); + assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 1)); + assert_ok!(Elections::end_block(System::block_number())); + + assert_noop!(Elections::reap_inactive_voter(Origin::signed(4), + 0, + 2, (voter_ids().iter().position(|&i| i == 2).unwrap() as u32).into(), + 2 + ), "reporter must be a voter"); + }); + } + + #[test] + fn presenting_loser_should_not_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(4); + assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true], 0, 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 1)); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![false, true], 0, 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 2)); + assert_ok!(Elections::set_approvals(Origin::signed(3), vec![false, false, true], 0, 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(4), 3)); + assert_ok!(Elections::set_approvals(Origin::signed(4), vec![false, false, false, true], 0, 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 4)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, false, false, false, true], 0, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert_ok!(Elections::present_winner(Origin::signed(4), 1, 60, 0)); + assert_ok!(Elections::present_winner(Origin::signed(4), 3, 30, 0)); + assert_ok!(Elections::present_winner(Origin::signed(4), 4, 40, 0)); + assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 0)); + + assert_eq!(Elections::leaderboard(), Some(vec![ + (30, 3), + (40, 4), + (50, 5), + (60, 1) + ])); + + assert_noop!(Elections::present_winner(Origin::signed(4), 2, 20, 0), "candidate not worthy of leaderboard"); + }); + } + + #[test] + fn presenting_loser_first_should_not_matter() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(4); + assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true], 0, 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 1)); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![false, true], 0, 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 2)); + assert_ok!(Elections::set_approvals(Origin::signed(3), vec![false, false, true], 0, 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(4), 3)); + assert_ok!(Elections::set_approvals(Origin::signed(4), vec![false, false, false, true], 0, 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 4)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, false, false, false, true], 0, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert_ok!(Elections::present_winner(Origin::signed(4), 2, 20, 0)); + assert_ok!(Elections::present_winner(Origin::signed(4), 1, 60, 0)); + assert_ok!(Elections::present_winner(Origin::signed(4), 3, 30, 0)); + assert_ok!(Elections::present_winner(Origin::signed(4), 4, 40, 0)); + assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 0)); + + assert_eq!(Elections::leaderboard(), Some(vec![ + (30, 3), + (40, 4), + (50, 5), + (60, 1) + ])); + }); + } + + #[test] + fn present_outside_of_presentation_period_should_not_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(4); + assert!(!Elections::presentation_active()); + assert_noop!( + Elections::present_winner(Origin::signed(5), 5, 1, 0), + "cannot present outside of presentation period" + ); + }); + } + + #[test] + fn present_with_invalid_vote_index_should_not_work() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(4); + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true, false], 0, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, true], 0, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert_noop!(Elections::present_winner(Origin::signed(4), 2, 20, 1), "index not current"); + }); + } + + #[test] + fn present_when_presenter_is_poor_should_not_work() { + let test_present = |p| { + with_externalities(&mut ExtBuilder::default() + .voting_fee(5) + .voter_bond(2) + .bad_presentation_punishment(p) + .build(), + || { + System::set_block_number(4); + let _ = Balances::make_free_balance_be(&1, 15); + assert!(!Elections::presentation_active()); + + assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); // -3 + assert_eq!(Balances::free_balance(&1), 12); + assert_ok!(Elections::set_approvals(Origin::signed(1), vec![true], 0, 0)); // -2 -5 + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert_eq!(Balances::free_balance(&1), 5); + assert_eq!(Balances::reserved_balance(&1), 5); + if p > 5 { + assert_noop!(Elections::present_winner( + Origin::signed(1), 1, 10, 0), + "presenter must have sufficient slashable funds" + ); + } else { + assert_ok!(Elections::present_winner(Origin::signed(1), 1, 10, 0)); + } + }); + }; + test_present(4); + test_present(6); + } + + #[test] + fn invalid_present_tally_should_slash() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(4); + assert!(!Elections::presentation_active()); + assert_eq!(Balances::total_balance(&4), 40); + + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true, false], 0, 0)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, true], 0, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert_err!(Elections::present_winner(Origin::signed(4), 2, 80, 0), "incorrect total"); + + assert_eq!(Balances::total_balance(&4), 38); + }); + } + + #[test] + fn runners_up_should_be_kept() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(4); + assert!(!Elections::presentation_active()); + + assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true], 0, 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 1)); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![false, true], 0, 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 2)); + assert_ok!(Elections::set_approvals(Origin::signed(3), vec![false, false, true], 0, 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(4), 3)); + assert_ok!(Elections::set_approvals(Origin::signed(4), vec![false, false, false, true], 0, 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 4)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, false, false, false, true], 0, 0)); + + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert!(Elections::presentation_active()); + assert_ok!(Elections::present_winner(Origin::signed(4), 1, 60, 0)); + // leaderboard length is the empty seats plus the carry count (i.e. 5 + 2), where those + // to be carried are the lowest and stored in lowest indices + assert_eq!(Elections::leaderboard(), Some(vec![ + (0, 0), + (0, 0), + (0, 0), + (60, 1) + ])); + assert_ok!(Elections::present_winner(Origin::signed(4), 3, 30, 0)); + assert_ok!(Elections::present_winner(Origin::signed(4), 4, 40, 0)); + assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 0)); + assert_eq!(Elections::leaderboard(), Some(vec![ + (30, 3), + (40, 4), + (50, 5), + (60, 1) + ])); + + assert_ok!(Elections::end_block(System::block_number())); + + assert!(!Elections::presentation_active()); + assert_eq!(Elections::members(), vec![(1, 11), (5, 11)]); + + assert!(!Elections::is_a_candidate(&1)); + assert!(!Elections::is_a_candidate(&5)); + assert!(!Elections::is_a_candidate(&2)); + assert!(Elections::is_a_candidate(&3)); + assert!(Elections::is_a_candidate(&4)); + assert_eq!(Elections::vote_index(), 1); + assert_eq!(Elections::voter_info(2), Some(VoterInfo { last_win: 0, last_active: 0, stake: 20, pot: 0 })); + assert_eq!(Elections::voter_info(3), Some(VoterInfo { last_win: 0, last_active: 0, stake: 30, pot: 0 })); + assert_eq!(Elections::voter_info(4), Some(VoterInfo { last_win: 0, last_active: 0, stake: 40, pot: 0 })); + assert_eq!(Elections::voter_info(5), Some(VoterInfo { last_win: 1, last_active: 0, stake: 50, pot: 0 })); + assert_eq!(Elections::voter_info(6), Some(VoterInfo { last_win: 1, last_active: 0, stake: 60, pot: 0 })); + assert_eq!(Elections::candidate_reg_info(3), Some((0, 2))); + assert_eq!(Elections::candidate_reg_info(4), Some((0, 3))); + }); + } + + #[test] + fn second_tally_should_use_runners_up() { + with_externalities(&mut ExtBuilder::default().build(), || { + System::set_block_number(4); + assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); + assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true], 0, 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(2), 1)); + assert_ok!(Elections::set_approvals(Origin::signed(2), vec![false, true], 0, 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(3), 2)); + assert_ok!(Elections::set_approvals(Origin::signed(3), vec![false, false, true], 0, 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(4), 3)); + assert_ok!(Elections::set_approvals(Origin::signed(4), vec![false, false, false, true], 0, 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 4)); + assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, false, false, false, true], 0, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert_ok!(Elections::present_winner(Origin::signed(4), 1, 60, 0)); + assert_ok!(Elections::present_winner(Origin::signed(4), 3, 30, 0)); + assert_ok!(Elections::present_winner(Origin::signed(4), 4, 40, 0)); + assert_ok!(Elections::present_winner(Origin::signed(4), 5, 50, 0)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(8); + assert_ok!(Elections::set_approvals(Origin::signed(6), vec![false, false, true, false], 1, 0)); + assert_ok!(Elections::set_desired_seats(Origin::ROOT, 3)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(10); + assert_ok!(Elections::present_winner(Origin::signed(4), 3, 30 + Elections::get_offset(30, 1) + 60, 1)); + assert_ok!(Elections::present_winner(Origin::signed(4), 4, 40 + Elections::get_offset(40, 1), 1)); + assert_ok!(Elections::end_block(System::block_number())); + + assert!(!Elections::presentation_active()); + assert_eq!(Elections::members(), vec![(1, 11), (5, 11), (3, 15)]); + + assert!(!Elections::is_a_candidate(&1)); + assert!(!Elections::is_a_candidate(&2)); + assert!(!Elections::is_a_candidate(&3)); + assert!(!Elections::is_a_candidate(&5)); + assert!(Elections::is_a_candidate(&4)); + assert_eq!(Elections::vote_index(), 2); + assert_eq!(Elections::voter_info(2), Some( VoterInfo { last_win: 0, last_active: 0, stake: 20, pot: 0})); + assert_eq!(Elections::voter_info(3), Some( VoterInfo { last_win: 2, last_active: 0, stake: 30, pot: 0})); + assert_eq!(Elections::voter_info(4), Some( VoterInfo { last_win: 0, last_active: 0, stake: 40, pot: 0})); + assert_eq!(Elections::voter_info(5), Some( VoterInfo { last_win: 1, last_active: 0, stake: 50, pot: 0})); + assert_eq!( + Elections::voter_info(6), + Some(VoterInfo { last_win: 2, last_active: 1, stake: 60, pot: 0}) + ); + + assert_eq!(Elections::candidate_reg_info(4), Some((0, 3))); + }); + } +} diff --git a/srml/example/Cargo.toml b/srml/example/Cargo.toml index 44a6a85e47e0f0c408bba993990f6f5f1b804663..f46ce5474924274de827bf42031be85341f2001c 100644 --- a/srml/example/Cargo.toml +++ b/srml/example/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] serde = { version = "1.0", optional = true } -parity-codec = { version = "3.3", default-features = false } +parity-codec = { version = "4.1.1", default-features = false } srml-support = { path = "../support", default-features = false } system = { package = "srml-system", path = "../system", default-features = false } balances = { package = "srml-balances", path = "../balances", default-features = false } diff --git a/srml/example/src/lib.rs b/srml/example/src/lib.rs index dd14b7198acd3aee381228b1064bfdd0c75279bc..20ee1c6ba114ff182a8fdc4ce2cde0011819187f 100644 --- a/srml/example/src/lib.rs +++ b/srml/example/src/lib.rs @@ -254,7 +254,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use srml_support::{StorageValue, dispatch::Result, decl_module, decl_storage, decl_event}; -use system::ensure_signed; +use system::{ensure_signed, ensure_root}; use sr_primitives::weights::TransactionWeight; /// Our module's configuration trait. All our types and consts go in here. If the @@ -440,7 +440,7 @@ decl_module! { } /// A privileged call; in this case it resets our dummy value to something new. - // Implementation of a privileged call. This doesn't have an `origin` parameter because + // Implementation of a privileged call. The `origin` parameter is ROOT because // it's not (directly) from an extrinsic, but rather the system as a whole has decided // to execute it. Different runtimes have different reasons for allow privileged // calls to be executed - we don't need to care why. Because it's privileged, we can @@ -448,7 +448,8 @@ decl_module! { // without worrying about gameability or attack scenarios. // If you not specify `Result` explicitly as return value, it will be added automatically // for you and `Ok(())` will be returned. - fn set_dummy(#[compact] new_value: T::Balance) { + fn set_dummy(origin, #[compact] new_value: T::Balance) { + ensure_root(origin)?; // Put the new value into storage. >::put(new_value); } @@ -504,14 +505,13 @@ impl Module { mod tests { use super::*; - use srml_support::{impl_outer_origin, assert_ok}; + use srml_support::{assert_ok, impl_outer_origin, parameter_types}; use sr_io::with_externalities; use substrate_primitives::{H256, Blake2Hasher}; // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are requried. use sr_primitives::{ - BuildStorage, traits::{BlakeTwo256, OnInitialize, OnFinalize, IdentityLookup}, - testing::Header + traits::{BlakeTwo256, OnInitialize, OnFinalize, IdentityLookup}, testing::Header }; impl_outer_origin! { @@ -523,6 +523,9 @@ mod tests { // configuration traits of modules we want to use. #[derive(Clone, Eq, PartialEq)] pub struct Test; + parameter_types! { + pub const BlockHashCount: u64 = 250; + } impl system::Trait for Test { type Origin = Origin; type Index = u64; @@ -533,6 +536,14 @@ mod tests { type Lookup = IdentityLookup; type Header = Header; type Event = (); + type BlockHashCount = BlockHashCount; + } + parameter_types! { + pub const ExistentialDeposit: u64 = 0; + pub const TransferFee: u64 = 0; + pub const CreationFee: u64 = 0; + pub const TransactionBaseFee: u64 = 0; + pub const TransactionByteFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; @@ -542,6 +553,11 @@ mod tests { type TransactionPayment = (); type TransferPayment = (); type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type TransferFee = TransferFee; + type CreationFee = CreationFee; + type TransactionBaseFee = TransactionBaseFee; + type TransactionByteFee = TransactionByteFee; } impl Trait for Test { type Event = (); @@ -551,7 +567,7 @@ mod tests { // This function basically just builds a genesis storage key/value store according to // our desired mockup. fn new_test_ext() -> sr_io::TestExternalities { - let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; + let mut t = system::GenesisConfig::default().build_storage::().unwrap().0; // We use default for brevity, but you can configure as desired if needed. t.extend(balances::GenesisConfig::::default().build_storage().unwrap().0); t.extend(GenesisConfig::{ diff --git a/srml/executive/Cargo.toml b/srml/executive/Cargo.toml index 7089a2aa9b973b363705041792c54d1bf985206d..27057fe523ab39b01baa4d57f085c0b991dd7c21 100644 --- a/srml/executive/Cargo.toml +++ b/srml/executive/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] serde = { version = "1.0", optional = true } -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } runtime_io = { package = "sr-io", path = "../../core/sr-io", default-features = false } primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index f4299abe476306dba563bf27491eb57f3ca3fd6d..49d4addb3bc2bfd3e20e2d02c15e2e202d3cc641 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -395,10 +395,10 @@ mod tests { use balances::Call; use runtime_io::with_externalities; use substrate_primitives::{H256, Blake2Hasher}; - use primitives::BuildStorage; use primitives::traits::{Header as HeaderT, BlakeTwo256, IdentityLookup}; use primitives::testing::{Digest, Header, Block}; - use srml_support::{traits::Currency, impl_outer_origin, impl_outer_event}; + use srml_support::{impl_outer_event, impl_outer_origin, parameter_types}; + use srml_support::traits::{Currency, LockIdentifier, LockableCurrency, WithdrawReasons, WithdrawReason}; use system; use hex_literal::hex; @@ -416,6 +416,9 @@ mod tests { // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, Eq, PartialEq)] pub struct Runtime; + parameter_types! { + pub const BlockHashCount: u64 = 250; + } impl system::Trait for Runtime { type Origin = Origin; type Index = u64; @@ -426,6 +429,14 @@ mod tests { type Lookup = IdentityLookup; type Header = Header; type Event = MetaEvent; + type BlockHashCount = BlockHashCount; + } + parameter_types! { + pub const ExistentialDeposit: u64 = 0; + pub const TransferFee: u64 = 0; + pub const CreationFee: u64 = 0; + pub const TransactionBaseFee: u64 = 10; + pub const TransactionByteFee: u64 = 0; } impl balances::Trait for Runtime { type Balance = u64; @@ -435,6 +446,11 @@ mod tests { type TransactionPayment = (); type DustRemoval = (); type TransferPayment = (); + type ExistentialDeposit = ExistentialDeposit; + type TransferFee = TransferFee; + type CreationFee = CreationFee; + type TransactionBaseFee = TransactionBaseFee; + type TransactionByteFee = TransactionByteFee; } impl ValidateUnsigned for Runtime { @@ -466,18 +482,13 @@ mod tests { #[test] fn balance_transfer_dispatch_works() { - let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; - t.extend(balances::GenesisConfig:: { - transaction_base_fee: 10, - transaction_byte_fee: 0, + let mut t = system::GenesisConfig::default().build_storage::().unwrap(); + balances::GenesisConfig:: { balances: vec![(1, 111)], - existential_deposit: 0, - transfer_fee: 0, - creation_fee: 0, vesting: vec![], - }.build_storage().unwrap().0); + }.assimilate_storage(&mut t.0, &mut t.1).unwrap(); let xt = primitives::testing::TestXt(Some(1), 0, Call::transfer(2, 69)); - let mut t = runtime_io::TestExternalities::::new(t); + let mut t = runtime_io::TestExternalities::::new_with_children(t); with_externalities(&mut t, || { Executive::initialize_block(&Header::new( 1, @@ -487,14 +498,17 @@ mod tests { Digest::default(), )); Executive::apply_extrinsic(xt).unwrap(); - assert_eq!(>::total_balance(&1), 32); + assert_eq!(>::total_balance(&1), 42 - 10); assert_eq!(>::total_balance(&2), 69); }); } fn new_test_ext() -> runtime_io::TestExternalities { - let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; - t.extend(balances::GenesisConfig::::default().build_storage().unwrap().0); + let mut t = system::GenesisConfig::default().build_storage::().unwrap().0; + t.extend(balances::GenesisConfig:: { + balances: vec![(1, 111)], + vesting: vec![], + }.build_storage().unwrap().0); t.into() } @@ -505,7 +519,7 @@ mod tests { header: Header { parent_hash: [69u8; 32].into(), number: 1, - state_root: hex!("5ba497e45e379d80a4524f9509d224e9c175d0fa30f3491481e7e44a6a758adf").into(), + state_root: hex!("9159f07939faa7de6ec7f46e292144fc82112c42ead820dfb588f1788f3e8058").into(), extrinsics_root: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").into(), digest: Digest { logs: vec![], }, }, @@ -634,4 +648,41 @@ mod tests { assert_eq!(Executive::apply_extrinsic(xt), Ok(ApplyOutcome::Fail)); }); } + + #[test] + fn can_pay_for_tx_fee_on_full_lock() { + let id: LockIdentifier = *b"0 "; + let execute_with_lock = |lock: WithdrawReasons| { + let mut t = new_test_ext(); + with_externalities(&mut t, || { + as LockableCurrency>::set_lock( + id, + &1, + 110, + 10, + lock, + ); + let xt = primitives::testing::TestXt(Some(1), 0, Call::transfer(2, 10)); + Executive::initialize_block(&Header::new( + 1, + H256::default(), + H256::default(), + [69u8; 32].into(), + Digest::default(), + )); + + if lock == WithdrawReasons::except(WithdrawReason::TransactionPayment) { + assert_eq!(Executive::apply_extrinsic(xt).unwrap(), ApplyOutcome::Fail); + // but tx fee has been deducted. the transaction failed on transfer, not on fee. + assert_eq!(>::total_balance(&1), 111 - 10); + } else { + assert_eq!(Executive::apply_extrinsic(xt), Err(ApplyError::CantPay)); + assert_eq!(>::total_balance(&1), 111); + } + }); + }; + + execute_with_lock(WithdrawReasons::all()); + execute_with_lock(WithdrawReasons::except(WithdrawReason::TransactionPayment)); + } } diff --git a/srml/finality-tracker/Cargo.toml b/srml/finality-tracker/Cargo.toml index e6cf47ab25a26db462e35d96a8a3e344e9446cd8..e7eea0e152676dcde2ab5340759ce102f7c0de06 100644 --- a/srml/finality-tracker/Cargo.toml +++ b/srml/finality-tracker/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] serde = { version = "1.0", default-features = false, features = ["derive"] } -parity-codec = { version = "3.3", default-features = false } +parity-codec = { version = "4.1.1", default-features = false } inherents = { package = "substrate-inherents", path = "../../core/inherents", default-features = false } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } @@ -16,8 +16,6 @@ srml-system = { path = "../system", default-features = false } [dev-dependencies] substrate-primitives = { path = "../../core/primitives", default-features = false } sr-io = { path = "../../core/sr-io", default-features = false } -lazy_static = "1.0" -parking_lot = "0.8.0" [features] default = ["std"] diff --git a/srml/finality-tracker/src/lib.rs b/srml/finality-tracker/src/lib.rs index 6442fee543ab4dc7d996907c7167af3f3d91c4e2..f9ccc363462220c0f7f88f257ec26daf622bc47d 100644 --- a/srml/finality-tracker/src/lib.rs +++ b/srml/finality-tracker/src/lib.rs @@ -18,9 +18,6 @@ #![cfg_attr(not(feature = "std"), no_std)] -#[macro_use] -extern crate srml_support; - use inherents::{ RuntimeString, InherentIdentifier, ProvideInherent, InherentData, MakeFatalError, @@ -29,14 +26,13 @@ use srml_support::StorageValue; use primitives::traits::{One, Zero, SaturatedConversion}; use rstd::{prelude::*, result, cmp, vec}; use parity_codec::Decode; +use srml_support::{decl_module, decl_storage, for_each_tuple}; +use srml_support::traits::Get; use srml_system::{ensure_none, Trait as SystemTrait}; #[cfg(feature = "std")] use parity_codec::Encode; -const DEFAULT_WINDOW_SIZE: u32 = 101; -const DEFAULT_DELAY: u32 = 1000; - /// The identifier for the `finalnum` inherent. pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"finalnum"; @@ -85,10 +81,17 @@ impl inherents::ProvideInherentData for InherentDataProvider } } +pub const DEFAULT_WINDOW_SIZE: u32 = 101; +pub const DEFAULT_REPORT_LATENCY: u32 = 1000; pub trait Trait: SystemTrait { - /// Something which can be notified when the timestamp is set. Set this to `()` if not needed. + /// Something which can be notified when the timestamp is set. Set this to `()` + /// if not needed. type OnFinalizationStalled: OnFinalizationStalled; + /// The number of recent samples to keep from this chain. Default is 101. + type WindowSize: Get; + /// The delay after which point things become suspicious. Default is 1000. + type ReportLatency: Get; } decl_storage! { @@ -99,10 +102,6 @@ decl_storage! { OrderedHints get(ordered_hints) build(|_| vec![T::BlockNumber::zero()]): Vec; /// The median. Median get(median) build(|_| T::BlockNumber::zero()): T::BlockNumber; - /// The number of recent samples to keep from this chain. Default is n-100 - pub WindowSize get(window_size) config(window_size): T::BlockNumber = DEFAULT_WINDOW_SIZE.into(); - /// The delay after which point things become suspicious. - pub ReportLatency get(report_latency) config(report_latency): T::BlockNumber = DEFAULT_DELAY.into(); /// Final hint to apply in the block. `None` means "same as parent". Update: Option; @@ -114,6 +113,12 @@ decl_storage! { decl_module! { pub struct Module for enum Call where origin: T::Origin { + /// The number of recent samples to keep from this chain. Default is 101. + const WindowSize: T::BlockNumber = T::WindowSize::get(); + + /// The delay after which point things become suspicious. Default is 1000. + const ReportLatency: T::BlockNumber = T::ReportLatency::get(); + /// Hint that the author of this block thinks the best finalized /// block is the given number. fn final_hint(origin, #[compact] hint: T::BlockNumber) { @@ -144,7 +149,7 @@ impl Module { let mut recent = Self::recent_hints(); let mut ordered = Self::ordered_hints(); - let window_size = cmp::max(T::BlockNumber::one(), Self::window_size()); + let window_size = cmp::max(T::BlockNumber::one(), T::WindowSize::get()); let hint = hint.unwrap_or_else(|| recent.last() .expect("always at least one recent sample; qed").clone() @@ -196,7 +201,7 @@ impl Module { if T::BlockNumber::from(our_window_size) == window_size { let now = srml_system::Module::::block_number(); - let latency = Self::report_latency(); + let latency = T::ReportLatency::get(); // the delay is the latency plus half the window size. let delay = latency + (window_size / two); @@ -261,13 +266,11 @@ mod tests { use sr_io::{with_externalities, TestExternalities}; use substrate_primitives::H256; - use primitives::BuildStorage; use primitives::traits::{BlakeTwo256, IdentityLookup, OnFinalize, Header as HeaderT}; use primitives::testing::Header; - use srml_support::impl_outer_origin; + use srml_support::{assert_ok, impl_outer_origin, parameter_types}; use srml_system as system; - use lazy_static::lazy_static; - use parking_lot::Mutex; + use std::cell::RefCell; #[derive(Clone, PartialEq, Debug)] pub struct StallEvent { @@ -275,71 +278,67 @@ mod tests { further_wait: u64, } - macro_rules! make_test_context { - () => { - #[derive(Clone, Eq, PartialEq)] - pub struct Test; - - impl_outer_origin! { - pub enum Origin for Test {} - } - - impl system::Trait for Test { - type Origin = Origin; - type Index = u64; - type BlockNumber = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type Header = Header; - type Event = (); - } - - type System = system::Module; - - lazy_static! { - static ref NOTIFICATIONS: Mutex> = Mutex::new(Vec::new()); - } + #[derive(Clone, Eq, PartialEq)] + pub struct Test; - pub struct StallTracker; - impl OnFinalizationStalled for StallTracker { - fn on_stalled(further_wait: u64, _median: u64) { - let now = System::block_number(); - NOTIFICATIONS.lock().push(StallEvent { at: now, further_wait }); - } - } + impl_outer_origin! { + pub enum Origin for Test {} + } - impl Trait for Test { - type OnFinalizationStalled = StallTracker; - } + thread_local! { + static NOTIFICATIONS: RefCell> = Default::default(); + } - type FinalityTracker = Module; + pub struct StallTracker; + impl OnFinalizationStalled for StallTracker { + fn on_stalled(further_wait: u64, _median: u64) { + let now = System::block_number(); + NOTIFICATIONS.with(|v| v.borrow_mut().push(StallEvent { at: now, further_wait })); } } + parameter_types! { + pub const BlockHashCount: u64 = 250; + } + impl system::Trait for Test { + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = (); + type BlockHashCount = BlockHashCount; + } + parameter_types! { + pub const WindowSize: u64 = 11; + pub const ReportLatency: u64 = 100; + } + impl Trait for Test { + type OnFinalizationStalled = StallTracker; + type WindowSize = WindowSize; + type ReportLatency = ReportLatency; + } + + type System = system::Module; + type FinalityTracker = Module; + #[test] fn median_works() { - make_test_context!(); - let t = system::GenesisConfig::::default().build_storage().unwrap().0; - - with_externalities(&mut TestExternalities::new(t), || { + let t = system::GenesisConfig::default().build_storage::().unwrap(); + with_externalities(&mut TestExternalities::new_with_children(t), || { FinalityTracker::update_hint(Some(500)); assert_eq!(FinalityTracker::median(), 250); - assert!(NOTIFICATIONS.lock().is_empty()); + assert!(NOTIFICATIONS.with(|n| n.borrow().is_empty())); }); } #[test] fn notifies_when_stalled() { - make_test_context!(); - let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; - t.extend(GenesisConfig:: { - window_size: 11, - report_latency: 100 - }.build_storage().unwrap().0); - - with_externalities(&mut TestExternalities::new(t), || { + let t = system::GenesisConfig::default().build_storage::().unwrap(); + with_externalities(&mut TestExternalities::new_with_children(t), || { let mut parent_hash = System::parent_hash(); for i in 2..106 { System::initialize(&i, &parent_hash, &Default::default(), &Default::default()); @@ -349,7 +348,7 @@ mod tests { } assert_eq!( - NOTIFICATIONS.lock().to_vec(), + NOTIFICATIONS.with(|n| n.borrow().clone()), vec![StallEvent { at: 105, further_wait: 10 }] ) }); @@ -357,14 +356,8 @@ mod tests { #[test] fn recent_notifications_prevent_stalling() { - make_test_context!(); - let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; - t.extend(GenesisConfig:: { - window_size: 11, - report_latency: 100 - }.build_storage().unwrap().0); - - with_externalities(&mut TestExternalities::new(t), || { + let t = system::GenesisConfig::default().build_storage::().unwrap(); + with_externalities(&mut TestExternalities::new_with_children(t), || { let mut parent_hash = System::parent_hash(); for i in 2..106 { System::initialize(&i, &parent_hash, &Default::default(), &Default::default()); @@ -377,7 +370,7 @@ mod tests { parent_hash = hdr.hash(); } - assert!(NOTIFICATIONS.lock().is_empty()); + assert!(NOTIFICATIONS.with(|n| n.borrow().is_empty())); }); } } diff --git a/srml/generic-asset/Cargo.toml b/srml/generic-asset/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..bfa49d8018e52484783caa7631ff17025b8baf30 --- /dev/null +++ b/srml/generic-asset/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "srml-generic-asset" +version = "2.0.0" +authors = ["Centrality Developers "] +edition = "2018" + +[dependencies] +serde = { version = "1.0", optional = true } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } +rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } +primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } +support = { package = "srml-support", path = "../support", default-features = false } +system = { package = "srml-system", path = "../system", default-features = false } + +[dev-dependencies] +runtime_io = { package = "sr-io", path = "../../core/sr-io" } +substrate-primitives = { path = "../../core/primitives" } + +[features] +default = ["std"] +std =[ + "serde/std", + "parity-codec/std", + "rstd/std", + "primitives/std", + "support/std", + "system/std", +] diff --git a/srml/generic-asset/src/lib.rs b/srml/generic-asset/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..60370600a69a630ac9f10bba99d36a12390eef48 --- /dev/null +++ b/srml/generic-asset/src/lib.rs @@ -0,0 +1,1286 @@ +// Copyright 2019 +// by Centrality Investments Ltd. +// and Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +//! # Generic Asset Module +//! +//! The Generic Asset module provides functionality for handling accounts and asset balances. +//! +//! ## Overview +//! +//! The Generic Asset module provides functions for: +//! +//! - Creating a new kind of asset. +//! - Setting permissions of an asset. +//! - Getting and setting free balances. +//! - Retrieving total, reserved and unreserved balances. +//! - Repatriating a reserved balance to a beneficiary account. +//! - Transferring a balance between accounts (when not reserved). +//! - Slashing an account balance. +//! - Managing total issuance. +//! - Setting and managing locks. +//! +//! ### Terminology +//! +//! - **Staking Asset:** The asset for staking, to participate as Validators in the network. +//! - **Spending Asset:** The asset for payment, such as paying transfer fees, gas fees, etc. +//! - **Permissions:** A set of rules for a kind of asset, defining the allowed operations to the asset, and which +//! accounts are allowed to possess it. +//! - **Total Issuance:** The total number of units in existence in a system. +//! - **Free Balance:** The portion of a balance that is not reserved. The free balance is the only balance that matters +//! for most operations. When this balance falls below the existential deposit, most functionality of the account is +//! removed. When both it and the reserved balance are deleted, then the account is said to be dead. +//! - **Reserved Balance:** Reserved balance still belongs to the account holder, but is suspended. Reserved balance +//! can still be slashed, but only after all the free balance has been slashed. If the reserved balance falls below the +//! existential deposit then it and any related functionality will be deleted. When both it and the free balance are +//! deleted, then the account is said to be dead. +//! - **Imbalance:** A condition when some assets were credited or debited without equal and opposite accounting +//! (i.e. a difference between total issuance and account balances). Functions that result in an imbalance will +//! return an object of the `Imbalance` trait that can be managed within your runtime logic. (If an imbalance is +//! simply dropped, it should automatically maintain any book-keeping such as total issuance.) +//! - **Lock:** A freeze on a specified amount of an account's free balance until a specified block number. Multiple +//! locks always operate over the same funds, so they "overlay" rather than "stack". +//! +//! ### Implementations +//! +//! The Generic Asset module provides `AssetCurrency`, which implements the following traits. If these traits provide +//! the functionality that you need, you can avoid coupling with the Generic Asset module. +//! +//! - `Currency`: Functions for dealing with a fungible assets system. +//! - `ReservableCurrency`: Functions for dealing with assets that can be reserved from an account. +//! - `LockableCurrency`: Functions for dealing with accounts that allow liquidity restrictions. +//! - `Imbalance`: Functions for handling imbalances between total issuance in the system and account balances. +//! Must be used when a function creates new assets (e.g. a reward) or destroys some assets (e.g. a system fee). +//! +//! The Generic Asset module provides two types of `AssetCurrency` as follows. +//! +//! - `StakingAssetCurrency`: Currency for staking. +//! - `SpendingAssetCurrency`: Currency for payments such as transfer fee, gas fee. +//! +//! ## Interface +//! +//! ### Dispatchable Functions +//! +//! - `create`: Create a new kind of asset. +//! - `transfer`: Transfer some liquid free balance to another account. +//! - `update_permission`: Updates permission for a given `asset_id` and an account. The origin of this call +//! must have update permissions. +//! - `mint`: Mint an asset, increases its total issuance. The origin of this call must have mint permissions. +//! - `burn`: Burn an asset, decreases its total issuance. The origin of this call must have burn permissions. +//! - `create_reserved`: Create a new kind of reserved asset. The origin of this call must be root. +//! +//! ### Public Functions +//! +//! - `total_balance`: Get an account's total balance of an asset kind. +//! - `free_balance`: Get an account's free balance of an asset kind. +//! - `reserved_balance`: Get an account's reserved balance of an asset kind. +//! - `create_asset`: Creates an asset. +//! - `make_transfer`: Transfer some liquid free balance from one account to another. +//! This will not emit the `Transferred` event. +//! - `make_transfer_with_event`: Transfer some liquid free balance from one account to another. +//! This will emit the `Transferred` event. +//! - `reserve`: Moves an amount from free balance to reserved balance. +//! - `unreserve`: Move up to an amount from reserved balance to free balance. This function cannot fail. +//! - `slash`: Deduct up to an amount from the combined balance of `who`, preferring to deduct from the +//! free balance. This function cannot fail. +//! - `reward`: Add up to an amount to the free balance of an account. +//! - `slash_reserved`: Deduct up to an amount from reserved balance of an account. This function cannot fail. +//! - `repatriate_reserved`: Move up to an amount from reserved balance of an account to free balance of another +//! account. +//! - `check_permission`: Check permission to perform burn, mint or update. +//! - `ensure_can_withdraw`: Check if the account is able to make a withdrawal of the given amount +//! for the given reason. +//! +//! ### Usage +//! +//! The following examples show how to use the Generic Asset module in your custom module. +//! +//! ### Examples from the PRML +//! +//! The Fees module uses the `Currency` trait to handle fee charge/refund, and its types inherit from `Currency`: +//! +//! ``` +//! use support::{ +//! traits::{Currency, ExistenceRequirement, WithdrawReason}, +//! dispatch::Result, +//! }; +//! # pub trait Trait: system::Trait { +//! # type Currency: Currency; +//! # } +//! type AssetOf = <::Currency as Currency<::AccountId>>::Balance; +//! +//! fn charge_fee(transactor: &T::AccountId, amount: AssetOf) -> Result { +//! // ... +//! T::Currency::withdraw( +//! transactor, +//! amount, +//! WithdrawReason::TransactionPayment, +//! ExistenceRequirement::KeepAlive, +//! )?; +//! // ... +//! Ok(()) +//! } +//! +//! fn refund_fee(transactor: &T::AccountId, amount: AssetOf) -> Result { +//! // ... +//! T::Currency::deposit_into_existing(transactor, amount)?; +//! // ... +//! Ok(()) +//! } +//! +//! # fn main() {} +//! ``` +//! +//! ## Genesis config +//! +//! The Generic Asset module depends on the [`GenesisConfig`](./struct.GenesisConfig.html). + +#![cfg_attr(not(feature = "std"), no_std)] + +use parity_codec::{Decode, Encode, HasCompact, Input, Output}; + +use primitives::traits::{ + CheckedAdd, CheckedSub, MaybeSerializeDebug, Member, One, Saturating, SimpleArithmetic, Zero, Bounded +}; + +use rstd::prelude::*; +use rstd::{cmp, result}; +use support::dispatch::Result; +use support::{ + decl_event, decl_module, decl_storage, ensure, + traits::{ + Currency, ExistenceRequirement, Imbalance, LockIdentifier, LockableCurrency, ReservableCurrency, + SignedImbalance, UpdateBalanceOutcome, WithdrawReason, WithdrawReasons, + }, + Parameter, StorageDoubleMap, StorageMap, StorageValue, +}; +use system::{ensure_signed, ensure_root}; + +mod mock; +mod tests; + +pub use self::imbalances::{NegativeImbalance, PositiveImbalance}; + +pub trait Trait: system::Trait { + type Balance: Parameter + + Member + + SimpleArithmetic + + Default + + Copy + + MaybeSerializeDebug; + type AssetId: Parameter + Member + SimpleArithmetic + Default + Copy; + type Event: From> + Into<::Event>; +} + +pub trait Subtrait: system::Trait { + type Balance: Parameter + + Member + + SimpleArithmetic + + Default + + Copy + + MaybeSerializeDebug; + type AssetId: Parameter + Member + SimpleArithmetic + Default + Copy; +} + +impl Subtrait for T { + type Balance = T::Balance; + type AssetId = T::AssetId; +} + +/// Asset creation options. +#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, Encode, Decode, PartialEq, Eq)] +pub struct AssetOptions { + /// Initial issuance of this asset. All deposit to the creater of the asset. + #[codec(compact)] + pub initial_issuance: Balance, + /// Which accounts are allowed to possess this asset. + pub permissions: PermissionLatest, +} + +/// Owner of an asset. +#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, Encode, Decode, PartialEq, Eq)] +pub enum Owner { + /// No owner. + None, + /// Owned by an AccountId + Address(AccountId), +} + +impl Default for Owner { + fn default() -> Self { + Owner::None + } +} + +/// Asset permissions +#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, Encode, Decode, PartialEq, Eq)] +pub struct PermissionsV1 { + /// Who have permission to update asset permission + pub update: Owner, + /// Who have permission to mint new asset + pub mint: Owner, + /// Who have permission to burn asset + pub burn: Owner, +} + +#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, Encode, Decode, PartialEq, Eq)] +#[repr(u8)] +enum PermissionVersionNumber { + V1 = 0, +} + +/// Versioned asset permission +#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, PartialEq, Eq)] +pub enum PermissionVersions { + V1(PermissionsV1), +} + +/// Asset permission types +pub enum PermissionType { + /// Permission to update asset permission + Burn, + /// Permission to mint new asset + Mint, + /// Permission to burn asset + Update, +} + +/// Alias to latest asset permissions +pub type PermissionLatest = PermissionsV1; + +impl Default for PermissionVersions { + fn default() -> Self { + PermissionVersions::V1(Default::default()) + } +} + +impl Encode for PermissionVersions { + fn encode_to(&self, dest: &mut T) { + match self { + PermissionVersions::V1(payload) => { + dest.push(&PermissionVersionNumber::V1); + dest.push(payload); + }, + } + } +} + +impl Decode for PermissionVersions { + fn decode(input: &mut I) -> Option { + let version = PermissionVersionNumber::decode(input)?; + Some( + match version { + PermissionVersionNumber::V1 => PermissionVersions::V1(Decode::decode(input)?) + } + ) + } +} + +impl Default for PermissionsV1 { + fn default() -> Self { + PermissionsV1 { + update: Owner::None, + mint: Owner::None, + burn: Owner::None, + } + } +} + +impl Into> for PermissionVersions { + fn into(self) -> PermissionLatest { + match self { + PermissionVersions::V1(v1) => v1, + } + } +} + +/// Converts the latest permission to other version. +impl Into> for PermissionLatest { + fn into(self) -> PermissionVersions { + PermissionVersions::V1(self) + } +} + +decl_module! { + pub struct Module for enum Call where origin: T::Origin { + fn deposit_event() = default; + + /// Create a new kind of asset. + fn create(origin, options: AssetOptions) -> Result { + let origin = ensure_signed(origin)?; + let id = Self::next_asset_id(); + + let permissions: PermissionVersions = options.permissions.clone().into(); + + // The last available id serves as the overflow mark and won't be used. + let next_id = id.checked_add(&One::one()).ok_or_else(|| "No new assets id available.")?; + + >::put(next_id); + >::insert(id, &options.initial_issuance); + >::insert(&id, &origin, options.initial_issuance); + >::insert(&id, permissions); + + Self::deposit_event(RawEvent::Created(id, origin, options)); + + Ok(()) + } + + /// Transfer some liquid free balance to another account. + pub fn transfer(origin, #[compact] asset_id: T::AssetId, to: T::AccountId, #[compact] amount: T::Balance) { + let origin = ensure_signed(origin)?; + ensure!(!amount.is_zero(), "cannot transfer zero amount"); + Self::make_transfer_with_event(&asset_id, &origin, &to, amount)?; + } + + /// Updates permission for a given `asset_id` and an account. + /// + /// The `origin` must have `update` permission. + fn update_permission( + origin, + #[compact] asset_id: T::AssetId, + new_permission: PermissionLatest + ) -> Result { + let origin = ensure_signed(origin)?; + + let permissions: PermissionVersions = new_permission.into(); + + if Self::check_permission(&asset_id, &origin, &PermissionType::Update) { + >::insert(asset_id, &permissions); + + Self::deposit_event(RawEvent::PermissionUpdated(asset_id, permissions.into())); + + Ok(()) + } else { + Err("Origin does not have enough permission to update permissions.") + } + } + + /// Mints an asset, increases its total issuance. + /// The origin must have `mint` permissions. + fn mint(origin, #[compact] asset_id: T::AssetId, to: T::AccountId, amount: T::Balance) -> Result { + let origin = ensure_signed(origin)?; + if Self::check_permission(&asset_id, &origin, &PermissionType::Mint) { + let original_free_balance = Self::free_balance(&asset_id, &to); + let current_total_issuance = >::get(asset_id); + let new_total_issuance = current_total_issuance.checked_add(&amount) + .ok_or_else(|| "total_issuance got overflow after minting.")?; + let value = original_free_balance.checked_add(&amount) + .ok_or_else(|| "free balance got overflow after minting.")?; + + >::insert(asset_id, new_total_issuance); + Self::set_free_balance(&asset_id, &to, value); + + Self::deposit_event(RawEvent::Minted(asset_id, to, amount)); + + Ok(()) + } else { + Err("The origin does not have permission to mint an asset.") + } + } + + /// Burns an asset, decreases its total issuance. + /// + /// The `origin` must have `burn` permissions. + fn burn(origin, #[compact] asset_id: T::AssetId, to: T::AccountId, amount: T::Balance) -> Result { + let origin = ensure_signed(origin)?; + + if Self::check_permission(&asset_id, &origin, &PermissionType::Burn) { + let original_free_balance = Self::free_balance(&asset_id, &to); + + let current_total_issuance = >::get(asset_id); + let new_total_issuance = current_total_issuance.checked_sub(&amount) + .ok_or_else(|| "total_issuance got underflow after burning")?; + let value = original_free_balance.checked_sub(&amount) + .ok_or_else(|| "free_balance got underflow after burning")?; + + >::insert(asset_id, new_total_issuance); + + Self::set_free_balance(&asset_id, &to, value); + + Self::deposit_event(RawEvent::Burned(asset_id, to, amount)); + + Ok(()) + } else { + Err("The origin does not have permission to burn an asset.") + } + } + + /// Can be used to create reserved tokens. + /// Requires Root call. + fn create_reserved(origin, asset_id: T::AssetId, options: AssetOptions) -> Result { + ensure_root(origin)?; + Self::create_asset(Some(asset_id), None, options) + } + } +} + +#[derive(Encode, Decode, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "std", derive(Debug))] +pub struct BalanceLock { + pub id: LockIdentifier, + pub amount: Balance, + pub until: BlockNumber, + pub reasons: WithdrawReasons, +} + +decl_storage! { + trait Store for Module as GenericAsset { + /// Total issuance of a given asset. + pub TotalIssuance get(total_issuance) build(|config: &GenesisConfig| { + let issuance = config.initial_balance * (config.endowed_accounts.len() as u32).into(); + config.assets.iter().map(|id| (id.clone(), issuance)).collect::>() + }): map T::AssetId => T::Balance; + + /// The free balance of a given asset under an account. + pub FreeBalance: double_map T::AssetId, twox_128(T::AccountId) => T::Balance; + + /// The reserved balance of a given asset under an account. + pub ReservedBalance: double_map T::AssetId, twox_128(T::AccountId) => T::Balance; + + /// Next available ID for user-created asset. + pub NextAssetId get(next_asset_id) config(): T::AssetId; + + /// Permission options for a given asset. + pub Permissions get(get_permission): map T::AssetId => PermissionVersions; + + /// Any liquidity locks on some account balances. + pub Locks get(locks): map T::AccountId => Vec>; + + /// The identity of the asset which is the one that is designated for the chain's staking system. + pub StakingAssetId get(staking_asset_id) config(): T::AssetId; + + /// The identity of the asset which is the one that is designated for paying the chain's transaction fee. + pub SpendingAssetId get(spending_asset_id) config(): T::AssetId; + } + add_extra_genesis { + config(assets): Vec; + config(initial_balance): T::Balance; + config(endowed_accounts): Vec; + + build(| + storage: &mut primitives::StorageOverlay, + _: &mut primitives::ChildrenStorageOverlay, + config: &GenesisConfig| { + config.assets.iter().for_each(|asset_id| { + config.endowed_accounts.iter().for_each(|account_id| { + storage.insert( + >::key_for(asset_id, account_id), + ::encode(&config.initial_balance) + ); + }); + }); + }); + } +} + +decl_event!( + pub enum Event where + ::AccountId, + ::Balance, + ::AssetId, + AssetOptions = AssetOptions<::Balance, ::AccountId> + { + /// Asset created (asset_id, creator, asset_options). + Created(AssetId, AccountId, AssetOptions), + /// Asset transfer succeeded (asset_id, from, to, amount). + Transferred(AssetId, AccountId, AccountId, Balance), + /// Asset permission updated (asset_id, new_permissions). + PermissionUpdated(AssetId, PermissionLatest), + /// New asset minted (asset_id, account, amount). + Minted(AssetId, AccountId, Balance), + /// Asset burned (asset_id, account, amount). + Burned(AssetId, AccountId, Balance), + } +); + +impl Module { + // PUBLIC IMMUTABLES + + /// Get an account's total balance of an asset kind. + pub fn total_balance(asset_id: &T::AssetId, who: &T::AccountId) -> T::Balance { + Self::free_balance(asset_id, who) + Self::reserved_balance(asset_id, who) + } + + /// Get an account's free balance of an asset kind. + pub fn free_balance(asset_id: &T::AssetId, who: &T::AccountId) -> T::Balance { + >::get(asset_id, who) + } + + /// Get an account's reserved balance of an asset kind. + pub fn reserved_balance(asset_id: &T::AssetId, who: &T::AccountId) -> T::Balance { + >::get(asset_id, who) + } + + /// Creates an asset. + /// + /// # Arguments + /// * `asset_id`: An ID of a reserved asset. + /// If not provided, a user-generated asset will be created with the next available ID. + /// * `from_account`: The initiator account of this call + /// * `asset_options`: Asset creation options. + /// + pub fn create_asset( + asset_id: Option, + from_account: Option, + options: AssetOptions, + ) -> Result { + let asset_id = if let Some(asset_id) = asset_id { + ensure!(!>::exists(&asset_id), "Asset id already taken."); + ensure!(asset_id < Self::next_asset_id(), "Asset id not available."); + asset_id + } else { + let asset_id = Self::next_asset_id(); + let next_id = asset_id + .checked_add(&One::one()) + .ok_or_else(|| "No new user asset id available.")?; + >::put(next_id); + asset_id + }; + + let account_id = from_account.unwrap_or_default(); + let permissions: PermissionVersions = options.permissions.clone().into(); + + >::insert(asset_id, &options.initial_issuance); + >::insert(&asset_id, &account_id, options.initial_issuance); + >::insert(&asset_id, permissions); + + Self::deposit_event(RawEvent::Created(asset_id, account_id, options)); + + Ok(()) + } + + /// Transfer some liquid free balance from one account to another. + /// This will not emit the `Transferred` event. + pub fn make_transfer(asset_id: &T::AssetId, from: &T::AccountId, to: &T::AccountId, amount: T::Balance) -> Result { + let new_balance = Self::free_balance(asset_id, from) + .checked_sub(&amount) + .ok_or_else(|| "balance too low to send amount")?; + Self::ensure_can_withdraw(asset_id, from, amount, WithdrawReason::Transfer, new_balance)?; + + if from != to { + >::mutate(asset_id, from, |balance| *balance -= amount); + >::mutate(asset_id, to, |balance| *balance += amount); + } + + Ok(()) + } + + /// Transfer some liquid free balance from one account to another. + /// This will emit the `Transferred` event. + pub fn make_transfer_with_event( + asset_id: &T::AssetId, + from: &T::AccountId, + to: &T::AccountId, + amount: T::Balance, + ) -> Result { + Self::make_transfer(asset_id, from, to, amount)?; + + if from != to { + Self::deposit_event(RawEvent::Transferred(*asset_id, from.clone(), to.clone(), amount)); + } + + Ok(()) + } + + /// Move `amount` from free balance to reserved balance. + /// + /// If the free balance is lower than `amount`, then no funds will be moved and an `Err` will + /// be returned. This is different behavior than `unreserve`. + pub fn reserve(asset_id: &T::AssetId, who: &T::AccountId, amount: T::Balance) -> Result { + // Do we need to consider that this is an atomic transaction? + let original_reserve_balance = Self::reserved_balance(asset_id, who); + let original_free_balance = Self::free_balance(asset_id, who); + if original_free_balance < amount { + return Err("not enough free funds"); + } + let new_reserve_balance = original_reserve_balance + amount; + Self::set_reserved_balance(asset_id, who, new_reserve_balance); + let new_free_balance = original_free_balance - amount; + Self::set_free_balance(asset_id, who, new_free_balance); + Ok(()) + } + + /// Moves up to `amount` from reserved balance to free balance. This function cannot fail. + /// + /// As many assets up to `amount` will be moved as possible. If the reserve balance of `who` + /// is less than `amount`, then the remaining amount will be returned. + /// NOTE: This is different behavior than `reserve`. + pub fn unreserve(asset_id: &T::AssetId, who: &T::AccountId, amount: T::Balance) -> T::Balance { + let b = Self::reserved_balance(asset_id, who); + let actual = rstd::cmp::min(b, amount); + let original_free_balance = Self::free_balance(asset_id, who); + let new_free_balance = original_free_balance + actual; + Self::set_free_balance(asset_id, who, new_free_balance); + Self::set_reserved_balance(asset_id, who, b - actual); + amount - actual + } + + /// Deduct up to `amount` from the combined balance of `who`, preferring to deduct from the + /// free balance. This function cannot fail. + /// + /// As much funds up to `amount` will be deducted as possible. If this is less than `amount` + /// then `Some(remaining)` will be returned. Full completion is given by `None`. + /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that + /// the caller will do this. + fn slash(asset_id: &T::AssetId, who: &T::AccountId, amount: T::Balance) -> Option { + let free_balance = Self::free_balance(asset_id, who); + let free_slash = rstd::cmp::min(free_balance, amount); + let new_free_balance = free_balance - free_slash; + Self::set_free_balance(asset_id, who, new_free_balance); + if free_slash < amount { + Self::slash_reserved(asset_id, who, amount - free_slash) + } else { + None + } + } + + /// Deducts up to `amount` from reserved balance of `who`. This function cannot fail. + /// + /// As much funds up to `amount` will be deducted as possible. If the reserve balance of `who` + /// is less than `amount`, then a non-zero second item will be returned. + /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that + /// the caller will do this. + fn slash_reserved(asset_id: &T::AssetId, who: &T::AccountId, amount: T::Balance) -> Option { + let original_reserve_balance = Self::reserved_balance(asset_id, who); + let slash = rstd::cmp::min(original_reserve_balance, amount); + let new_reserve_balance = original_reserve_balance - slash; + Self::set_reserved_balance(asset_id, who, new_reserve_balance); + if amount == slash { + None + } else { + Some(amount - slash) + } + } + + /// Move up to `amount` from reserved balance of account `who` to free balance of account + /// `beneficiary`. + /// + /// As much funds up to `amount` will be moved as possible. If this is less than `amount`, then + /// the `remaining` would be returned, else `Zero::zero()`. + /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that + /// the caller will do this. + fn repatriate_reserved( + asset_id: &T::AssetId, + who: &T::AccountId, + beneficiary: &T::AccountId, + amount: T::Balance, + ) -> T::Balance { + let b = Self::reserved_balance(asset_id, who); + let slash = rstd::cmp::min(b, amount); + + let original_free_balance = Self::free_balance(asset_id, beneficiary); + let new_free_balance = original_free_balance + slash; + Self::set_free_balance(asset_id, beneficiary, new_free_balance); + + let new_reserve_balance = b - slash; + Self::set_reserved_balance(asset_id, who, new_reserve_balance); + amount - slash + } + + /// Check permission to perform burn, mint or update. + /// + /// # Arguments + /// * `asset_id`: A `T::AssetId` type that contains the `asset_id`, which has the permission embedded. + /// * `who`: A `T::AccountId` type that contains the `account_id` for which to check permissions. + /// * `what`: The permission to check. + /// + pub fn check_permission(asset_id: &T::AssetId, who: &T::AccountId, what: &PermissionType) -> bool { + let permission_versions: PermissionVersions = Self::get_permission(asset_id); + let permission = permission_versions.into(); + + match (what, permission) { + ( + PermissionType::Burn, + PermissionLatest { + burn: Owner::Address(account), + .. + }, + ) => account == *who, + ( + PermissionType::Mint, + PermissionLatest { + mint: Owner::Address(account), + .. + }, + ) => account == *who, + ( + PermissionType::Update, + PermissionLatest { + update: Owner::Address(account), + .. + }, + ) => account == *who, + _ => false, + } + } + + /// Return `Ok` iff the account is able to make a withdrawal of the given amount + /// for the given reason. + /// + /// `Err(...)` with the reason why not otherwise. + pub fn ensure_can_withdraw( + asset_id: &T::AssetId, + who: &T::AccountId, + _amount: T::Balance, + reason: WithdrawReason, + new_balance: T::Balance, + ) -> Result { + if asset_id != &Self::staking_asset_id() { + return Ok(()); + } + + let locks = Self::locks(who); + if locks.is_empty() { + return Ok(()); + } + let now = >::block_number(); + if Self::locks(who) + .into_iter() + .all(|l| now >= l.until || new_balance >= l.amount || !l.reasons.contains(reason)) + { + Ok(()) + } else { + Err("account liquidity restrictions prevent withdrawal") + } + } + + // PRIVATE MUTABLES + + /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that + /// the caller will do this. + fn set_reserved_balance(asset_id: &T::AssetId, who: &T::AccountId, balance: T::Balance) { + >::insert(asset_id, who, balance); + } + + /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that + /// the caller will do this. + fn set_free_balance(asset_id: &T::AssetId, who: &T::AccountId, balance: T::Balance) { + >::insert(asset_id, who, balance); + } + + fn set_lock( + id: LockIdentifier, + who: &T::AccountId, + amount: T::Balance, + until: T::BlockNumber, + reasons: WithdrawReasons, + ) { + let now = >::block_number(); + let mut new_lock = Some(BalanceLock { + id, + amount, + until, + reasons, + }); + let mut locks = >::locks(who) + .into_iter() + .filter_map(|l| { + if l.id == id { + new_lock.take() + } else if l.until > now { + Some(l) + } else { + None + } + }) + .collect::>(); + if let Some(lock) = new_lock { + locks.push(lock) + } + >::insert(who, locks); + } + + fn extend_lock( + id: LockIdentifier, + who: &T::AccountId, + amount: T::Balance, + until: T::BlockNumber, + reasons: WithdrawReasons, + ) { + let now = >::block_number(); + let mut new_lock = Some(BalanceLock { + id, + amount, + until, + reasons, + }); + let mut locks = >::locks(who) + .into_iter() + .filter_map(|l| { + if l.id == id { + new_lock.take().map(|nl| BalanceLock { + id: l.id, + amount: l.amount.max(nl.amount), + until: l.until.max(nl.until), + reasons: l.reasons | nl.reasons, + }) + } else if l.until > now { + Some(l) + } else { + None + } + }) + .collect::>(); + if let Some(lock) = new_lock { + locks.push(lock) + } + >::insert(who, locks); + } + + fn remove_lock(id: LockIdentifier, who: &T::AccountId) { + let now = >::block_number(); + let locks = >::locks(who) + .into_iter() + .filter_map(|l| if l.until > now && l.id != id { Some(l) } else { None }) + .collect::>(); + >::insert(who, locks); + } +} + +pub trait AssetIdProvider { + type AssetId; + fn asset_id() -> Self::AssetId; +} + +// wrapping these imbalanes in a private module is necessary to ensure absolute privacy +// of the inner member. +mod imbalances { + use super::{result, AssetIdProvider, Imbalance, Saturating, StorageMap, Subtrait, Zero}; + use rstd::mem; + + /// Opaque, move-only struct with private fields that serves as a token denoting that + /// funds have been created without any equal and opposite accounting. + #[must_use] + pub struct PositiveImbalance>( + T::Balance, + rstd::marker::PhantomData, + ); + impl PositiveImbalance + where + T: Subtrait, + U: AssetIdProvider, + { + pub fn new(amount: T::Balance) -> Self { + PositiveImbalance(amount, Default::default()) + } + } + + /// Opaque, move-only struct with private fields that serves as a token denoting that + /// funds have been destroyed without any equal and opposite accounting. + #[must_use] + pub struct NegativeImbalance>( + T::Balance, + rstd::marker::PhantomData, + ); + impl NegativeImbalance + where + T: Subtrait, + U: AssetIdProvider, + { + pub fn new(amount: T::Balance) -> Self { + NegativeImbalance(amount, Default::default()) + } + } + + impl Imbalance for PositiveImbalance + where + T: Subtrait, + U: AssetIdProvider, + { + type Opposite = NegativeImbalance; + + fn zero() -> Self { + Self::new(Zero::zero()) + } + fn drop_zero(self) -> result::Result<(), Self> { + if self.0.is_zero() { + Ok(()) + } else { + Err(self) + } + } + fn split(self, amount: T::Balance) -> (Self, Self) { + let first = self.0.min(amount); + let second = self.0 - first; + + mem::forget(self); + (Self::new(first), Self::new(second)) + } + fn merge(mut self, other: Self) -> Self { + self.0 = self.0.saturating_add(other.0); + mem::forget(other); + + self + } + fn subsume(&mut self, other: Self) { + self.0 = self.0.saturating_add(other.0); + mem::forget(other); + } + fn offset(self, other: Self::Opposite) -> result::Result { + let (a, b) = (self.0, other.0); + mem::forget((self, other)); + + if a >= b { + Ok(Self::new(a - b)) + } else { + Err(NegativeImbalance::new(b - a)) + } + } + fn peek(&self) -> T::Balance { + self.0.clone() + } + } + + impl Imbalance for NegativeImbalance + where + T: Subtrait, + U: AssetIdProvider, + { + type Opposite = PositiveImbalance; + + fn zero() -> Self { + Self::new(Zero::zero()) + } + fn drop_zero(self) -> result::Result<(), Self> { + if self.0.is_zero() { + Ok(()) + } else { + Err(self) + } + } + fn split(self, amount: T::Balance) -> (Self, Self) { + let first = self.0.min(amount); + let second = self.0 - first; + + mem::forget(self); + (Self::new(first), Self::new(second)) + } + fn merge(mut self, other: Self) -> Self { + self.0 = self.0.saturating_add(other.0); + mem::forget(other); + + self + } + fn subsume(&mut self, other: Self) { + self.0 = self.0.saturating_add(other.0); + mem::forget(other); + } + fn offset(self, other: Self::Opposite) -> result::Result { + let (a, b) = (self.0, other.0); + mem::forget((self, other)); + + if a >= b { + Ok(Self::new(a - b)) + } else { + Err(PositiveImbalance::new(b - a)) + } + } + fn peek(&self) -> T::Balance { + self.0.clone() + } + } + + impl Drop for PositiveImbalance + where + T: Subtrait, + U: AssetIdProvider, + { + /// Basic drop handler will just square up the total issuance. + fn drop(&mut self) { + >>::mutate(&U::asset_id(), |v| *v = v.saturating_add(self.0)); + } + } + + impl Drop for NegativeImbalance + where + T: Subtrait, + U: AssetIdProvider, + { + /// Basic drop handler will just square up the total issuance. + fn drop(&mut self) { + >>::mutate(&U::asset_id(), |v| *v = v.saturating_sub(self.0)); + } + } +} + +// TODO: #2052 +// Somewhat ugly hack in order to gain access to module's `increase_total_issuance_by` +// using only the Subtrait (which defines only the types that are not dependent +// on Positive/NegativeImbalance). Subtrait must be used otherwise we end up with a +// circular dependency with Trait having some types be dependent on PositiveImbalance +// and PositiveImbalance itself depending back on Trait for its Drop impl (and thus +// its type declaration). +// This works as long as `increase_total_issuance_by` doesn't use the Imbalance +// types (basically for charging fees). +// This should eventually be refactored so that the three type items that do +// depend on the Imbalance type (TransactionPayment, TransferPayment, DustRemoval) +// are placed in their own SRML module. +struct ElevatedTrait(T); +impl Clone for ElevatedTrait { + fn clone(&self) -> Self { + unimplemented!() + } +} +impl PartialEq for ElevatedTrait { + fn eq(&self, _: &Self) -> bool { + unimplemented!() + } +} +impl Eq for ElevatedTrait {} +impl system::Trait for ElevatedTrait { + type Origin = T::Origin; + type Index = T::Index; + type BlockNumber = T::BlockNumber; + type Hash = T::Hash; + type Hashing = T::Hashing; + type AccountId = T::AccountId; + type Lookup = T::Lookup; + type Header = T::Header; + type Event = (); + type BlockHashCount = T::BlockHashCount; +} +impl Trait for ElevatedTrait { + type Balance = T::Balance; + type AssetId = T::AssetId; + type Event = (); +} + +#[derive(Encode, Decode, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "std", derive(Debug))] +pub struct AssetCurrency(rstd::marker::PhantomData, rstd::marker::PhantomData); + +impl Currency for AssetCurrency +where + T: Trait, + U: AssetIdProvider, +{ + type Balance = T::Balance; + type PositiveImbalance = PositiveImbalance; + type NegativeImbalance = NegativeImbalance; + + fn total_balance(who: &T::AccountId) -> Self::Balance { + Self::free_balance(&who) + Self::reserved_balance(&who) + } + + fn free_balance(who: &T::AccountId) -> Self::Balance { + >::free_balance(&U::asset_id(), &who) + } + + /// Returns the total staking asset issuance + fn total_issuance() -> Self::Balance { + >::total_issuance(U::asset_id()) + } + + fn minimum_balance() -> Self::Balance { + Zero::zero() + } + + fn transfer(transactor: &T::AccountId, dest: &T::AccountId, value: Self::Balance) -> Result { + >::make_transfer(&U::asset_id(), transactor, dest, value) + } + + fn ensure_can_withdraw( + who: &T::AccountId, + amount: Self::Balance, + reason: WithdrawReason, + new_balance: Self::Balance, + ) -> Result { + >::ensure_can_withdraw(&U::asset_id(), who, amount, reason, new_balance) + } + + fn withdraw( + who: &T::AccountId, + value: Self::Balance, + reason: WithdrawReason, + _: ExistenceRequirement, // no existential deposit policy for generic asset + ) -> result::Result { + let new_balance = Self::free_balance(who) + .checked_sub(&value) + .ok_or_else(|| "account has too few funds")?; + Self::ensure_can_withdraw(who, value, reason, new_balance)?; + >::set_free_balance(&U::asset_id(), who, new_balance); + Ok(NegativeImbalance::new(value)) + } + + fn deposit_into_existing( + who: &T::AccountId, + value: Self::Balance, + ) -> result::Result { + // No existential deposit rule and creation fee in GA. `deposit_into_existing` is same with `deposit_creating`. + Ok(Self::deposit_creating(who, value)) + } + + fn deposit_creating(who: &T::AccountId, value: Self::Balance) -> Self::PositiveImbalance { + let (imbalance, _) = Self::make_free_balance_be(who, Self::free_balance(who) + value); + if let SignedImbalance::Positive(p) = imbalance { + p + } else { + // Impossible, but be defensive. + Self::PositiveImbalance::zero() + } + } + + fn make_free_balance_be( + who: &T::AccountId, + balance: Self::Balance, + ) -> ( + SignedImbalance, + UpdateBalanceOutcome, + ) { + let original = >::free_balance(&U::asset_id(), who); + let imbalance = if original <= balance { + SignedImbalance::Positive(PositiveImbalance::new(balance - original)) + } else { + SignedImbalance::Negative(NegativeImbalance::new(original - balance)) + }; + >::set_free_balance(&U::asset_id(), who, balance); + (imbalance, UpdateBalanceOutcome::Updated) + } + + fn can_slash(who: &T::AccountId, value: Self::Balance) -> bool { + >::free_balance(&U::asset_id(), &who) >= value + } + + fn slash(who: &T::AccountId, value: Self::Balance) -> (Self::NegativeImbalance, Self::Balance) { + let remaining = >::slash(&U::asset_id(), who, value); + if let Some(r) = remaining { + (NegativeImbalance::new(value - r), r) + } else { + (NegativeImbalance::new(value), Zero::zero()) + } + } + + fn burn(mut amount: Self::Balance) -> Self::PositiveImbalance { + >::mutate(&U::asset_id(), |issued| + issued.checked_sub(&amount).unwrap_or_else(|| { + amount = *issued; + Zero::zero() + }) + ); + PositiveImbalance::new(amount) + } + + fn issue(mut amount: Self::Balance) -> Self::NegativeImbalance { + >::mutate(&U::asset_id(), |issued| + *issued = issued.checked_add(&amount).unwrap_or_else(|| { + amount = Self::Balance::max_value() - *issued; + Self::Balance::max_value() + }) + ); + NegativeImbalance::new(amount) + } +} + +impl ReservableCurrency for AssetCurrency +where + T: Trait, + U: AssetIdProvider, +{ + fn can_reserve(who: &T::AccountId, value: Self::Balance) -> bool { + Self::free_balance(who) + .checked_sub(&value) + .map_or(false, |new_balance| + >::ensure_can_withdraw(&U::asset_id(), who, value, WithdrawReason::Reserve, new_balance).is_ok() + ) + } + + fn reserved_balance(who: &T::AccountId) -> Self::Balance { + >::reserved_balance(&U::asset_id(), &who) + } + + fn reserve(who: &T::AccountId, value: Self::Balance) -> result::Result<(), &'static str> { + >::reserve(&U::asset_id(), who, value) + } + + fn unreserve(who: &T::AccountId, value: Self::Balance) -> Self::Balance { + >::unreserve(&U::asset_id(), who, value) + } + + fn slash_reserved(who: &T::AccountId, value: Self::Balance) -> (Self::NegativeImbalance, Self::Balance) { + let b = Self::reserved_balance(&who.clone()); + let slash = cmp::min(b, value); + + >::set_reserved_balance(&U::asset_id(), who, b - slash); + (NegativeImbalance::new(slash), value - slash) + } + + fn repatriate_reserved( + slashed: &T::AccountId, + beneficiary: &T::AccountId, + value: Self::Balance, + ) -> result::Result { + Ok(>::repatriate_reserved(&U::asset_id(), slashed, beneficiary, value)) + } +} + +pub struct StakingAssetIdProvider(rstd::marker::PhantomData); + +impl AssetIdProvider for StakingAssetIdProvider { + type AssetId = T::AssetId; + fn asset_id() -> Self::AssetId { + >::staking_asset_id() + } +} + +pub struct SpendingAssetIdProvider(rstd::marker::PhantomData); + +impl AssetIdProvider for SpendingAssetIdProvider { + type AssetId = T::AssetId; + fn asset_id() -> Self::AssetId { + >::spending_asset_id() + } +} + +impl LockableCurrency for AssetCurrency> +where + T: Trait, + T::Balance: MaybeSerializeDebug, +{ + type Moment = T::BlockNumber; + + fn set_lock( + id: LockIdentifier, + who: &T::AccountId, + amount: T::Balance, + until: T::BlockNumber, + reasons: WithdrawReasons, + ) { + >::set_lock(id, who, amount, until, reasons) + } + + fn extend_lock( + id: LockIdentifier, + who: &T::AccountId, + amount: T::Balance, + until: T::BlockNumber, + reasons: WithdrawReasons, + ) { + >::extend_lock(id, who, amount, until, reasons) + } + + fn remove_lock(id: LockIdentifier, who: &T::AccountId) { + >::remove_lock(id, who) + } +} + +pub type StakingAssetCurrency = AssetCurrency>; +pub type SpendingAssetCurrency = AssetCurrency>; diff --git a/srml/generic-asset/src/mock.rs b/srml/generic-asset/src/mock.rs new file mode 100644 index 0000000000000000000000000000000000000000..02e18fc335839638527b452d0cb131ab0b74d098 --- /dev/null +++ b/srml/generic-asset/src/mock.rs @@ -0,0 +1,140 @@ +// Copyright 2019 +// by Centrality Investments Ltd. +// and Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +//! Mocks for the module. + +#![cfg(test)] + +use primitives::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, +}; +use substrate_primitives::{Blake2Hasher, H256}; +use support::{parameter_types, impl_outer_event, impl_outer_origin}; + +use super::*; + +impl_outer_origin! { + pub enum Origin for Test {} +} + +// For testing the module, we construct most of a mock runtime. This means +// first constructing a configuration type (`Test`) which `impl`s each of the +// configuration traits of modules we want to use. +#[derive(Clone, Eq, PartialEq)] +pub struct Test; +parameter_types! { + pub const BlockHashCount: u64 = 250; +} +impl system::Trait for Test { + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = TestEvent; + type BlockHashCount = BlockHashCount; +} + +impl Trait for Test { + type Balance = u64; + type AssetId = u32; + type Event = TestEvent; +} + +mod generic_asset { + pub use crate::Event; +} + +impl_outer_event! { + pub enum TestEvent for Test { + generic_asset, + } +} + +pub type GenericAsset = Module; + +pub type System = system::Module; + +pub struct ExtBuilder { + asset_id: u32, + next_asset_id: u32, + accounts: Vec, + initial_balance: u64, +} + +// Returns default values for genesis config +impl Default for ExtBuilder { + fn default() -> Self { + Self { + asset_id: 0, + next_asset_id: 1000, + accounts: vec![0], + initial_balance: 0, + } + } +} + +impl ExtBuilder { + // Sets free balance to genesis config + pub fn free_balance(mut self, free_balance: (u32, u64, u64)) -> Self { + self.asset_id = free_balance.0; + self.accounts = vec![free_balance.1]; + self.initial_balance = free_balance.2; + self + } + + pub fn next_asset_id(mut self, asset_id: u32) -> Self { + self.next_asset_id = asset_id; + self + } + + // builds genesis config + pub fn build(self) -> runtime_io::TestExternalities { + let mut t = system::GenesisConfig::default().build_storage::().unwrap().0; + + t.extend( + GenesisConfig:: { + assets: vec![self.asset_id], + endowed_accounts: self.accounts, + initial_balance: self.initial_balance, + next_asset_id: self.next_asset_id, + staking_asset_id: 16000, + spending_asset_id: 16001, + } + .build_storage() + .unwrap() + .0, + ); + + t.into() + } +} + +// This function basically just builds a genesis storage key/value store according to +// our desired mockup. +pub fn new_test_ext() -> runtime_io::TestExternalities { + system::GenesisConfig::default() + .build_storage::() + .unwrap() + .0 + .into() +} diff --git a/srml/generic-asset/src/tests.rs b/srml/generic-asset/src/tests.rs new file mode 100644 index 0000000000000000000000000000000000000000..685e553c1c14d03687a3595ece8032746f273fea --- /dev/null +++ b/srml/generic-asset/src/tests.rs @@ -0,0 +1,1288 @@ +// Copyright 2019 +// by Centrality Investments Ltd. +// and Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +//! Tests for the module. + +#![cfg(test)] + +use super::*; +use crate::mock::{new_test_ext, ExtBuilder, GenericAsset, Origin, System, Test, TestEvent}; +use runtime_io::with_externalities; +use support::{assert_noop, assert_ok}; + +#[test] +fn issuing_asset_units_to_issuer_should_work() { + let balance = 100; + + with_externalities(&mut ExtBuilder::default().free_balance((16000, 1, 100)).build(), || { + let default_permission = PermissionLatest { + update: Owner::Address(1), + mint: Owner::Address(1), + burn: Owner::Address(1), + }; + + let expected_balance = balance; + + assert_ok!(GenericAsset::create( + Origin::signed(1), + AssetOptions { + initial_issuance: balance, + permissions: default_permission + } + )); + assert_eq!(GenericAsset::free_balance(&16000, &1), expected_balance); + }); +} + +#[test] +fn issuing_with_next_asset_id_overflow_should_not_work() { + with_externalities( + &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), + || { + NextAssetId::::put(u32::max_value()); + let default_permission = PermissionLatest { + update: Owner::Address(1), + mint: Owner::Address(1), + burn: Owner::Address(1), + }; + assert_noop!( + GenericAsset::create( + Origin::signed(1), + AssetOptions { + initial_issuance: 1, + permissions: default_permission + } + ), + "No new assets id available." + ); + assert_eq!(GenericAsset::next_asset_id(), u32::max_value()); + }, + ); +} + +#[test] +fn querying_total_supply_should_work() { + let asset_id = 1000; + + with_externalities( + &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), + || { + let default_permission = PermissionLatest { + update: Owner::Address(1), + mint: Owner::Address(1), + burn: Owner::Address(1), + }; + assert_ok!(GenericAsset::create( + Origin::signed(1), + AssetOptions { + initial_issuance: 100, + permissions: default_permission + } + )); + assert_eq!(GenericAsset::free_balance(&asset_id, &1), 100); + assert_ok!(GenericAsset::transfer(Origin::signed(1), asset_id, 2, 50)); + assert_eq!(GenericAsset::free_balance(&asset_id, &1), 50); + assert_eq!(GenericAsset::free_balance(&asset_id, &2), 50); + assert_ok!(GenericAsset::transfer(Origin::signed(2), asset_id, 3, 31)); + assert_eq!(GenericAsset::free_balance(&asset_id, &1), 50); + assert_eq!(GenericAsset::free_balance(&asset_id, &2), 19); + assert_eq!(GenericAsset::free_balance(&asset_id, &3), 31); + assert_ok!(GenericAsset::transfer(Origin::signed(1), asset_id, 1, 1)); + assert_eq!(GenericAsset::free_balance(&asset_id, &1), 50); + }, + ); +} + +// Given +// - The next asset id as `asset_id` = 1000. +// - AssetOptions with all permissions. +// - GenesisStore has sufficient free balance. +// +// When +// - Create an asset from `origin` as 1. +// Then +// - free_balance of next asset id = 100. +// +// When +// - After transferring 40 from account 1 to account 2. +// Then +// - Origin account's `free_balance` = 60. +// - account 2's `free_balance` = 40. +#[test] +fn transferring_amount_should_work() { + let asset_id = 1000; + let free_balance = 100; + with_externalities( + &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), + || { + let default_permission = PermissionLatest { + update: Owner::Address(1), + mint: Owner::Address(1), + burn: Owner::Address(1), + }; + assert_ok!(GenericAsset::create( + Origin::signed(1), + AssetOptions { + initial_issuance: free_balance, + permissions: default_permission + } + )); + assert_eq!(GenericAsset::free_balance(&asset_id, &1), free_balance); + assert_ok!(GenericAsset::transfer(Origin::signed(1), asset_id, 2, 40)); + assert_eq!(GenericAsset::free_balance(&asset_id, &1), 60); + assert_eq!(GenericAsset::free_balance(&asset_id, &2), 40); + }, + ); +} + +// Given +// - The next asset id as `asset_id` = 1000. +// - AssetOptions with all permissions. +// - GenesisStore has sufficient free balance. +// +// When +// - Create an asset from `origin` as 1. +// Then +// - free_balance of next asset id = 100. +// +// When +// - After transferring 40 from account 1 to account 2. +// Then +// - Origin account's `free_balance` = 60. +// - account 2's `free_balance` = 40. +#[test] +fn transferring_amount_should_fail_when_transferring_more_than_free_balance() { + let asset_id = 1000; + with_externalities( + &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), + || { + let default_permission = PermissionLatest { + update: Owner::Address(1), + mint: Owner::Address(1), + burn: Owner::Address(1), + }; + assert_ok!(GenericAsset::create( + Origin::signed(1), + AssetOptions { + initial_issuance: 100, + permissions: default_permission + } + )); + assert_noop!( + GenericAsset::transfer(Origin::signed(1), asset_id, 2, 2000), + "balance too low to send amount" + ); + }, + ); +} + +#[test] +fn transferring_less_than_one_unit_should_not_work() { + let asset_id = 1000; + + with_externalities( + &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), + || { + let default_permission = PermissionLatest { + update: Owner::Address(1), + mint: Owner::Address(1), + burn: Owner::Address(1), + }; + assert_ok!(GenericAsset::create( + Origin::signed(1), + AssetOptions { + initial_issuance: 100, + permissions: default_permission + } + )); + assert_eq!(GenericAsset::free_balance(&asset_id, &1), 100); + assert_noop!( + GenericAsset::transfer(Origin::signed(1), asset_id, 2, 0), + "cannot transfer zero amount" + ); + }, + ); +} + +// Given +// - Next asset id as `asset_id` = 1000. +// - Sufficient free balance. +// - initial balance = 100. +// When +// - After performing a self transfer from account 1 to 1. +// Then +// - Should not throw any errors. +// - Free balance after self transfer should equal to the free balance before self transfer. +#[test] +fn self_transfer_should_fail() { + let asset_id = 1000; + let balance = 100; + + with_externalities( + &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), + || { + let default_permission = PermissionLatest { + update: Owner::Address(1), + mint: Owner::Address(1), + burn: Owner::Address(1), + }; + assert_ok!(GenericAsset::create( + Origin::signed(1), + AssetOptions { + initial_issuance: balance, + permissions: default_permission + } + )); + + let initial_free_balance = GenericAsset::free_balance(&asset_id, &1); + assert_ok!(GenericAsset::transfer(Origin::signed(1), asset_id, 1, 10)); + assert_eq!(GenericAsset::free_balance(&asset_id, &1), initial_free_balance); + }, + ); +} + +#[test] +fn transferring_more_units_than_total_supply_should_not_work() { + let asset_id = 1000; + with_externalities( + &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), + || { + let default_permission = PermissionLatest { + update: Owner::Address(1), + mint: Owner::Address(1), + burn: Owner::Address(1), + }; + assert_ok!(GenericAsset::create( + Origin::signed(1), + AssetOptions { + initial_issuance: 100, + permissions: default_permission + } + )); + assert_eq!(GenericAsset::free_balance(&asset_id, &1), 100); + assert_noop!( + GenericAsset::transfer(Origin::signed(1), asset_id, 2, 101), + "balance too low to send amount" + ); + }, + ); +} + +// Ensures it uses fake money for staking asset id. +#[test] +fn staking_asset_id_should_return_0() { + with_externalities(&mut ExtBuilder::default().build(), || { + assert_eq!(GenericAsset::staking_asset_id(), 16000); + }); +} + +// Ensures it uses fake money for spending asset id. +#[test] +fn spending_asset_id_should_return_10() { + with_externalities(&mut ExtBuilder::default().build(), || { + assert_eq!(GenericAsset::spending_asset_id(), 16001); + }); +} + +// Given +// -Â Free balance is 0 and the reserved balance is 0. +// Then +// -Â total_balance should return 0 +#[test] +fn total_balance_should_be_zero() { + with_externalities(&mut new_test_ext(), || { + assert_eq!(GenericAsset::total_balance(&0, &0), 0); + }); +} + +// Given +// -Â Free balance is 0 and the reserved balance > 0. +// When +// - After calling total_balance. +// Then +// -Â total_balance should equals to reserved balance. +#[test] +fn total_balance_should_be_equal_to_account_balance() { + let default_permission = PermissionLatest { + update: Owner::Address(1), + mint: Owner::Address(1), + burn: Owner::Address(1), + }; + with_externalities( + &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), + || { + assert_ok!(GenericAsset::create( + Origin::signed(1), + AssetOptions { + initial_issuance: 100, + permissions: default_permission + } + )); + assert_eq!(GenericAsset::total_balance(&1000, &1), 100); + }, + ); +} + +// Given +// - An account presents with AccountId = 1 +// -Â free_balance > 0. +// - reserved_balance = 50. +// When +// - After calling free_balance. +// Then +// -Â free_balance should return 50. +#[test] +fn free_balance_should_only_return_account_free_balance() { + with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 50)).build(), || { + GenericAsset::set_reserved_balance(&1, &0, 70); + assert_eq!(GenericAsset::free_balance(&1, &0), 50); + }); +} + +// Given +// - An account presents with AccountId = 1. +// -Â Free balance > 0 and the reserved balance > 0. +// When +// - After calling total_balance. +// Then +// -Â total_balance should equals to account balance + free balance. +#[test] +fn total_balance_should_be_equal_to_sum_of_account_balance_and_free_balance() { + with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 50)).build(), || { + GenericAsset::set_reserved_balance(&1, &0, 70); + assert_eq!(GenericAsset::total_balance(&1, &0), 120); + }); +} + +// Given +// -Â free_balance > 0. +// - reserved_balance = 70. +// When +// - After calling reserved_balance. +// Then +// - reserved_balance should return 70. +#[test] +fn reserved_balance_should_only_return_account_reserved_balance() { + with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 50)).build(), || { + GenericAsset::set_reserved_balance(&1, &0, 70); + assert_eq!(GenericAsset::reserved_balance(&1, &0), 70); + }); +} + +// Given +// - A valid account presents. +// - Initial reserved_balance = 0 +// When +// - After calls set_reserved_balance +// Then +// - Should persists the amount as reserved_balance. +// - reserved_balance = amount +#[test] +fn set_reserved_balance_should_add_balance_as_reserved() { + with_externalities(&mut ExtBuilder::default().build(), || { + GenericAsset::set_reserved_balance(&1, &0, 50); + assert_eq!(GenericAsset::reserved_balance(&1, &0), 50); + }); +} + +// Given +// - A valid account presents. +// - Initial free_balance = 100. +// When +// - After calling set_free_balance. +// Then +// - Should persists the amount as free_balance. +// - New free_balance should replace older free_balance. +#[test] +fn set_free_balance_should_add_amount_as_free_balance() { + with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + GenericAsset::set_free_balance(&1, &0, 50); + assert_eq!(GenericAsset::free_balance(&1, &0), 50); + }); +} + +// Given +// - free_balance is greater than the account balance. +// - free_balance = 100 +// - reserved_balance = 0 +// - reserve amount = 70 +// When +// - After calling reserve +// Then +// - Funds should be removed from the account. +// - new free_balance = original free_balance - reserved amount +// - new reserved_balance = original free balance + reserved amount +#[test] +fn reserve_should_moves_amount_from_balance_to_reserved_balance() { + with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + assert_ok!(GenericAsset::reserve(&1, &0, 70)); + assert_eq!(GenericAsset::free_balance(&1, &0), 30); + assert_eq!(GenericAsset::reserved_balance(&1, &0), 70); + }); +} + +// Given +// - Free balance is lower than the account balance. +// - free_balance = 100 +// - reserved_balance = 0 +// - reserve amount = 120 +// When +// - After calling reverse function. +// Then +// - Funds should not be removed from the account. +// - Should throw an error. +#[test] +fn reserve_should_not_moves_amount_from_balance_to_reserved_balance() { + with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + assert_noop!(GenericAsset::reserve(&1, &0, 120), "not enough free funds"); + assert_eq!(GenericAsset::free_balance(&1, &0), 100); + assert_eq!(GenericAsset::reserved_balance(&1, &0), 0); + }); +} + +// Given +// - unreserved_amount > reserved_balance. +// - reserved_balance = 100. +// - free_balance = 100. +// - unreserved_amount = 120. +// When +// - After calling unreserve function. +// Then +// - unreserved should return 20. +#[test] +fn unreserve_should_return_substratced_value_from_unreserved_amount_by_actual_acount_balance() { + with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + GenericAsset::set_reserved_balance(&1, &0, 100); + assert_eq!(GenericAsset::unreserve(&1, &0, 120), 20); + }); +} + +// Given +// - unreserved_amount < reserved_balance. +// - reserved_balance = 100. +// - free_balance = 100. +// - unreserved_amount = 50. +// When +// - After calling unreserve function. +// Then +// - unreserved should return None. +#[test] +fn unreserve_should_return_none() { + with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + GenericAsset::set_reserved_balance(&1, &0, 100); + assert_eq!(GenericAsset::unreserve(&1, &0, 50), 0); + }); +} + +// Given +// - unreserved_amount > reserved_balance. +// - reserved_balance = 100. +// - free_balance = 100. +// - unreserved_amount = 120. +// When +// - After calling unreserve function. +// Then +// - free_balance should be 200. +#[test] +fn unreserve_should_increase_free_balance_by_reserved_balance() { + with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + GenericAsset::set_reserved_balance(&1, &0, 100); + GenericAsset::unreserve(&1, &0, 120); + assert_eq!(GenericAsset::free_balance(&1, &0), 200); + }); +} + +// Given +// - unreserved_amount > reserved_balance. +// - reserved_balance = 100. +// - free_balance = 100. +// - unreserved_amount = 120. +// When +// - After calling unreserve function. +// Then +// - reserved_balance should be 0. +#[test] +fn unreserve_should_deduct_reserved_balance_by_reserved_amount() { + with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + GenericAsset::set_free_balance(&1, &0, 100); + GenericAsset::unreserve(&1, &0, 120); + assert_eq!(GenericAsset::reserved_balance(&1, &0), 0); + }); +} + +// Given +// - slash amount < free_balance. +// - reserved_balance = 100. +// - free_balance = 100. +// - slash amount = 70. +// When +// - After calling slash function. +// Then +// - slash should return None. +#[test] +fn slash_should_return_slash_reserved_amount() { + with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + GenericAsset::set_reserved_balance(&1, &0, 100); + assert_eq!(GenericAsset::slash(&1, &0, 70), None); + }); +} + +// Given +// - slashed_amount > reserved_balance. +// When +// - After calling slashed_reverse function. +// Then +// - Should return slashed_reserved - reserved_balance. +#[test] +fn slash_reserved_should_deducts_up_to_amount_from_reserved_balance() { + with_externalities(&mut ExtBuilder::default().build(), || { + GenericAsset::set_reserved_balance(&1, &0, 100); + assert_eq!(GenericAsset::slash_reserved(&1, &0, 150), Some(50)); + }); +} + +// Given +// - slashed_amount equals to reserved_amount. +// When +// - After calling slashed_reverse function. +// Then +// - Should return None. +#[test] +fn slash_reserved_should_return_none() { + with_externalities(&mut ExtBuilder::default().build(), || { + GenericAsset::set_reserved_balance(&1, &0, 100); + assert_eq!(GenericAsset::slash_reserved(&1, &0, 100), None); + }); +} + +// Given +// - reserved_balance = 100. +// - repatriate_reserved_amount > reserved_balance. +// When +// - After calling repatriate_reserved. +// Then +// - Should not return None. +#[test] +fn repatriate_reserved_return_amount_substracted_by_slash_amount() { + with_externalities(&mut ExtBuilder::default().build(), || { + GenericAsset::set_reserved_balance(&1, &0, 100); + assert_eq!(GenericAsset::repatriate_reserved(&1, &0, &1, 130), 30); + }); +} + +// Given +// - reserved_balance = 100. +// - repatriate_reserved_amount > reserved_balance. +// When +// - After calling repatriate_reserved. +// Then +// - Should return None. +#[test] +fn repatriate_reserved_return_none() { + with_externalities(&mut ExtBuilder::default().build(), || { + GenericAsset::set_reserved_balance(&1, &0, 100); + assert_eq!(GenericAsset::repatriate_reserved(&1, &0, &1, 90), 0); + }); +} + +// Given +// - An asset with all permissions +// When +// - After calling `create_reserved` function. +// Then +// - Should create a new reserved asset. +#[test] +fn create_reserved_should_create_a_default_account_with_the_balance_given() { + with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { + let default_permission = PermissionLatest { + update: Owner::Address(1), + mint: Owner::Address(1), + burn: Owner::Address(1), + }; + let options = AssetOptions { + initial_issuance: 500, + permissions: default_permission, + }; + + let expected_total_issuance = 500; + let created_asset_id = 9; + let created_account_id = 0; + + assert_ok!(GenericAsset::create_reserved(Origin::ROOT, created_asset_id, options)); + + // Tests for side effects. + assert_eq!(>::get(created_asset_id), expected_total_issuance); + assert_eq!( + >::get(&created_asset_id, &created_account_id), + expected_total_issuance + ); + }); +} + +// Given +// - Origin is signed +// - Origin does not have minting permission +// When +// - After calling mint function +// Then +// - Should throw a permission error +#[test] +fn mint_should_throw_permission_error() { + with_externalities(&mut ExtBuilder::default().build(), || { + let origin = 1; + let asset_id = 4; + let to_account = 2; + let amount = 100; + + assert_noop!( + GenericAsset::mint(Origin::signed(origin), asset_id, to_account, amount), + "The origin does not have permission to mint an asset." + ); + }); +} + +// Given +// - Origin is signed. +// - Origin has permissions. +// When +// - After calling mint function +// Then +// - Should increase `to` free_balance. +// - Should not change `origins` free_balance. +#[test] +fn mint_should_increase_asset() { + with_externalities( + &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), + || { + let origin = 1; + let asset_id = 1000; + let to_account = 2; + let amount = 500; + let initial_issuance = 100; + + let default_permission = PermissionLatest { + update: Owner::Address(origin), + mint: Owner::Address(origin), + burn: Owner::Address(origin), + }; + + assert_ok!(GenericAsset::create( + Origin::signed(origin), + AssetOptions { + initial_issuance: initial_issuance, + permissions: default_permission + } + )); + + assert_ok!(GenericAsset::mint(Origin::signed(origin), asset_id, to_account, amount)); + assert_eq!(GenericAsset::free_balance(&asset_id, &to_account), amount); + + // Origin's free_balance should not change. + assert_eq!(GenericAsset::free_balance(&asset_id, &origin), initial_issuance); + }, + ); +} + +// Given +// - Origin is signed. +// - Origin does not have burning permission. +// When +// - After calling burn function. +// Then +// - Should throw a permission error. +#[test] +fn burn_should_throw_permission_error() { + with_externalities( + &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), + || { + let origin = 1; + let asset_id = 4; + let to_account = 2; + let amount = 10; + + assert_noop!( + GenericAsset::burn(Origin::signed(origin), asset_id, to_account, amount), + "The origin does not have permission to burn an asset." + ); + }, + ); +} + +// Given +// - Origin is signed. +// - Origin has permissions. +// When +// - After calling burn function +// Then +// - Should decrease `to`'s free_balance. +// - Should not change `origin`'s free_balance. +#[test] +fn burn_should_burn_an_asset() { + with_externalities( + &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), + || { + let origin = 1; + let asset_id = 1000; + let to_account = 2; + let amount = 1000; + let initial_issuance = 100; + let burn_amount = 400; + let expected_amount = 600; + + let default_permission = PermissionLatest { + update: Owner::Address(origin), + mint: Owner::Address(origin), + burn: Owner::Address(origin), + }; + + assert_ok!(GenericAsset::create( + Origin::signed(origin), + AssetOptions { + initial_issuance: initial_issuance, + permissions: default_permission + } + )); + assert_ok!(GenericAsset::mint(Origin::signed(origin), asset_id, to_account, amount)); + + assert_ok!(GenericAsset::burn( + Origin::signed(origin), + asset_id, + to_account, + burn_amount + )); + assert_eq!(GenericAsset::free_balance(&asset_id, &to_account), expected_amount); + }, + ); +} + +// Given +// - `default_permission` with all privileges. +// - All permissions for origin. +// When +// - After executing create function and check_permission function. +// Then +// - The account origin should have burn, mint and update permissions. +#[test] +fn check_permission_should_return_correct_permission() { + with_externalities( + &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), + || { + let origin = 1; + let asset_id = 1000; + let initial_issuance = 100; + + let default_permission = PermissionLatest { + update: Owner::Address(origin), + mint: Owner::Address(origin), + burn: Owner::Address(origin), + }; + + assert_ok!(GenericAsset::create( + Origin::signed(origin), + AssetOptions { + initial_issuance: initial_issuance, + permissions: default_permission + } + )); + + assert_eq!( + GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Burn), + true + ); + assert_eq!( + GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Mint), + true + ); + assert_eq!( + GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Update), + true + ); + }, + ); +} + +// Given +// - `default_permission` with no privileges. +// - No permissions for origin. +// When +// - After executing create function and check_permission function. +// Then +// - The account origin should not have burn, mint and update permissions. +#[test] +fn check_permission_should_return_false_for_no_permission() { + with_externalities( + &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), + || { + let origin = 1; + let asset_id = 1000; + let initial_issuance = 100; + + let default_permission = PermissionLatest { + update: Owner::None, + mint: Owner::None, + burn: Owner::None, + }; + + assert_ok!(GenericAsset::create( + Origin::signed(origin), + AssetOptions { + initial_issuance: initial_issuance, + permissions: default_permission + } + )); + + assert_eq!( + GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Burn), + false + ); + assert_eq!( + GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Mint), + false + ); + assert_eq!( + GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Update), + false + ); + }, + ); +} + +// Given +// - `default_permission` only with update. +// When +// - After executing update_permission function. +// Then +// - The account origin should not have the burn permission. +// - The account origin should have update and mint permissions. +#[test] +fn update_permission_should_change_permission() { + with_externalities( + &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), + || { + let origin = 1; + let asset_id = 1000; + let initial_issuance = 100; + + let default_permission = PermissionLatest { + update: Owner::Address(origin), + mint: Owner::None, + burn: Owner::None, + }; + + let new_permission = PermissionLatest { + update: Owner::Address(origin), + mint: Owner::Address(origin), + burn: Owner::None, + }; + + assert_ok!(GenericAsset::create( + Origin::signed(origin), + AssetOptions { + initial_issuance: initial_issuance, + permissions: default_permission + } + )); + + assert_ok!(GenericAsset::update_permission( + Origin::signed(origin), + asset_id, + new_permission + )); + assert_eq!( + GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Mint), + true + ); + assert_eq!( + GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Burn), + false + ); + }, + ); +} + +// Given +// - `default_permission` without any permissions. +// When +// - After executing update_permission function. +// Then +// - Should throw an error stating "Origin does not have enough permission to update permissions." +#[test] +fn update_permission_should_throw_error_when_lack_of_permissions() { + with_externalities( + &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), + || { + let origin = 1; + let asset_id = 1000; + let initial_issuance = 100; + + let default_permission = PermissionLatest { + update: Owner::None, + mint: Owner::None, + burn: Owner::None, + }; + + let new_permission = PermissionLatest { + update: Owner::Address(origin), + mint: Owner::Address(origin), + burn: Owner::None, + }; + + let expected_error_message = "Origin does not have enough permission to update permissions."; + + assert_ok!(GenericAsset::create( + Origin::signed(origin), + AssetOptions { + initial_issuance: initial_issuance, + permissions: default_permission + } + )); + + assert_noop!( + GenericAsset::update_permission(Origin::signed(origin), asset_id, new_permission), + expected_error_message + ); + }, + ); +} + +// Given +// - `asset_id` provided. +// - `from_account` is present. +// - All permissions for origin. +// When +// - After calling create_asset. +// Then +// - Should create a reserved token with provided id. +// - NextAssetId doesn't change. +// - TotalIssuance must equal to initial issuance. +// - FreeBalance must equal to initial issuance for the given account. +// - Permissions must have burn, mint and updatePermission for the given asset_id. +#[test] +fn create_asset_works_with_given_asset_id_and_from_account() { + with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { + let origin = 1; + let from_account: Option<::AccountId> = Some(1); + + let default_permission = PermissionLatest { + update: Owner::Address(origin), + mint: Owner::Address(origin), + burn: Owner::Address(origin), + }; + let expected_permission = PermissionVersions::V1(default_permission.clone()); + let asset_id = 9; + let initial_issuance = 100; + + assert_ok!(GenericAsset::create_asset( + Some(asset_id), + from_account, + AssetOptions { + initial_issuance: initial_issuance, + permissions: default_permission.clone() + } + )); + + // Test for side effects. + assert_eq!(>::get(), 10); + assert_eq!(>::get(asset_id), initial_issuance); + assert_eq!(>::get(&asset_id, &origin), initial_issuance); + assert_eq!(>::get(&asset_id), expected_permission); + }); +} + +// Given +// - `asset_id` is an id for user generated assets. +// - Whatever other params. +// Then +// - `create_asset` should not work. +#[test] +fn create_asset_with_non_reserved_asset_id_should_not_work() { + with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { + let origin = 1; + let from_account: Option<::AccountId> = Some(1); + + let default_permission = PermissionLatest { + update: Owner::Address(origin), + mint: Owner::Address(origin), + burn: Owner::Address(origin), + }; + + let asset_id = 11; + let initial_issuance = 100; + + assert_noop!( + GenericAsset::create_asset( + Some(asset_id), + from_account, + AssetOptions { + initial_issuance, + permissions: default_permission.clone() + } + ), + "Asset id not available." + ); + }); +} + +// Given +// - `asset_id` is for reserved assets, but already taken. +// - Whatever other params. +// Then +// - `create_asset` should not work. +#[test] +fn create_asset_with_a_taken_asset_id_should_not_work() { + with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { + let origin = 1; + let from_account: Option<::AccountId> = Some(1); + + let default_permission = PermissionLatest { + update: Owner::Address(origin), + mint: Owner::Address(origin), + burn: Owner::Address(origin), + }; + + let asset_id = 9; + let initial_issuance = 100; + + assert_ok!(GenericAsset::create_asset( + Some(asset_id), + from_account, + AssetOptions { + initial_issuance, + permissions: default_permission.clone() + } + )); + assert_noop!( + GenericAsset::create_asset( + Some(asset_id), + from_account, + AssetOptions { + initial_issuance, + permissions: default_permission.clone() + } + ), + "Asset id already taken." + ); + }); +} + +// Given +// - `asset_id` provided. +// - `from_account` is None. +// - All permissions for origin. +// When +// - After calling create_asset. +// Then +// - Should create a reserved token. +#[test] +fn create_asset_should_create_a_reserved_asset_when_from_account_is_none() { + with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { + let origin = 1; + let from_account: Option<::AccountId> = None; + + let default_permission = PermissionLatest { + update: Owner::Address(origin), + mint: Owner::Address(origin), + burn: Owner::Address(origin), + }; + + let created_account_id = 0; + let asset_id = 9; + let initial_issuance = 100; + + assert_ok!(GenericAsset::create_asset( + Some(asset_id), + from_account, + AssetOptions { + initial_issuance: initial_issuance, + permissions: default_permission + } + )); + + // Test for a side effect. + assert_eq!( + >::get(&asset_id, &created_account_id), + initial_issuance + ); + }); +} + +// Given +// - `asset_id` not provided. +// - `from_account` is None. +// - All permissions for origin. +// When +// - After calling create_asset. +// Then +// - Should create a user token. +// - `NextAssetId`'s get should return a new value. +// - Should not create a `reserved_asset`. +#[test] +fn create_asset_should_create_a_user_asset() { + with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { + let origin = 1; + let from_account: Option<::AccountId> = None; + + let default_permission = PermissionLatest { + update: Owner::Address(origin), + mint: Owner::Address(origin), + burn: Owner::Address(origin), + }; + + let created_account_id = 0; + let reserved_asset_id = 100000; + let initial_issuance = 100; + let created_user_asset_id = 10; + + assert_ok!(GenericAsset::create_asset( + None, + from_account, + AssetOptions { + initial_issuance: initial_issuance, + permissions: default_permission + } + )); + + // Test for side effects. + assert_eq!(>::get(&reserved_asset_id, &created_account_id), 0); + assert_eq!( + >::get(&created_user_asset_id, &created_account_id), + initial_issuance + ); + assert_eq!(>::get(created_user_asset_id), initial_issuance); + }); +} + +#[test] +fn update_permission_should_raise_event() { + // Arrange + let staking_asset_id = 16000; + let asset_id = 1000; + let origin = 1; + let initial_balance = 1000; + let permissions = PermissionLatest { + update: Owner::Address(origin), + mint: Owner::Address(origin), + burn: Owner::Address(origin), + }; + + with_externalities( + &mut ExtBuilder::default() + .next_asset_id(asset_id) + .free_balance((staking_asset_id, origin, initial_balance)) + .build(), + || { + assert_ok!(GenericAsset::create( + Origin::signed(origin), + AssetOptions { + initial_issuance: 0, + permissions: permissions.clone(), + } + )); + + // Act + assert_ok!(GenericAsset::update_permission( + Origin::signed(origin), + asset_id, + permissions.clone() + )); + + // Assert + assert!(System::events().iter().any(|record| record.event + == TestEvent::generic_asset(RawEvent::PermissionUpdated(asset_id, permissions.clone())))); + }, + ); +} + +#[test] +fn mint_should_raise_event() { + // Arrange + let staking_asset_id = 16000; + let asset_id = 1000; + let origin = 1; + let initial_balance = 1000; + let permissions = PermissionLatest { + update: Owner::Address(origin), + mint: Owner::Address(origin), + burn: Owner::Address(origin), + }; + let to = 2; + let amount = 100; + + with_externalities( + &mut ExtBuilder::default() + .next_asset_id(asset_id) + .free_balance((staking_asset_id, origin, initial_balance)) + .build(), + || { + assert_ok!(GenericAsset::create( + Origin::signed(origin), + AssetOptions { + initial_issuance: 0, + permissions: permissions.clone(), + } + )); + + // Act + assert_ok!(GenericAsset::mint(Origin::signed(origin), asset_id, to, amount)); + + // Assert + assert!(System::events() + .iter() + .any(|record| record.event == TestEvent::generic_asset(RawEvent::Minted(asset_id, to, amount)))); + }, + ); +} + +#[test] +fn burn_should_raise_event() { + // Arrange + let staking_asset_id = 16000; + let asset_id = 1000; + let origin = 1; + let initial_balance = 1000; + let permissions = PermissionLatest { + update: Owner::Address(origin), + mint: Owner::Address(origin), + burn: Owner::Address(origin), + }; + let amount = 100; + + with_externalities( + &mut ExtBuilder::default() + .next_asset_id(asset_id) + .free_balance((staking_asset_id, origin, initial_balance)) + .build(), + || { + assert_ok!(GenericAsset::create( + Origin::signed(origin), + AssetOptions { + initial_issuance: amount, + permissions: permissions.clone(), + } + )); + + // Act + assert_ok!(GenericAsset::burn(Origin::signed(origin), asset_id, origin, amount)); + + // Assert + assert!(System::events() + .iter() + .any(|record| record.event == TestEvent::generic_asset(RawEvent::Burned(asset_id, origin, amount)))); + }, + ); +} diff --git a/srml/grandpa/Cargo.toml b/srml/grandpa/Cargo.toml index 9e61029f728c2eabd3e78aa136262af91ce4edf6..2f13bd018fcaebca078e33d626a4568a77b339e4 100644 --- a/srml/grandpa/Cargo.toml +++ b/srml/grandpa/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] serde = { version = "1.0", optional = true, features = ["derive"] } -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } substrate-primitives = { path = "../../core/primitives", default-features = false } substrate-finality-grandpa-primitives = { path = "../../core/finality-grandpa/primitives", default-features = false } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } diff --git a/srml/grandpa/src/lib.rs b/srml/grandpa/src/lib.rs index 61610e91940fd05e5f825f291e8bdbac99adc390..ba60128a897cf583112d8ee0bc0b0e70dd78608b 100644 --- a/srml/grandpa/src/lib.rs +++ b/srml/grandpa/src/lib.rs @@ -30,8 +30,6 @@ // re-export since this is necessary for `impl_apis` in runtime. pub use substrate_finality_grandpa_primitives as fg_primitives; -#[cfg(feature = "std")] -use serde::Serialize; use rstd::prelude::*; use parity_codec::{self as codec, Encode, Decode}; use srml_support::{ @@ -40,44 +38,13 @@ use srml_support::{ use primitives::{ generic::{DigestItem, OpaqueDigestItemId}, traits::CurrentHeight }; -use fg_primitives::{ScheduledChange, GRANDPA_ENGINE_ID}; +use fg_primitives::{ScheduledChange, ConsensusLog, GRANDPA_ENGINE_ID}; pub use fg_primitives::{AuthorityId, AuthorityWeight}; use system::{ensure_signed, DigestOf}; mod mock; mod tests; -/// Consensus log type of this module. -#[cfg_attr(feature = "std", derive(Serialize, Debug))] -#[derive(Encode, Decode, PartialEq, Eq, Clone)] -pub enum Signal { - /// Authorities set change has been signaled. Contains the new set of authorities - /// and the delay in blocks _to finalize_ before applying. - AuthoritiesChange(ScheduledChange), - /// A forced authorities set change. Contains in this order: the median last - /// finalized block when the change was signaled, the delay in blocks _to import_ - /// before applying and the new set of authorities. - ForcedAuthoritiesChange(N, ScheduledChange), -} - -impl Signal { - /// Try to cast the log entry as a contained signal. - pub fn try_into_change(self) -> Option> { - match self { - Signal::AuthoritiesChange(change) => Some(change), - Signal::ForcedAuthoritiesChange(_, _) => None, - } - } - - /// Try to cast the log entry as a contained forced signal. - pub fn try_into_forced_change(self) -> Option<(N, ScheduledChange)> { - match self { - Signal::ForcedAuthoritiesChange(median, change) => Some((median, change)), - Signal::AuthoritiesChange(_) => None, - } - } -} - pub trait Trait: system::Trait { /// The event type of this module. type Event: From + Into<::Event>; @@ -161,7 +128,7 @@ decl_module! { if let Some(pending_change) = >::get() { if block_number == pending_change.scheduled_at { if let Some(median) = pending_change.forced { - Self::deposit_log(Signal::ForcedAuthoritiesChange( + Self::deposit_log(ConsensusLog::ForcedChange( median, ScheduledChange{ delay: pending_change.delay, @@ -169,7 +136,7 @@ decl_module! { } )) } else { - Self::deposit_log(Signal::AuthoritiesChange( + Self::deposit_log(ConsensusLog::ScheduledChange( ScheduledChange{ delay: pending_change.delay, next_authorities: pending_change.next_authorities.clone(), @@ -179,7 +146,7 @@ decl_module! { } if block_number == pending_change.scheduled_at + pending_change.delay { - >::put(&pending_change.next_authorities); + Authorities::put(&pending_change.next_authorities); Self::deposit_event( Event::NewAuthorities(pending_change.next_authorities) ); @@ -193,7 +160,7 @@ decl_module! { impl Module { /// Get the current set of authorities, along with their respective weights. pub fn grandpa_authorities() -> Vec<(AuthorityId, u64)> { - >::get() + Authorities::get() } /// Schedule a change in the authorities. @@ -242,16 +209,16 @@ impl Module { } /// Deposit one of this module's logs. - fn deposit_log(log: Signal) { + fn deposit_log(log: ConsensusLog) { let log: DigestItem = DigestItem::Consensus(GRANDPA_ENGINE_ID, log.encode()); >::deposit_log(log.into()); } } impl Module { - pub fn grandpa_log(digest: &DigestOf) -> Option> { + pub fn grandpa_log(digest: &DigestOf) -> Option> { let id = OpaqueDigestItemId::Consensus(&GRANDPA_ENGINE_ID); - digest.convert_first(|l| l.try_to::>(id)) + digest.convert_first(|l| l.try_to::>(id)) } pub fn pending_change(digest: &DigestOf) @@ -269,6 +236,7 @@ impl Module { impl session::OneSessionHandler for Module { type Key = AuthorityId; + fn on_new_session<'a, I: 'a>(changed: bool, validators: I) where I: Iterator { @@ -286,8 +254,8 @@ impl session::OneSessionHandler for Module { } } } - fn on_disabled(_i: usize) { - // ignore? + fn on_disabled(i: usize) { + Self::deposit_log(ConsensusLog::OnDisabled(i as u64)) } } diff --git a/srml/grandpa/src/mock.rs b/srml/grandpa/src/mock.rs index 80c99b9a3cfaa8cb37f25ef6b52f8ccc9963bcff..733b2deaf1493cc19a482d1fa3b40078eea3969c 100644 --- a/srml/grandpa/src/mock.rs +++ b/srml/grandpa/src/mock.rs @@ -18,24 +18,20 @@ #![cfg(test)] -use primitives::{ - BuildStorage, DigestItem, traits::IdentityLookup, testing::{Header, UintAuthorityId} -}; +use primitives::{DigestItem, traits::IdentityLookup, testing::{Header, UintAuthorityId}}; use runtime_io; -use srml_support::{impl_outer_origin, impl_outer_event}; +use srml_support::{impl_outer_origin, impl_outer_event, parameter_types}; use substrate_primitives::{H256, Blake2Hasher}; use parity_codec::{Encode, Decode}; -use crate::{AuthorityId, GenesisConfig, Trait, Module, Signal}; +use crate::{AuthorityId, GenesisConfig, Trait, Module, ConsensusLog}; use substrate_finality_grandpa_primitives::GRANDPA_ENGINE_ID; impl_outer_origin!{ pub enum Origin for Test {} } -impl From> for DigestItem { - fn from(log: Signal) -> DigestItem { - DigestItem::Consensus(GRANDPA_ENGINE_ID, log.encode()) - } +pub fn grandpa_log(log: ConsensusLog) -> DigestItem { + DigestItem::Consensus(GRANDPA_ENGINE_ID, log.encode()) } // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. @@ -45,6 +41,9 @@ impl Trait for Test { type Event = TestEvent; } +parameter_types! { + pub const BlockHashCount: u64 = 250; +} impl system::Trait for Test { type Origin = Origin; type Index = u64; @@ -55,6 +54,7 @@ impl system::Trait for Test { type Lookup = IdentityLookup; type Header = Header; type Event = TestEvent; + type BlockHashCount = BlockHashCount; } mod grandpa { @@ -72,9 +72,8 @@ pub fn to_authorities(vec: Vec<(u64, u64)>) -> Vec<(AuthorityId, u64)> { } pub fn new_test_ext(authorities: Vec<(u64, u64)>) -> runtime_io::TestExternalities { - let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; - t.extend(GenesisConfig:: { - _genesis_phantom_data: Default::default(), + let mut t = system::GenesisConfig::default().build_storage::().unwrap().0; + t.extend(GenesisConfig { authorities: to_authorities(authorities), }.build_storage().unwrap().0); t.into() diff --git a/srml/grandpa/src/tests.rs b/srml/grandpa/src/tests.rs index ab923f295b6d7475e6603ebd2b895527d70be9d4..763c4fce89cca0b271f16cf92052e60ff4266dba 100644 --- a/srml/grandpa/src/tests.rs +++ b/srml/grandpa/src/tests.rs @@ -39,9 +39,9 @@ fn authorities_change_logged() { let header = System::finalize(); assert_eq!(header.digest, Digest { logs: vec![ - Signal::AuthoritiesChange( + grandpa_log(ConsensusLog::ScheduledChange( ScheduledChange { delay: 0, next_authorities: to_authorities(vec![(4, 1), (5, 1), (6, 1)]) } - ).into(), + )), ], }); @@ -64,9 +64,9 @@ fn authorities_change_logged_after_delay() { let header = System::finalize(); assert_eq!(header.digest, Digest { logs: vec![ - Signal::AuthoritiesChange( + grandpa_log(ConsensusLog::ScheduledChange( ScheduledChange { delay: 1, next_authorities: to_authorities(vec![(4, 1), (5, 1), (6, 1)]) } - ).into(), + )), ], }); diff --git a/srml/indices/Cargo.toml b/srml/indices/Cargo.toml index de496f20c6bbaab9a637275b123abe6f0ace3954..bc67132c86f1dc44531a48c83e25046c2455ad52 100644 --- a/srml/indices/Cargo.toml +++ b/srml/indices/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] serde = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false} -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } substrate-keyring = { path = "../../core/keyring", optional = true } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } runtime-io = { package = "sr-io", path = "../../core/sr-io", default-features = false } diff --git a/srml/indices/src/mock.rs b/srml/indices/src/mock.rs index e2ea51e89d958dd893d8a56df7d78c714f342236..53e8f314c94bbfa46d4e9d65bc66ca9daa1bb8c2 100644 --- a/srml/indices/src/mock.rs +++ b/srml/indices/src/mock.rs @@ -20,10 +20,9 @@ use std::collections::HashSet; use ref_thread_local::{ref_thread_local, RefThreadLocal}; -use primitives::BuildStorage; use primitives::testing::Header; use substrate_primitives::{H256, Blake2Hasher}; -use srml_support::impl_outer_origin; +use srml_support::{impl_outer_origin, parameter_types}; use {runtime_io, system}; use crate::{GenesisConfig, Module, Trait, IsDeadAccount, OnNewAccount, ResolveHint}; @@ -65,6 +64,9 @@ impl ResolveHint for TestResolveHint { // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, PartialEq, Eq, Debug)] pub struct Runtime; +parameter_types! { + pub const BlockHashCount: u64 = 250; +} impl system::Trait for Runtime { type Origin = Origin; type Index = u64; @@ -75,6 +77,7 @@ impl system::Trait for Runtime { type Lookup = Indices; type Header = Header; type Event = (); + type BlockHashCount = BlockHashCount; } impl Trait for Runtime { type AccountIndex = u64; @@ -90,7 +93,7 @@ pub fn new_test_ext() -> runtime_io::TestExternalities { for i in 1..5 { h.insert(i); } } - let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; + let mut t = system::GenesisConfig::default().build_storage::().unwrap().0; t.extend(GenesisConfig:: { ids: vec![1, 2, 3, 4] }.build_storage().unwrap().0); diff --git a/srml/metadata/Cargo.toml b/srml/metadata/Cargo.toml index 0e9ae66540bfa46ab8e11ca03a1ac9b2ead08b25..cdb7a41ff860dea57de64ac4bc12e4b00390b5d5 100644 --- a/srml/metadata/Cargo.toml +++ b/srml/metadata/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0", optional = true, features = ["derive"] } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } primitives = { package = "substrate-primitives", path = "../../core/primitives", default-features = false } diff --git a/srml/metadata/src/lib.rs b/srml/metadata/src/lib.rs index b1ab57b506878559b3a8dd07e2d37a1e00c2629b..fca2a1cfdcf0d5162a0bfe9d263dc987460ca73d 100644 --- a/srml/metadata/src/lib.rs +++ b/srml/metadata/src/lib.rs @@ -102,10 +102,7 @@ impl serde::Serialize for DecodeDifferent B: serde::Serialize + 'static, O: serde::Serialize + 'static, { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { + fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { match self { DecodeDifferent::Encode(b) => b.serialize(serializer), DecodeDifferent::Decoded(o) => o.serialize(serializer), @@ -162,10 +159,7 @@ impl std::fmt::Debug for FnEncode { #[cfg(feature = "std")] impl serde::Serialize for FnEncode { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { + fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { self.0().serialize(serializer) } } @@ -190,21 +184,24 @@ pub struct EventMetadata { pub documentation: DecodeDifferentArray<&'static str, StringBuf>, } -/// All the metadata about a storage. +/// All the metadata about one storage entry. #[derive(Clone, PartialEq, Eq, Encode)] #[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] -pub struct StorageMetadata { - pub functions: DecodeDifferentArray, +pub struct StorageEntryMetadata { + pub name: DecodeDifferentStr, + pub modifier: StorageEntryModifier, + pub ty: StorageEntryType, + pub default: ByteGetter, + pub documentation: DecodeDifferentArray<&'static str, StringBuf>, } -/// All the metadata about a storage function. +/// All the metadata about one module constant. #[derive(Clone, PartialEq, Eq, Encode)] #[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] -pub struct StorageFunctionMetadata { +pub struct ModuleConstantMetadata { pub name: DecodeDifferentStr, - pub modifier: StorageFunctionModifier, - pub ty: StorageFunctionType, - pub default: ByteGetter, + pub ty: DecodeDifferentStr, + pub value: ByteGetter, pub documentation: DecodeDifferentArray<&'static str, StringBuf>, } @@ -238,10 +235,7 @@ impl Eq for DefaultByteGetter { } #[cfg(feature = "std")] impl serde::Serialize for DefaultByteGetter { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { + fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { self.0.default_byte().serialize(serializer) } } @@ -264,10 +258,10 @@ pub enum StorageHasher { Twox64Concat, } -/// A storage function type. +/// A storage entry type. #[derive(Clone, PartialEq, Eq, Encode)] #[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] -pub enum StorageFunctionType { +pub enum StorageEntryType { Plain(DecodeDifferentStr), Map { hasher: StorageHasher, @@ -284,10 +278,10 @@ pub enum StorageFunctionType { }, } -/// A storage function modifier. +/// A storage entry modifier. #[derive(Clone, PartialEq, Eq, Encode)] #[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] -pub enum StorageFunctionModifier { +pub enum StorageEntryModifier { Optional, Default, } @@ -313,8 +307,10 @@ pub enum RuntimeMetadata { V3(RuntimeMetadataDeprecated), /// Version 4 for runtime metadata. No longer used. V4(RuntimeMetadataDeprecated), - /// Version 5 for runtime metadata. - V5(RuntimeMetadataV5), + /// Version 5 for runtime metadata. No longer used. + V5(RuntimeMetadataDeprecated), + /// Version 6 for runtime metadata. + V6(RuntimeMetadataV6), } /// Enum that should fail. @@ -323,8 +319,7 @@ pub enum RuntimeMetadata { pub enum RuntimeMetadataDeprecated { } impl Encode for RuntimeMetadataDeprecated { - fn encode_to(&self, _dest: &mut W) { - } + fn encode_to(&self, _dest: &mut W) {} } #[cfg(feature = "std")] @@ -337,7 +332,7 @@ impl Decode for RuntimeMetadataDeprecated { /// The metadata of a runtime. #[derive(Eq, Encode, PartialEq)] #[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] -pub struct RuntimeMetadataV5 { +pub struct RuntimeMetadataV6 { pub modules: DecodeDifferentArray, } @@ -347,12 +342,14 @@ pub struct RuntimeMetadataV5 { pub struct ModuleMetadata { pub name: DecodeDifferentStr, pub prefix: DecodeDifferent, StringBuf>, - pub storage: ODFnA, + pub storage: ODFnA, pub calls: ODFnA, pub event: ODFnA, + pub constants: DFnA, } -type ODFnA = Option, Vec>>; +type ODFnA = Option>; +type DFnA = DecodeDifferent, Vec>; impl Into for RuntimeMetadataPrefixed { fn into(self) -> primitives::OpaqueMetadata { diff --git a/srml/session/Cargo.toml b/srml/session/Cargo.toml index 2c8c040ea1519408ac68cd6144b2725aa0fd4fac..51b613497f47a373a7414d8825914bb27f38c666 100644 --- a/srml/session/Cargo.toml +++ b/srml/session/Cargo.toml @@ -7,20 +7,22 @@ edition = "2018" [dependencies] serde = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false} -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } srml-support = { path = "../support", default-features = false } system = { package = "srml-system", path = "../system", default-features = false } timestamp = { package = "srml-timestamp", path = "../timestamp", default-features = false } +substrate-trie = { path = "../../core/trie", default-features = false, optional = true } +runtime_io = { package = "sr-io", path = "../../core/sr-io", default-features = false } [dev-dependencies] substrate-primitives = { path = "../../core/primitives" } -runtime_io = { package = "sr-io", path = "../../core/sr-io" } lazy_static = "1.0" [features] -default = ["std"] +default = ["std", "historical"] +historical = ["substrate-trie"] std = [ "serde", "safe-mix/std", @@ -28,5 +30,6 @@ std = [ "rstd/std", "srml-support/std", "primitives/std", - "timestamp/std" + "timestamp/std", + "substrate-trie/std" ] diff --git a/srml/session/src/historical.rs b/srml/session/src/historical.rs new file mode 100644 index 0000000000000000000000000000000000000000..c6755c3ba3592a10c7eaf9dca2e9e33ddf7f8b08 --- /dev/null +++ b/srml/session/src/historical.rs @@ -0,0 +1,447 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +//! An opt-in utility for tracking historical sessions in SRML-session. +//! +//! This is generally useful when implementing blockchains that require accountable +//! safety where validators from some amount f prior sessions must remain slashable. +//! +//! Rather than store the full session data for any given session, we instead commit +//! to the roots of merkle tries containing the session data. +//! +//! These roots and proofs of inclusion can be generated at any time during the current session. +//! Afterwards, the proofs can be fed to a consensus module when reporting misbehavior. + +use rstd::prelude::*; +use parity_codec::{Encode, Decode}; +use primitives::KeyTypeId; +use primitives::traits::{Convert, OpaqueKeys, Hash as HashT}; +use srml_support::{ + StorageValue, StorageMap, decl_module, decl_storage, +}; +use srml_support::{Parameter, print}; +use substrate_trie::{MemoryDB, Trie, TrieMut, TrieDBMut, TrieDB, Recorder}; + +use super::{SessionIndex, Module as SessionModule}; + +/// Trait necessary for the historical module. +pub trait Trait: super::Trait { + /// Full identification of the validator. + type FullIdentification: Parameter; + + /// A conversion from validator ID to full identification. + /// + /// This should contain any references to economic actors associated with the + /// validator, since they may be outdated by the time this is queried from a + /// historical trie. + /// + /// This mapping is expected to remain stable in between calls to + /// `Self::OnSessionEnding::on_session_ending` which return new validators. + type FullIdentificationOf: Convert>; +} + +decl_storage! { + trait Store for Module as Session { + /// Mapping from historical session indices to session-data root hash. + HistoricalSessions get(historical_root): map SessionIndex => Option; + /// Queued full identifications for queued sessions whose validators have become obsolete. + CachedObsolete get(cached_obsolete): map SessionIndex + => Option>; + /// The range of historical sessions we store. [first, last) + StoredRange: Option<(SessionIndex, SessionIndex)>; + } +} + +decl_module! { + pub struct Module for enum Call where origin: T::Origin { } +} + +impl Module { + /// Prune historical stored session roots up to (but not including) + /// `up_to`. + pub fn prune_up_to(up_to: SessionIndex) { + ::StoredRange::mutate(|range| { + let (start, end) = match *range { + Some(range) => range, + None => return, // nothing to prune. + }; + + let up_to = rstd::cmp::min(up_to, end); + + if up_to < start { + return // out of bounds. harmless. + } + + (start..up_to).for_each(::HistoricalSessions::remove); + + let new_start = up_to; + *range = if new_start == end { + None // nothing is stored. + } else { + Some((new_start, end)) + } + }) + } +} + +/// Specialization of the crate-level `OnSessionEnding` which returns the old +/// set of full identification when changing the validator set. +pub trait OnSessionEnding: crate::OnSessionEnding { + /// Returns the set of new validators, if any, along with the old validators + /// and their full identifications. + fn on_session_ending(ending: SessionIndex, applied_at: SessionIndex) + -> Option<(Vec, Vec<(ValidatorId, FullIdentification)>)>; +} + +/// An `OnSessionEnding` implementation that wraps an inner `I` and also +/// sets the historical trie root of the ending session. +pub struct NoteHistoricalRoot(rstd::marker::PhantomData<(T, I)>); + +impl crate::OnSessionEnding for NoteHistoricalRoot + where I: OnSessionEnding +{ + fn on_session_ending(ending: SessionIndex, applied_at: SessionIndex) -> Option> { + StoredRange::mutate(|range| { + range.get_or_insert_with(|| (ending, ending)).1 = ending + 1; + }); + + // do all of this _before_ calling the other `on_session_ending` impl + // so that we have e.g. correct exposures from the _current_. + + match ProvingTrie::::generate_for(ending) { + Ok(trie) => >::insert(ending, &trie.root), + Err(reason) => { + print("Failed to generate historical ancestry-inclusion proof."); + print(reason); + } + }; + + // trie has been generated for this session, so it's no longer queued. + >::remove(&ending); + + let (new_validators, old_exposures) = >::on_session_ending(ending, applied_at)?; + + // every session from `ending+1 .. applied_at` now has obsolete `FullIdentification` + // now that a new validator election has occurred. + // we cache these in the trie until those sessions themselves end. + for obsolete in (ending + 1) .. applied_at { + >::insert(obsolete, &old_exposures); + } + + Some(new_validators) + } +} + +type HasherOf = <::Hashing as HashT>::Hasher; + +/// A tuple of the validator's ID and their full identification. +pub type IdentificationTuple = (::ValidatorId, ::FullIdentification); + +/// a trie instance for checking and generating proofs. +pub struct ProvingTrie { + db: MemoryDB>, + root: T::Hash, +} + +impl ProvingTrie { + fn generate_for(now: SessionIndex) -> Result { + let mut db = MemoryDB::default(); + let mut root = Default::default(); + + fn build(root: &mut T::Hash, db: &mut MemoryDB>, validators: I) + -> Result<(), &'static str> + where I: IntoIterator)> + { + let mut trie = TrieDBMut::new(db, root); + for (i, (validator, full_id)) in validators.into_iter().enumerate() { + let i = i as u32; + let keys = match >::load_keys(&validator) { + None => continue, + Some(k) => k, + }; + + let full_id = full_id.or_else(|| T::FullIdentificationOf::convert(validator.clone())); + let full_id = match full_id { + None => return Err("no full identification for a current validator"), + Some(full) => (validator, full), + }; + + // map each key to the owner index. + for key_id in T::Keys::key_ids() { + let key = keys.get_raw(key_id); + let res = (key_id, key).using_encoded(|k| + i.using_encoded(|v| + trie.insert(k, v) + ) + ); + + let _ = res.map_err(|_| "failed to insert into trie")?; + } + + // map each owner index to the full identification. + let _ = i.using_encoded(|k| full_id.using_encoded(|v| trie.insert(k, v))) + .map_err(|_| "failed to insert into trie")?; + } + + Ok(()) + } + + // if the current session's full identifications are obsolete but cached, + // use those. + if let Some(obsolete) = >::get(&now) { + build::(&mut root, &mut db, obsolete.into_iter().map(|(v, f)| (v, Some(f))))? + } else { + let validators = >::validators(); + build::(&mut root, &mut db, validators.into_iter().map(|v| (v, None)))? + } + + Ok(ProvingTrie { + db, + root, + }) + } + + fn from_nodes(root: T::Hash, nodes: &[Vec]) -> Self { + use substrate_trie::HashDBT; + + let mut memory_db = MemoryDB::default(); + for node in nodes { + HashDBT::insert(&mut memory_db, &[], &node[..]); + } + + ProvingTrie { + db: memory_db, + root, + } + } + + /// Prove the full verification data for a given key and key ID. + pub fn prove(&self, key_id: KeyTypeId, key_data: &[u8]) -> Option>> { + let trie = TrieDB::new(&self.db, &self.root).ok()?; + let mut recorder = Recorder::new(); + let val_idx = (key_id, key_data).using_encoded(|s| { + trie.get_with(s, &mut recorder) + .ok()? + .and_then(|raw| u32::decode(&mut &*raw)) + })?; + + val_idx.using_encoded(|s| { + trie.get_with(s, &mut recorder) + .ok()? + .and_then(|raw| >::decode(&mut &*raw)) + })?; + + Some(recorder.drain().into_iter().map(|r| r.data).collect()) + } + + /// Access the underlying trie root. + pub fn root(&self) -> &T::Hash { + &self.root + } + + // Check a proof contained within the current memory-db. Returns `None` if the + // nodes within the current `MemoryDB` are insufficient to query the item. + fn query(&self, key_id: KeyTypeId, key_data: &[u8]) -> Option> { + let trie = TrieDB::new(&self.db, &self.root).ok()?; + let val_idx = (key_id, key_data).using_encoded(|s| trie.get(s)) + .ok()? + .and_then(|raw| u32::decode(&mut &*raw))?; + + val_idx.using_encoded(|s| trie.get(s)) + .ok()? + .and_then(|raw| >::decode(&mut &*raw)) + } + +} + +/// Proof of ownership of a specific key. +#[derive(Encode, Decode, Clone)] +pub struct Proof { + session: SessionIndex, + trie_nodes: Vec>, +} + +impl> srml_support::traits::KeyOwnerProofSystem<(KeyTypeId, D)> + for Module +{ + type Proof = Proof; + type FullIdentification = IdentificationTuple; + + fn prove(key: (KeyTypeId, D)) -> Option { + let session = >::current_index(); + let trie = ProvingTrie::::generate_for(session).ok()?; + + let (id, data) = key; + + trie.prove(id, data.as_ref()).map(|trie_nodes| Proof { + session, + trie_nodes, + }) + } + + fn check_proof(key: (KeyTypeId, D), proof: Proof) -> Option> { + let (id, data) = key; + + if proof.session == >::current_index() { + >::key_owner(id, data.as_ref()).and_then(|owner| + T::FullIdentificationOf::convert(owner.clone()).map(move |id| (owner, id)) + ) + } else { + let root = >::get(&proof.session)?; + let trie = ProvingTrie::::from_nodes(root, &proof.trie_nodes); + + trie.query(id, data.as_ref()) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use runtime_io::with_externalities; + use substrate_primitives::Blake2Hasher; + use primitives::{ + traits::OnInitialize, + testing::{UintAuthorityId, UINT_DUMMY_KEY}, + }; + use crate::mock::{ + NEXT_VALIDATORS, force_new_session, + set_next_validators, Test, System, Session, + }; + use srml_support::traits::KeyOwnerProofSystem; + + type Historical = Module; + + fn new_test_ext() -> runtime_io::TestExternalities { + let mut t = system::GenesisConfig::default().build_storage::().unwrap().0; + let (storage, _child_storage) = crate::GenesisConfig:: { + keys: NEXT_VALIDATORS.with(|l| + l.borrow().iter().cloned().map(|i| (i, UintAuthorityId(i))).collect() + ), + }.build_storage().unwrap(); + t.extend(storage); + runtime_io::TestExternalities::new(t) + } + + #[test] + fn generated_proof_is_good() { + with_externalities(&mut new_test_ext(), || { + set_next_validators(vec![1, 2]); + force_new_session(); + + System::set_block_number(1); + Session::on_initialize(1); + + let encoded_key_1 = UintAuthorityId(1).encode(); + let proof = Historical::prove((UINT_DUMMY_KEY, &encoded_key_1[..])).unwrap(); + + // proof-checking in the same session is OK. + assert!( + Historical::check_proof( + (UINT_DUMMY_KEY, &encoded_key_1[..]), + proof.clone(), + ).is_some() + ); + + set_next_validators(vec![1, 2, 4]); + force_new_session(); + + assert!(Historical::cached_obsolete(&(proof.session + 1)).is_none()); + + System::set_block_number(2); + Session::on_initialize(2); + + assert!(Historical::cached_obsolete(&(proof.session + 1)).is_some()); + + assert!(Historical::historical_root(proof.session).is_some()); + assert!(Session::current_index() > proof.session); + + // proof-checking in the next session is also OK. + assert!( + Historical::check_proof( + (UINT_DUMMY_KEY, &encoded_key_1[..]), + proof.clone(), + ).is_some() + ); + + set_next_validators(vec![1, 2, 5]); + + force_new_session(); + System::set_block_number(3); + Session::on_initialize(3); + + assert!(Historical::cached_obsolete(&(proof.session + 1)).is_none()); + }); + } + + #[test] + fn prune_up_to_works() { + with_externalities(&mut new_test_ext(), || { + for i in 1..101u64 { + set_next_validators(vec![i]); + force_new_session(); + + System::set_block_number(i); + Session::on_initialize(i); + + } + + assert_eq!(StoredRange::get(), Some((0, 100))); + + for i in 1..100 { + assert!(Historical::historical_root(i).is_some()) + } + + Historical::prune_up_to(10); + assert_eq!(StoredRange::get(), Some((10, 100))); + + Historical::prune_up_to(9); + assert_eq!(StoredRange::get(), Some((10, 100))); + + for i in 10..100 { + assert!(Historical::historical_root(i).is_some()) + } + + Historical::prune_up_to(99); + assert_eq!(StoredRange::get(), Some((99, 100))); + + Historical::prune_up_to(100); + assert_eq!(StoredRange::get(), None); + + for i in 101..201u64 { + set_next_validators(vec![i]); + force_new_session(); + + System::set_block_number(i); + Session::on_initialize(i); + + } + + assert_eq!(StoredRange::get(), Some((100, 200))); + + for i in 101..200 { + assert!(Historical::historical_root(i).is_some()) + } + + Historical::prune_up_to(9999); + assert_eq!(StoredRange::get(), None); + + for i in 101..200 { + assert!(Historical::historical_root(i).is_none()) + } + }); + } +} diff --git a/srml/session/src/lib.rs b/srml/session/src/lib.rs index 3ae7c9801299be7026bcadfe4c66be07dc77b36c..546513c953afb28bc7de5977dab6d9c59be31688 100644 --- a/srml/session/src/lib.rs +++ b/srml/session/src/lib.rs @@ -29,13 +29,17 @@ //! //! //! - **Session:** A session is a period of time that has a constant set of validators. Validators can only join -//! or exit the validator set at a session change. It is measured in block numbers and set with `set_length` -//! during a session for use in subsequent sessions. +//! or exit the validator set at a session change. It is measured in block numbers. The block where a session is +//! ended is determined by the `ShouldSessionEnd` trait. When the session is ending, a new validator set +//! can be chosen by `OnSessionEnding` implementations. //! - **Session key:** A session key is actually several keys kept together that provide the various signing //! functions required by network authorities/validators in pursuit of their duties. +//! - **Validator ID:** Every account has an associated validator ID. For some simple staking systems, this +//! may just be the same as the account ID. For staking systems using a stash/controller model, +//! the validator ID would be the stash account ID of the controller. //! - **Session key configuration process:** A session key is set using `set_key` for use in the -//! next session. It is stored in `NextKeyFor`, a mapping between the caller's `AccountID` and the session -//! key provided. `set_key` allows users to set their session key prior to becoming a validator. +//! next session. It is stored in `NextKeyFor`, a mapping between the caller's `ValidatorId` and the session +//! keys provided. `set_key` allows users to set their session key prior to being selected as validator. //! It is a public call since it uses `ensure_signed`, which checks that the origin is a signed account. //! As such, the account ID of the origin stored in in `NextKeyFor` may not necessarily be associated with //! a block author or a validator. The session keys of accounts are removed once their account balance is zero. @@ -115,59 +119,86 @@ #![cfg_attr(not(feature = "std"), no_std)] -use rstd::{prelude::*, marker::PhantomData, ops::Rem}; -#[cfg(not(feature = "std"))] -use rstd::alloc::borrow::ToOwned; -use parity_codec::Decode; -use primitives::traits::{Zero, Saturating, Member, OpaqueKeys}; -use srml_support::{StorageValue, StorageMap, for_each_tuple, decl_module, decl_event, decl_storage}; -use srml_support::{ensure, traits::{OnFreeBalanceZero, Get}, Parameter, print}; -use system::ensure_signed; +use rstd::{prelude::*, marker::PhantomData, ops::{Sub, Rem}}; +use parity_codec::{Decode, Encode}; +use primitives::KeyTypeId; +use primitives::traits::{Convert, Zero, Member, OpaqueKeys, TypedKey, Hash}; +use srml_support::{ + dispatch::Result, + storage, + ConsensusEngineId, StorageValue, for_each_tuple, decl_module, + decl_event, decl_storage, +}; +use srml_support::{ensure, traits::{OnFreeBalanceZero, Get, FindAuthor}, Parameter}; +use system::{self, ensure_signed}; + +#[cfg(test)] +mod mock; + +#[cfg(feature = "historical")] +pub mod historical; /// Simple index type with which we can count sessions. pub type SessionIndex = u32; +/// Decides whether the session should be ended. pub trait ShouldEndSession { + /// Return `true` if the session should be ended. fn should_end_session(now: BlockNumber) -> bool; } +/// Ends the session after a fixed period of blocks. +/// +/// The first session will have length of `Offset`, and +/// the following sessions will have length of `Period`. +/// This may prove nonsensical if `Offset` >= `Period`. pub struct PeriodicSessions< Period, Offset, >(PhantomData<(Period, Offset)>); impl< - BlockNumber: Rem + Saturating + Zero, + BlockNumber: Rem + Sub + Zero + PartialOrd, Period: Get, Offset: Get, > ShouldEndSession for PeriodicSessions { fn should_end_session(now: BlockNumber) -> bool { - ((now.saturating_sub(Offset::get())) % Period::get()).is_zero() + let offset = Offset::get(); + now >= offset && ((now - offset) % Period::get()).is_zero() } } -pub trait OnSessionEnding { +/// An event handler for when the session is ending. +pub trait OnSessionEnding { /// Handle the fact that the session is ending, and optionally provide the new validator set. - fn on_session_ending(i: SessionIndex) -> Option>; + /// + /// `ending_index` is the index of the currently ending session. + /// The returned validator set, if any, will not be applied until `next_index`. + /// `next_index` is guaranteed to be at least `ending_index + 1`, since session indices don't + /// repeat. + fn on_session_ending(ending_index: SessionIndex, next_index: SessionIndex) -> Option>; } impl OnSessionEnding for () { - fn on_session_ending(_: SessionIndex) -> Option> { None } + fn on_session_ending(_: SessionIndex, _: SessionIndex) -> Option> { None } } /// Handler for when a session keys set changes. -pub trait SessionHandler { +pub trait SessionHandler { /// Session set has changed; act appropriately. - fn on_new_session(changed: bool, validators: &[(AccountId, Ks)]); + fn on_new_session(changed: bool, validators: &[(ValidatorId, Ks)]); /// A validator got disabled. Act accordingly until a new session begins. fn on_disabled(validator_index: usize); } -pub trait OneSessionHandler { - type Key: Decode + Default; +/// One session-key type handler. +pub trait OneSessionHandler { + /// The key type expected. + type Key: Decode + Default + TypedKey; + fn on_new_session<'a, I: 'a>(changed: bool, validators: I) - where I: Iterator, AccountId: 'a; + where I: Iterator, ValidatorId: 'a; fn on_disabled(i: usize); } @@ -182,11 +213,10 @@ macro_rules! impl_session_handlers { ( $($t:ident)* ) => { impl ),*> SessionHandler for ( $( $t , )* ) { fn on_new_session(changed: bool, validators: &[(AId, Ks)]) { - let mut i: usize = 0; $( - i += 1; let our_keys = validators.iter() - .map(|k| (&k.0, k.1.get::<$t::Key>(i - 1).unwrap_or_default())); + .map(|k| (&k.0, k.1.get::<$t::Key>(<$t::Key as TypedKey>::KEY_TYPE) + .unwrap_or_default())); $t::on_new_session(changed, our_keys); )* } @@ -201,54 +231,105 @@ macro_rules! impl_session_handlers { for_each_tuple!(impl_session_handlers); +/// Handler for selecting the genesis validator set. +pub trait SelectInitialValidators { + /// Returns the initial validator set. If `None` is returned + /// all accounts that have session keys set in the genesis block + /// will be validators. + fn select_initial_validators() -> Option>; +} + +/// Implementation of `SelectInitialValidators` that does nothing. +impl SelectInitialValidators for () { + fn select_initial_validators() -> Option> { + None + } +} pub trait Trait: system::Trait { /// The overarching event type. type Event: From + Into<::Event>; + /// A stable ID for a validator. + type ValidatorId: Member + Parameter; + + /// A conversion to validator ID to account ID. + type ValidatorIdOf: Convert>; + /// Indicator for when to end the session. type ShouldEndSession: ShouldEndSession; /// Handler for when a session is about to end. - type OnSessionEnding: OnSessionEnding; + type OnSessionEnding: OnSessionEnding; /// Handler when a session has changed. - type SessionHandler: SessionHandler; + type SessionHandler: SessionHandler; /// The keys. type Keys: OpaqueKeys + Member + Parameter + Default; + + /// Select initial validators. + type SelectInitialValidators: SelectInitialValidators; } -type OpaqueKey = Vec; +const DEDUP_KEY_LEN: usize = 13; +const DEDUP_KEY_PREFIX: &[u8; DEDUP_KEY_LEN] = b":session:keys"; decl_storage! { trait Store for Module as Session { /// The current set of validators. - pub Validators get(validators) config(): Vec; + Validators get(validators): Vec; /// Current index of the session. - pub CurrentIndex get(current_index): SessionIndex; + CurrentIndex get(current_index): SessionIndex; /// True if anything has changed in this session. Changed: bool; - /// The next key for a given validator. - NextKeyFor build(|config: &GenesisConfig| { - config.keys.clone() - }): map T::AccountId => Option; - - /// The keys that are currently active. - Active build(|config: &GenesisConfig| { - (0..T::Keys::count()).map(|i| ( - i as u32, - config.keys.iter() - .map(|x| x.1.get_raw(i).to_vec()) - .collect::>(), - )).collect::)>>() - }): map u32 => Vec; + /// Queued keys changed. + QueuedChanged: bool; + + /// The queued keys for the next session. When the next session begins, these keys + /// will be used to determine the validator's session keys. + QueuedKeys get(queued_keys): Vec<(T::ValidatorId, T::Keys)>; + } add_extra_genesis { - config(keys): Vec<(T::AccountId, T::Keys)>; + config(keys): Vec<(T::ValidatorId, T::Keys)>; + build(| + storage: &mut primitives::StorageOverlay, + _: &mut primitives::ChildrenStorageOverlay, + config: &GenesisConfig + | { + runtime_io::with_storage(storage, || { + for (who, keys) in config.keys.iter().cloned() { + assert!( + >::load_keys(&who).is_none(), + "genesis config contained duplicate validator {:?}", who, + ); + + >::do_set_keys(&who, keys) + .expect("genesis config must not contain duplicates; qed"); + } + + let initial_validators = T::SelectInitialValidators::select_initial_validators() + .unwrap_or_else(|| config.keys.iter().map(|(ref v, _)| v.clone()).collect()); + + assert!(!initial_validators.is_empty(), "Empty validator set in genesis block!"); + + let queued_keys: Vec<_> = initial_validators + .iter() + .cloned() + .map(|v| ( + v.clone(), + >::load_keys(&v).unwrap_or_default(), + )) + .collect(); + + >::put(initial_validators); + >::put(queued_keys); + }); + }); } } @@ -271,51 +352,25 @@ decl_module! { /// The dispatch origin of this function must be signed. /// /// # - /// - O(1). + /// - O(log n) in number of accounts. /// - One extra DB entry. /// # - fn set_keys(origin, keys: T::Keys, proof: Vec) { + fn set_keys(origin, keys: T::Keys, proof: Vec) -> Result { let who = ensure_signed(origin)?; ensure!(keys.ownership_proof_is_valid(&proof), "invalid ownership proof"); - let old_keys = >::get(&who); - let mut updates = vec![]; + let who = match T::ValidatorIdOf::convert(who) { + Some(val_id) => val_id, + None => return Err("no associated validator ID for account."), + }; - for i in 0..T::Keys::count() { - let new_key = keys.get_raw(i); - let maybe_old_key = old_keys.as_ref().map(|o| o.get_raw(i)); - if maybe_old_key == Some(new_key) { - // no change. - updates.push(None); - continue; - } - let mut active = >::get(i as u32); - match active.binary_search_by(|k| k[..].cmp(&new_key)) { - Ok(_) => return Err("duplicate key provided"), - Err(pos) => active.insert(pos, new_key.to_owned()), - } - if let Some(old_key) = maybe_old_key { - match active.binary_search_by(|k| k[..].cmp(&old_key)) { - Ok(pos) => { active.remove(pos); } - Err(_) => { - // unreachable as long as our state is valid. we don't want to panic if - // it isn't, though. - print("ERROR: active doesn't contain outgoing key"); - } - } - } - updates.push(Some((i, active))); - } + Self::do_set_keys(&who, keys)?; - // Update the active sets. - for (i, active) in updates.into_iter().filter_map(|x| x) { - >::insert(i as u32, active); - } - // Set new keys value for next session. - >::insert(who, keys); // Something changed. - >::put(true); + Changed::put(true); + + Ok(()) } /// Called when a block is finalized. Will rotate session if it is the last @@ -329,154 +384,199 @@ decl_module! { } impl Module { - /// Move on to next session: register the new authority set. + /// Move on to next session. Register new validator set and session keys. Changes + /// to the validator set have a session of delay to take effect. This allows for + /// equivocation punishment after a fork. pub fn rotate_session() { - // Increment current session index. - let session_index = >::get(); + let session_index = CurrentIndex::get(); + + let changed = QueuedChanged::get(); + let mut next_changed = Changed::take(); + + // Get queued session keys and validators. + let session_keys = >::get(); + let validators = session_keys.iter() + .map(|(validator, _)| validator.clone()) + .collect::>(); + >::put(&validators); - let mut changed = >::take(); + let applied_at = session_index + 2; - // See if we have a new validator set. - let validators = if let Some(new) = T::OnSessionEnding::on_session_ending(session_index) { - changed = true; - >::put(&new); - new + // Get next validator set. + let maybe_validators = T::OnSessionEnding::on_session_ending(session_index, applied_at); + let next_validators = if let Some(validators) = maybe_validators { + next_changed = true; + validators } else { >::get() }; + // Increment session index. let session_index = session_index + 1; - >::put(session_index); + CurrentIndex::put(session_index); + + // Queue next session keys. + let queued_amalgamated = next_validators.into_iter() + .map(|a| { let k = Self::load_keys(&a).unwrap_or_default(); (a, k) }) + .collect::>(); + + >::put(queued_amalgamated); + QueuedChanged::put(next_changed); // Record that this happened. Self::deposit_event(Event::NewSession(session_index)); // Tell everyone about the new session keys. - let amalgamated = validators.into_iter() - .map(|a| { let k = >::get(&a).unwrap_or_default(); (a, k) }) - .collect::>(); - T::SessionHandler::on_new_session::(changed, &amalgamated); + T::SessionHandler::on_new_session::(changed, &session_keys); } /// Disable the validator of index `i`. pub fn disable_index(i: usize) { T::SessionHandler::on_disabled(i); - >::put(true); + Changed::put(true); } /// Disable the validator identified by `c`. (If using with the staking module, this would be - /// their *controller* account.) - pub fn disable(c: &T::AccountId) -> rstd::result::Result<(), ()> { + /// their *stash* account.) + pub fn disable(c: &T::ValidatorId) -> rstd::result::Result<(), ()> { Self::validators().iter().position(|i| i == c).map(Self::disable_index).ok_or(()) } -} -impl OnFreeBalanceZero for Module { - fn on_free_balance_zero(who: &T::AccountId) { - >::remove(who); - } -} + // perform the set_key operation, checking for duplicates. + // does not set `Changed`. + fn do_set_keys(who: &T::ValidatorId, keys: T::Keys) -> Result { + let old_keys = Self::load_keys(&who); -#[cfg(test)] -mod tests { - use super::*; - use std::cell::RefCell; - use srml_support::{impl_outer_origin, assert_ok}; - use runtime_io::with_externalities; - use substrate_primitives::{H256, Blake2Hasher}; - use primitives::BuildStorage; - use primitives::traits::{BlakeTwo256, IdentityLookup, OnInitialize}; - use primitives::testing::{Header, UintAuthorityId}; + for id in T::Keys::key_ids() { + let key = keys.get_raw(id); - impl_outer_origin!{ - pub enum Origin for Test {} - } + // ensure keys are without duplication. + ensure!( + Self::key_owner(id, key).map_or(true, |owner| &owner == who), + "registered duplicate key" + ); - thread_local!{ - static NEXT_VALIDATORS: RefCell> = RefCell::new(vec![1, 2, 3]); - static AUTHORITIES: RefCell> = - RefCell::new(vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); - static FORCE_SESSION_END: RefCell = RefCell::new(false); - static SESSION_LENGTH: RefCell = RefCell::new(2); - } + if let Some(old) = old_keys.as_ref().map(|k| k.get_raw(id)) { + if key == old { + continue; + } + + Self::clear_key_owner(id, old); + } - pub struct TestShouldEndSession; - impl ShouldEndSession for TestShouldEndSession { - fn should_end_session(now: u64) -> bool { - let l = SESSION_LENGTH.with(|l| *l.borrow()); - now % l == 0 || FORCE_SESSION_END.with(|l| { let r = *l.borrow(); *l.borrow_mut() = false; r }) + Self::put_key_owner(id, key, &who); } + + Self::put_keys(&who, &keys); + + Ok(()) } - pub struct TestSessionHandler; - impl SessionHandler for TestSessionHandler { - fn on_new_session(_changed: bool, validators: &[(u64, T)]) { - AUTHORITIES.with(|l| - *l.borrow_mut() = validators.iter().map(|(_, id)| id.get::(0).unwrap_or_default()).collect() - ); + fn prune_dead_keys(who: &T::ValidatorId) { + if let Some(old_keys) = Self::take_keys(who) { + for id in T::Keys::key_ids() { + let key_data = old_keys.get_raw(id); + Self::clear_key_owner(id, key_data); + } + + Changed::put(true); } - fn on_disabled(_validator_index: usize) {} } - pub struct TestOnSessionEnding; - impl OnSessionEnding for TestOnSessionEnding { - fn on_session_ending(_: SessionIndex) -> Option> { - Some(NEXT_VALIDATORS.with(|l| l.borrow().clone())) - } + // Child trie storage. + + fn load_keys(v: &T::ValidatorId) -> Option { + storage::unhashed::get(&dedup_trie_key::(v)) + } + + fn take_keys(v: &T::ValidatorId) -> Option { + storage::unhashed::take(&dedup_trie_key::(v)) } - fn authorities() -> Vec { - AUTHORITIES.with(|l| l.borrow().to_vec()) + fn put_keys(v: &T::ValidatorId, keys: &T::Keys) { + storage::unhashed::put(&dedup_trie_key::(v), keys) } - fn force_new_session() { - FORCE_SESSION_END.with(|l| *l.borrow_mut() = true ) + fn key_owner(id: KeyTypeId, key_data: &[u8]) -> Option { + storage::unhashed::get(&dedup_trie_key::(&(id, key_data))) } - fn set_session_length(x: u64) { - SESSION_LENGTH.with(|l| *l.borrow_mut() = x ) + fn put_key_owner(id: KeyTypeId, key_data: &[u8], v: &T::ValidatorId) { + storage::unhashed::put(&dedup_trie_key::(&(id, key_data)), v); } - #[derive(Clone, Eq, PartialEq)] - pub struct Test; - impl system::Trait for Test { - type Origin = Origin; - type Index = u64; - type BlockNumber = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type Header = Header; - type Event = (); + fn clear_key_owner(id: KeyTypeId, key_data: &[u8]) { + storage::unhashed::kill(&dedup_trie_key::(&(id, key_data))); } - impl timestamp::Trait for Test { - type Moment = u64; - type OnTimestampSet = (); +} + +fn dedup_trie_key(key: &K) -> [u8; 32 + DEDUP_KEY_LEN] { + key.using_encoded(|s| { + // take at most 32 bytes from the hash of the value. + let hash = ::Hashing::hash(s); + let hash: &[u8] = hash.as_ref(); + let len = rstd::cmp::min(hash.len(), 32); + + let mut data = [0; 32 + DEDUP_KEY_LEN]; + data[..DEDUP_KEY_LEN].copy_from_slice(DEDUP_KEY_PREFIX); + data[DEDUP_KEY_LEN..][..len].copy_from_slice(hash); + data + }) +} + +impl OnFreeBalanceZero for Module { + fn on_free_balance_zero(who: &T::ValidatorId) { + Self::prune_dead_keys(who); } - impl Trait for Test { - type ShouldEndSession = TestShouldEndSession; - type OnSessionEnding = TestOnSessionEnding; - type SessionHandler = TestSessionHandler; - type Keys = UintAuthorityId; - type Event = (); +} + +/// Wraps the author-scraping logic for consensus engines that can recover +/// the canonical index of an author. This then transforms it into the +/// registering account-ID of that session key index. +pub struct FindAccountFromAuthorIndex(rstd::marker::PhantomData<(T, Inner)>); + +impl> FindAuthor + for FindAccountFromAuthorIndex +{ + fn find_author<'a, I>(digests: I) -> Option + where I: 'a + IntoIterator + { + let i = Inner::find_author(digests)?; + + let validators = >::validators(); + validators.get(i as usize).map(|k| k.clone()) } +} - type System = system::Module; - type Session = Module; +#[cfg(test)] +mod tests { + use super::*; + use srml_support::assert_ok; + use runtime_io::with_externalities; + use substrate_primitives::Blake2Hasher; + use primitives::{ + traits::OnInitialize, + testing::UintAuthorityId, + }; + use mock::{ + NEXT_VALIDATORS, SESSION_CHANGED, TEST_SESSION_CHANGED, authorities, force_new_session, + set_next_validators, set_session_length, session_changed, Test, Origin, System, Session, + }; fn new_test_ext() -> runtime_io::TestExternalities { - let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; - t.extend(timestamp::GenesisConfig::{ - minimum_period: 5, - }.build_storage().unwrap().0); - t.extend(GenesisConfig::{ - validators: NEXT_VALIDATORS.with(|l| l.borrow().clone()), + let mut t = system::GenesisConfig::default().build_storage::().unwrap(); + GenesisConfig:: { keys: NEXT_VALIDATORS.with(|l| l.borrow().iter().cloned().map(|i| (i, UintAuthorityId(i))).collect() ), - }.build_storage().unwrap().0); - runtime_io::TestExternalities::new(t) + }.assimilate_storage(&mut t.0, &mut t.1).unwrap(); + runtime_io::TestExternalities::new_with_children(t) + } + + fn initialize_block(block: u64) { + SESSION_CHANGED.with(|l| *l.borrow_mut() = false); + System::set_block_number(block); + Session::on_initialize(block); } #[test] @@ -487,32 +587,75 @@ mod tests { }); } + #[test] + fn put_get_keys() { + with_externalities(&mut new_test_ext(), || { + Session::put_keys(&10, &UintAuthorityId(10)); + assert_eq!(Session::load_keys(&10), Some(UintAuthorityId(10))); + }) + } + + #[test] + fn keys_cleared_on_kill() { + let mut ext = new_test_ext(); + with_externalities(&mut ext, || { + assert_eq!(Session::validators(), vec![1, 2, 3]); + assert_eq!(Session::load_keys(&1), Some(UintAuthorityId(1))); + + let id = ::KEY_TYPE; + assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(id)), Some(1)); + + Session::on_free_balance_zero(&1); + assert_eq!(Session::load_keys(&1), None); + assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(id)), None); + + assert!(Changed::get()); + }) + } + #[test] fn authorities_should_track_validators() { with_externalities(&mut new_test_ext(), || { - NEXT_VALIDATORS.with(|v| *v.borrow_mut() = vec![1, 2]); + set_next_validators(vec![1, 2]); force_new_session(); + initialize_block(1); + assert_eq!(Session::queued_keys(), vec![ + (1, UintAuthorityId(1)), + (2, UintAuthorityId(2)), + ]); + assert_eq!(Session::validators(), vec![1, 2, 3]); + assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); - System::set_block_number(1); - Session::on_initialize(1); + force_new_session(); + initialize_block(2); + assert_eq!(Session::queued_keys(), vec![ + (1, UintAuthorityId(1)), + (2, UintAuthorityId(2)), + ]); assert_eq!(Session::validators(), vec![1, 2]); assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2)]); - NEXT_VALIDATORS.with(|v| *v.borrow_mut() = vec![1, 2, 4]); + set_next_validators(vec![1, 2, 4]); assert_ok!(Session::set_keys(Origin::signed(4), UintAuthorityId(4), vec![])); + force_new_session(); + initialize_block(3); + assert_eq!(Session::queued_keys(), vec![ + (1, UintAuthorityId(1)), + (2, UintAuthorityId(2)), + (4, UintAuthorityId(4)), + ]); + assert_eq!(Session::validators(), vec![1, 2]); + assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2)]); force_new_session(); - System::set_block_number(2); - Session::on_initialize(2); + initialize_block(4); + assert_eq!(Session::queued_keys(), vec![ + (1, UintAuthorityId(1)), + (2, UintAuthorityId(2)), + (4, UintAuthorityId(4)), + ]); assert_eq!(Session::validators(), vec![1, 2, 4]); assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(4)]); - - NEXT_VALIDATORS.with(|v| *v.borrow_mut() = vec![1, 2, 3]); - force_new_session(); - System::set_block_number(3); - Session::on_initialize(3); - assert_eq!(Session::validators(), vec![1, 2, 3]); - assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); }); } @@ -521,25 +664,20 @@ mod tests { with_externalities(&mut new_test_ext(), || { set_session_length(10); - System::set_block_number(1); - Session::on_initialize(1); + initialize_block(1); assert_eq!(Session::current_index(), 0); - System::set_block_number(2); - Session::on_initialize(2); + initialize_block(2); assert_eq!(Session::current_index(), 0); - force_new_session(); - System::set_block_number(3); - Session::on_initialize(3); + force_new_session(); + initialize_block(3); assert_eq!(Session::current_index(), 1); - System::set_block_number(9); - Session::on_initialize(9); + initialize_block(9); assert_eq!(Session::current_index(), 1); - System::set_block_number(10); - Session::on_initialize(10); + initialize_block(10); assert_eq!(Session::current_index(), 2); }); } @@ -548,25 +686,108 @@ mod tests { fn session_change_should_work() { with_externalities(&mut new_test_ext(), || { // Block 1: No change - System::set_block_number(1); - Session::on_initialize(1); + initialize_block(1); assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); // Block 2: Session rollover, but no change. - System::set_block_number(2); - Session::on_initialize(2); + initialize_block(2); assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); // Block 3: Set new key for validator 2; no visible change. - System::set_block_number(3); - Session::on_initialize(3); + initialize_block(3); assert_ok!(Session::set_keys(Origin::signed(2), UintAuthorityId(5), vec![])); assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); - // Block 4: Session rollover, authority 2 changes. - System::set_block_number(4); - Session::on_initialize(4); + // Block 4: Session rollover; no visible change. + initialize_block(4); + assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); + + // Block 5: No change. + initialize_block(5); + assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); + + // Block 6: Session rollover; authority 2 changes. + initialize_block(6); assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(5), UintAuthorityId(3)]); }); } + + #[test] + fn duplicates_are_not_allowed() { + with_externalities(&mut new_test_ext(), || { + System::set_block_number(1); + Session::on_initialize(1); + assert!(Session::set_keys(Origin::signed(4), UintAuthorityId(1), vec![]).is_err()); + assert!(Session::set_keys(Origin::signed(1), UintAuthorityId(10), vec![]).is_ok()); + + // is fine now that 1 has migrated off. + assert!(Session::set_keys(Origin::signed(4), UintAuthorityId(1), vec![]).is_ok()); + }); + } + + #[test] + fn session_changed_flag_works() { + with_externalities(&mut new_test_ext(), || { + TEST_SESSION_CHANGED.with(|l| *l.borrow_mut() = true); + + force_new_session(); + initialize_block(1); + assert!(!session_changed()); + + force_new_session(); + initialize_block(2); + assert!(!session_changed()); + + Session::disable_index(0); + force_new_session(); + initialize_block(3); + assert!(!session_changed()); + + force_new_session(); + initialize_block(4); + assert!(session_changed()); + + force_new_session(); + initialize_block(5); + assert!(!session_changed()); + + assert_ok!(Session::set_keys(Origin::signed(2), UintAuthorityId(5), vec![])); + force_new_session(); + initialize_block(6); + assert!(!session_changed()); + + force_new_session(); + initialize_block(7); + assert!(session_changed()); + }); + } + + #[test] + fn periodic_session_works() { + struct Period; + struct Offset; + + impl Get for Period { + fn get() -> u64 { 10 } + } + + impl Get for Offset { + fn get() -> u64 { 3 } + } + + + type P = PeriodicSessions; + + for i in 0..3 { + assert!(!P::should_end_session(i)); + } + + assert!(P::should_end_session(3)); + + for i in (1..10).map(|i| 3 + i) { + assert!(!P::should_end_session(i)); + } + + assert!(P::should_end_session(13)); + } } diff --git a/srml/session/src/mock.rs b/srml/session/src/mock.rs new file mode 100644 index 0000000000000000000000000000000000000000..13d824c807f01d88579e294ee0f1e0c08f621bef --- /dev/null +++ b/srml/session/src/mock.rs @@ -0,0 +1,154 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +//! Mock helpers for Session. + +use super::*; +use std::cell::RefCell; +use srml_support::{impl_outer_origin, parameter_types}; +use substrate_primitives::H256; +use primitives::{ + traits::{BlakeTwo256, IdentityLookup, ConvertInto}, + testing::{Header, UintAuthorityId} +}; + + +impl_outer_origin! { + pub enum Origin for Test {} +} + +thread_local! { + pub static NEXT_VALIDATORS: RefCell> = RefCell::new(vec![1, 2, 3]); + pub static AUTHORITIES: RefCell> = + RefCell::new(vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); + pub static FORCE_SESSION_END: RefCell = RefCell::new(false); + pub static SESSION_LENGTH: RefCell = RefCell::new(2); + pub static SESSION_CHANGED: RefCell = RefCell::new(false); + pub static TEST_SESSION_CHANGED: RefCell = RefCell::new(false); +} + +pub struct TestShouldEndSession; +impl ShouldEndSession for TestShouldEndSession { + fn should_end_session(now: u64) -> bool { + let l = SESSION_LENGTH.with(|l| *l.borrow()); + now % l == 0 || FORCE_SESSION_END.with(|l| { let r = *l.borrow(); *l.borrow_mut() = false; r }) + } +} + +pub struct TestSessionHandler; +impl SessionHandler for TestSessionHandler { + fn on_new_session(changed: bool, validators: &[(u64, T)]) { + SESSION_CHANGED.with(|l| *l.borrow_mut() = changed); + AUTHORITIES.with(|l| + *l.borrow_mut() = validators.iter().map(|(_, id)| id.get::(0).unwrap_or_default()).collect() + ); + } + fn on_disabled(_validator_index: usize) {} +} + +pub struct TestOnSessionEnding; +impl OnSessionEnding for TestOnSessionEnding { + fn on_session_ending(_: SessionIndex, _: SessionIndex) -> Option> { + if !TEST_SESSION_CHANGED.with(|l| *l.borrow()) { + Some(NEXT_VALIDATORS.with(|l| l.borrow().clone())) + } else { + None + } + } +} + +#[cfg(feature = "historical")] +impl crate::historical::OnSessionEnding for TestOnSessionEnding { + fn on_session_ending(_: SessionIndex, _: SessionIndex) + -> Option<(Vec, Vec<(u64, u64)>)> + { + if !TEST_SESSION_CHANGED.with(|l| *l.borrow()) { + let last_validators = Session::validators(); + let last_identifications = last_validators.into_iter().map(|v| (v, v)).collect(); + Some((NEXT_VALIDATORS.with(|l| l.borrow().clone()), last_identifications)) + } else { + None + } + } +} + +pub fn authorities() -> Vec { + AUTHORITIES.with(|l| l.borrow().to_vec()) +} + +pub fn force_new_session() { + FORCE_SESSION_END.with(|l| *l.borrow_mut() = true ) +} + +pub fn set_session_length(x: u64) { + SESSION_LENGTH.with(|l| *l.borrow_mut() = x ) +} + +pub fn session_changed() -> bool { + SESSION_CHANGED.with(|l| *l.borrow()) +} + +pub fn set_next_validators(next: Vec) { + NEXT_VALIDATORS.with(|v| *v.borrow_mut() = next); +} + +#[derive(Clone, Eq, PartialEq)] +pub struct Test; +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MinimumPeriod: u64 = 5; +} +impl system::Trait for Test { + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = (); + type BlockHashCount = BlockHashCount; +} +impl timestamp::Trait for Test { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = MinimumPeriod; +} + + +impl Trait for Test { + type ShouldEndSession = TestShouldEndSession; + #[cfg(feature = "historical")] + type OnSessionEnding = crate::historical::NoteHistoricalRoot; + #[cfg(not(feature = "historical"))] + type OnSessionEnding = TestOnSessionEnding; + type SessionHandler = TestSessionHandler; + type ValidatorId = u64; + type ValidatorIdOf = ConvertInto; + type Keys = UintAuthorityId; + type Event = (); + type SelectInitialValidators = (); +} + +#[cfg(feature = "historical")] +impl crate::historical::Trait for Test { + type FullIdentification = u64; + type FullIdentificationOf = primitives::traits::ConvertInto; +} + +pub type System = system::Module; +pub type Session = Module; diff --git a/srml/staking/Cargo.toml b/srml/staking/Cargo.toml index 1b95f30f32350b4135c85860c0d4ebd37dfef1ac..74384495315cc536b150779752c53174c4c97248 100644 --- a/srml/staking/Cargo.toml +++ b/srml/staking/Cargo.toml @@ -7,14 +7,14 @@ edition = "2018" [dependencies] serde = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false} -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } substrate-keyring = { path = "../../core/keyring", optional = true } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } runtime_io = { package = "sr-io", path = "../../core/sr-io", default-features = false } primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } srml-support = { path = "../support", default-features = false } system = { package = "srml-system", path = "../system", default-features = false } -session = { package = "srml-session", path = "../session", default-features = false } +session = { package = "srml-session", path = "../session", default-features = false, features = ["historical"] } [dev-dependencies] substrate-primitives = { path = "../../core/primitives" } @@ -23,8 +23,9 @@ balances = { package = "srml-balances", path = "../balances" } rand = "0.6.5" [features] +equalize = [] bench = [] -default = ["std"] +default = ["std", "equalize"] std = [ "serde", "safe-mix/std", diff --git a/srml/staking/src/benches.rs b/srml/staking/src/benches.rs index e3ee00b9e94802658a05364b1b0b34a1ceee79ff..6e79ee70a47a26dedd201494e5e92adfb8943293 100644 --- a/srml/staking/src/benches.rs +++ b/srml/staking/src/benches.rs @@ -35,7 +35,15 @@ const EDGES: u64 = 2; const TO_ELECT: usize = 100; const STAKE: u64 = 1000; -fn do_phragmen(b: &mut Bencher, num_vals: u64, num_noms: u64, count: usize, votes_per: u64) { +fn do_phragmen( + b: &mut Bencher, + num_vals: u64, + num_noms: u64, + count: usize, + votes_per: u64, + eq_iters: usize, + eq_tolerance: u128, +) { with_externalities(&mut ExtBuilder::default().nominate(false).build(), || { assert!(num_vals > votes_per); let rr = |a, b| rand::thread_rng().gen_range(a as usize, b as usize) as u64; @@ -53,62 +61,135 @@ fn do_phragmen(b: &mut Bencher, num_vals: u64, num_noms: u64, count: usize, vote let mut stashes_to_vote = (1 ..= 2*num_vals) .step_by(2) .map(|ctrl| ctrl + 1) - .collect::>(); + .collect::>(); let votes = (0 .. votes_per) .map(|_| { stashes_to_vote.remove(rr(0, stashes_to_vote.len()) as usize) }) - .collect::>(); + .collect::>(); bond_nominator(acc, STAKE + rr(10, 50), votes); }); b.iter(|| { - let _ = phragmen::elect::( + let r = phragmen::elect::( count, 1_usize, >::enumerate(), >::enumerate(), Staking::slashable_balance_of - ); + ).unwrap(); + + // Do the benchmarking with equalize. + if eq_iters > 0 { + let elected_stashes = r.0; + let assignments = r.1; + + let to_balance = |b: ExtendedBalance| + <::CurrencyToVote as Convert>::convert(b); + let to_votes = |b: Balance| + <::CurrencyToVote as Convert>::convert(b) as ExtendedBalance; + let ratio_of = |b, p| (p as ExtendedBalance).saturating_mul(to_votes(b)) / ACCURACY; + + let assignments_with_stakes = assignments.into_iter().map(|(n, a)|( + n, + Staking::slashable_balance_of(&n), + a.into_iter().map(|(acc, r)| ( + acc.clone(), + r, + to_balance(ratio_of(Staking::slashable_balance_of(&n), r)), + )) + .collect::>>() + )).collect::>)>>(); + + let mut exposures = >::new(); + elected_stashes + .into_iter() + .map(|e| (e, Staking::slashable_balance_of(&e))) + .for_each(|(e, s)| { + let item = Exposure { own: s, total: s, ..Default::default() }; + exposures.insert(e, item); + }); + + for (n, _, assignment) in &assignments_with_stakes { + for (c, _, s) in assignment { + if let Some(expo) = exposures.get_mut(c) { + expo.total = expo.total.saturating_add(*s); + expo.others.push( IndividualExposure { who: n.clone(), value: *s } ); + } + } + } + + let mut assignments_with_votes = assignments_with_stakes.into_iter() + .map(|a| ( + a.0, a.1, + a.2.into_iter() + .map(|e| (e.0, e.1, to_votes(e.2))) + .collect::>() + )) + .collect:: + )>>(); + equalize::(&mut assignments_with_votes, &mut exposures, eq_tolerance, eq_iters); + } }) }) } macro_rules! phragmen_benches { ($($name:ident: $tup:expr,)*) => { - $( + $( #[bench] fn $name(b: &mut Bencher) { - let (v, n, t, e) = $tup; + let (v, n, t, e, eq_iter, eq_tol) = $tup; println!(""); println!( - "++ Benchmark: {} Validators // {} Nominators // {} Edges-per-nominator // {} total edges // electing {}", - v, n, e, e * n, t + r#" +++ Benchmark: {} Validators // {} Nominators // {} Edges-per-nominator // {} total edges // +electing {} // Equalize: {} iterations -- {} tolerance"#, + v, n, e, e * n, t, eq_iter, eq_tol, ); - do_phragmen(b, v, n, t, e); + do_phragmen(b, v, n, t, e, eq_iter, eq_tol); } )* } } phragmen_benches! { - bench_1_1: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES), - bench_1_2: (VALIDATORS*2, NOMINATORS, TO_ELECT, EDGES), - bench_1_3: (VALIDATORS*4, NOMINATORS, TO_ELECT, EDGES), - bench_1_4: (VALIDATORS*8, NOMINATORS, TO_ELECT, EDGES), - - bench_0_1: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES), - bench_0_2: (VALIDATORS, NOMINATORS, TO_ELECT * 4, EDGES), - bench_0_3: (VALIDATORS, NOMINATORS, TO_ELECT * 8, EDGES), - bench_0_4: (VALIDATORS, NOMINATORS, TO_ELECT * 16, EDGES), - - bench_2_1: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES), - bench_2_2: (VALIDATORS, NOMINATORS*2, TO_ELECT, EDGES), - bench_2_3: (VALIDATORS, NOMINATORS*4, TO_ELECT, EDGES), - bench_2_4: (VALIDATORS, NOMINATORS*8, TO_ELECT, EDGES), - - bench_3_1: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES), - bench_3_2: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES*2), - bench_3_3: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES*4), - bench_3_4: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES*8), + bench_1_1: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES, 0, 0), + bench_1_2: (VALIDATORS*2, NOMINATORS, TO_ELECT, EDGES, 0, 0), + bench_1_3: (VALIDATORS*4, NOMINATORS, TO_ELECT, EDGES, 0, 0), + bench_1_4: (VALIDATORS*8, NOMINATORS, TO_ELECT, EDGES, 0, 0), + bench_1_1_eq: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES, 2, 0), + bench_1_2_eq: (VALIDATORS*2, NOMINATORS, TO_ELECT, EDGES, 2, 0), + bench_1_3_eq: (VALIDATORS*4, NOMINATORS, TO_ELECT, EDGES, 2, 0), + bench_1_4_eq: (VALIDATORS*8, NOMINATORS, TO_ELECT, EDGES, 2, 0), + + bench_0_1: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES, 0, 0), + bench_0_2: (VALIDATORS, NOMINATORS, TO_ELECT * 4, EDGES, 0, 0), + bench_0_3: (VALIDATORS, NOMINATORS, TO_ELECT * 8, EDGES, 0, 0), + bench_0_4: (VALIDATORS, NOMINATORS, TO_ELECT * 16, EDGES , 0, 0), + bench_0_1_eq: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES, 2, 0), + bench_0_2_eq: (VALIDATORS, NOMINATORS, TO_ELECT * 4, EDGES, 2, 0), + bench_0_3_eq: (VALIDATORS, NOMINATORS, TO_ELECT * 8, EDGES, 2, 0), + bench_0_4_eq: (VALIDATORS, NOMINATORS, TO_ELECT * 16, EDGES , 2, 0), + + bench_2_1: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES, 0, 0), + bench_2_2: (VALIDATORS, NOMINATORS*2, TO_ELECT, EDGES, 0, 0), + bench_2_3: (VALIDATORS, NOMINATORS*4, TO_ELECT, EDGES, 0, 0), + bench_2_4: (VALIDATORS, NOMINATORS*8, TO_ELECT, EDGES, 0, 0), + bench_2_1_eq: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES, 2, 0), + bench_2_2_eq: (VALIDATORS, NOMINATORS*2, TO_ELECT, EDGES, 2, 0), + bench_2_3_eq: (VALIDATORS, NOMINATORS*4, TO_ELECT, EDGES, 2, 0), + bench_2_4_eq: (VALIDATORS, NOMINATORS*8, TO_ELECT, EDGES, 2, 0), + + bench_3_1: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES, 0, 0 ), + bench_3_2: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES*2, 0, 0), + bench_3_3: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES*4, 0, 0), + bench_3_4: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES*8, 0, 0), + bench_3_1_eq: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES, 2, 0), + bench_3_2_eq: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES*2, 2, 0), + bench_3_3_eq: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES*4, 2, 0), + bench_3_4_eq: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES*8, 2, 0), } diff --git a/srml/staking/src/lib.rs b/srml/staking/src/lib.rs index 086f78bd53379f0c36312ad1aa7f553e0fdec10a..7dfe7b60e9f03ed9513a8171de0c08cc19a604b0 100644 --- a/srml/staking/src/lib.rs +++ b/srml/staking/src/lib.rs @@ -278,19 +278,19 @@ use srml_support::{ StorageValue, StorageMap, EnumerableStorageMap, decl_module, decl_event, decl_storage, ensure, traits::{ Currency, OnFreeBalanceZero, OnDilution, LockIdentifier, LockableCurrency, - WithdrawReasons, OnUnbalanced, Imbalance, Get + WithdrawReasons, WithdrawReason, OnUnbalanced, Imbalance, Get } }; -use session::{OnSessionEnding, SessionIndex}; +use session::{historical::OnSessionEnding, SelectInitialValidators, SessionIndex}; use primitives::Perbill; use primitives::traits::{ - Convert, Zero, One, StaticLookup, CheckedSub, CheckedShl, Saturating, Bounded + Convert, Zero, One, StaticLookup, CheckedSub, CheckedShl, Saturating, Bounded, }; #[cfg(feature = "std")] use primitives::{Serialize, Deserialize}; -use system::ensure_signed; +use system::{ensure_signed, ensure_root}; -use phragmen::{elect, ACCURACY, ExtendedBalance}; +use phragmen::{elect, ACCURACY, ExtendedBalance, equalize}; const RECENT_OFFLINE_COUNT: usize = 32; const DEFAULT_MINIMUM_VALIDATOR_COUNT: u32 = 4; @@ -442,7 +442,46 @@ type ExpoMap = BTreeMap< Exposure<::AccountId, BalanceOf> >; -pub trait Trait: system::Trait + session::Trait { +pub const DEFAULT_SESSIONS_PER_ERA: u32 = 3; +pub const DEFAULT_BONDING_DURATION: u32 = 1; + +/// Means for interacting with a specialized version of the `session` trait. +/// +/// This is needed because `Staking` sets the `ValidatorId` of the `session::Trait` +pub trait SessionInterface: system::Trait { + /// Disable a given validator by stash ID. + fn disable_validator(validator: &AccountId) -> Result<(), ()>; + /// Get the validators from session. + fn validators() -> Vec; + /// Prune historical session tries up to but not including the given index. + fn prune_historical_up_to(up_to: session::SessionIndex); +} + +impl SessionInterface<::AccountId> for T where + T: session::Trait::AccountId>, + T: session::historical::Trait< + FullIdentification = Exposure<::AccountId, BalanceOf>, + FullIdentificationOf = ExposureOf, + >, + T::SessionHandler: session::SessionHandler<::AccountId>, + T::OnSessionEnding: session::OnSessionEnding<::AccountId>, + T::SelectInitialValidators: session::SelectInitialValidators<::AccountId>, + T::ValidatorIdOf: Convert<::AccountId, Option<::AccountId>> +{ + fn disable_validator(validator: &::AccountId) -> Result<(), ()> { + >::disable(validator) + } + + fn validators() -> Vec<::AccountId> { + >::validators() + } + + fn prune_historical_up_to(up_to: session::SessionIndex) { + >::prune_up_to(up_to); + } +} + +pub trait Trait: system::Trait { /// The staking balance. type Currency: LockableCurrency; @@ -470,6 +509,9 @@ pub trait Trait: system::Trait + session::Trait { /// Number of eras that staked funds must remain bonded for. type BondingDuration: Get; + + /// Interface for interacting with a session module. + type SessionInterface: self::SessionInterface; } decl_storage! { @@ -513,15 +555,6 @@ decl_storage! { /// This is keyed by the stash account. pub Stakers get(stakers): map T::AccountId => Exposure>; - // The historical validators and their nominations for a given era. Stored as a trie root - // of the mapping `T::AccountId` => `Exposure>`, which is just - // the contents of `Stakers`, under a key that is the `era`. - // - // Every era change, this will be appended with the trie root of the contents of `Stakers`, - // and the oldest entry removed down to a specific number of entries (probably around 90 for - // a 3 month history). - // pub HistoricalStakers get(historical_stakers): map T::BlockNumber => Option; - /// The currently elected validator set keyed by stash account ID. pub CurrentElected get(current_elected): Vec; @@ -552,6 +585,9 @@ decl_storage! { /// True if the next session change will be a new era regardless of index. pub ForceNewEra get(forcing_new_era): bool; + + /// A mapping from still-bonded eras to the first session index of that era. + BondedEras: Vec<(EraIndex, SessionIndex)>; } add_extra_genesis { config(stakers): @@ -563,7 +599,10 @@ decl_storage! { | { with_storage(storage, || { for &(ref stash, ref controller, balance, ref status) in &config.stakers { - assert!(T::Currency::free_balance(&stash) >= balance); + assert!( + T::Currency::free_balance(&stash) >= balance, + "Stash does not have enough balance to bond." + ); let _ = >::bond( T::Origin::from(Some(stash.clone()).into()), T::Lookup::unlookup(controller.clone()), @@ -584,10 +623,6 @@ decl_storage! { }, _ => Ok(()) }; } - - if let (_, Some(validators)) = >::select_validators() { - >::put(&validators); - } }); }); } @@ -607,10 +642,18 @@ decl_event!( decl_module! { pub struct Module for enum Call where origin: T::Origin { + /// Number of sessions per era. + const SessionsPerEra: SessionIndex = T::SessionsPerEra::get(); + + /// Number of eras that staked funds must remain bonded for. + const BondingDuration: EraIndex = T::BondingDuration::get(); + fn deposit_event() = default; /// Take the origin account as a stash and lock up `value` of its balance. `controller` will - /// be the account that controls it. + /// be the account that controls it. + /// + /// `value` must be more than the `existential_deposit` defined in the Balances module. /// /// The dispatch origin for this call must be _Signed_ by the stash account. /// @@ -621,10 +664,6 @@ decl_module! { /// /// NOTE: Two of the storage writes (`Self::bonded`, `Self::payee`) are _never_ cleaned unless /// the `origin` falls below _existential deposit_ and gets removed as dust. - /// - /// NOTE: At the moment, there are no financial restrictions to bond - /// (which creates a bunch of storage items for an account). In essence, nothing prevents many accounts from - /// spamming `Staking` storage by bonding 1 UNIT. See test case: `bond_with_no_staked_value`. /// # fn bond(origin, controller: ::Source, @@ -643,6 +682,11 @@ decl_module! { return Err("controller already paired") } + // reject a bond which is considered to be _dust_. + if value < T::Currency::minimum_balance() { + return Err("can not bond with value less than minimum balance") + } + // You're auto-bonded forever, here. We might improve this by only bonding when // you actually validate/nominate and remove once you unbond __everything__. >::insert(&stash, controller.clone()); @@ -655,9 +699,11 @@ decl_module! { } /// Add some extra amount that have appeared in the stash `free_balance` into the balance up - /// for staking. + /// for staking. /// /// Use this if there are additional funds in your stash account that you wish to bond. + /// Unlike [`bond`] or [`unbond`] this function does not impose any limitation on the amount + /// that can be added. /// /// The dispatch origin for this call must be _Signed_ by the stash, not the controller. /// @@ -740,9 +786,9 @@ decl_module! { /// See also [`Call::unbond`]. /// /// # - /// - Could be dependent on the `origin` argument and how much `unlocking` chunks exist. It implies - /// `consolidate_unlocked` which loops over `Ledger.unlocking`, which is indirectly - /// user-controlled. See [`unbond`] for more detail. + /// - Could be dependent on the `origin` argument and how much `unlocking` chunks exist. + /// It implies `consolidate_unlocked` which loops over `Ledger.unlocking`, which is + /// indirectly user-controlled. See [`unbond`] for more detail. /// - Contains a limited number of reads, yet the size of which could be large based on `ledger`. /// - Writes are limited to the `origin` account key. /// # @@ -750,7 +796,20 @@ decl_module! { let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or("not a controller")?; let ledger = ledger.consolidate_unlocked(Self::current_era()); - Self::update_ledger(&controller, &ledger); + + if ledger.unlocking.is_empty() && ledger.active.is_zero() { + // This account must have called `unbond()` with some value that caused the active + // portion to fall below existential deposit + will have no more unlocking chunks + // left. We can now safely remove this. + let stash = ledger.stash; + // remove the lock. + T::Currency::remove_lock(STAKING_ID, &stash); + // remove all staking-related information. + Self::kill_stash(&stash); + } else { + // This was the consequence of a partial unbond. just update the ledger and move on. + Self::update_ledger(&controller, &ledger); + } } /// Declare the desire to validate for the origin controller. @@ -865,8 +924,9 @@ decl_module! { } /// The ideal number of validators. - fn set_validator_count(#[compact] new: u32) { - >::put(new); + fn set_validator_count(origin, #[compact] new: u32) { + ensure_root(origin)?; + ValidatorCount::put(new); } // ----- Root calls. @@ -879,17 +939,20 @@ decl_module! { /// - Triggers the Phragmen election. Expensive but not user-controlled. /// - Depends on state: `O(|edges| * |validators|)`. /// # - fn force_new_era() { + fn force_new_era(origin) { + ensure_root(origin)?; Self::apply_force_new_era() } /// Set the offline slash grace period. - fn set_offline_slash_grace(#[compact] new: u32) { - >::put(new); + fn set_offline_slash_grace(origin, #[compact] new: u32) { + ensure_root(origin)?; + OfflineSlashGrace::put(new); } /// Set the validators who cannot be slashed (if any). - fn set_invulnerables(validators: Vec) { + fn set_invulnerables(origin, validators: Vec) { + ensure_root(origin)?; >::put(validators); } } @@ -906,7 +969,8 @@ impl Module { // MUTABLES (DANGEROUS) - /// Update the ledger for a controller. This will also update the stash lock. + /// Update the ledger for a controller. This will also update the stash lock. The lock will + /// will lock the entire funds except paying for further transactions. fn update_ledger( controller: &T::AccountId, ledger: &StakingLedger> @@ -916,7 +980,7 @@ impl Module { &ledger.stash, ledger.total, T::BlockNumber::max_value(), - WithdrawReasons::all() + WithdrawReasons::except(WithdrawReason::TransactionPayment), ); >::insert(controller, ledger); } @@ -940,11 +1004,10 @@ impl Module { // The total to be slashed from the nominators. let total = exposure.total - exposure.own; if !total.is_zero() { - // FIXME #1572 avoid overflow - let safe_mul_rational = |b| b * rest_slash / total; for i in exposure.others.iter() { + let per_u64 = Perbill::from_rational_approximation(i.value, total); // best effort - not much that can be done on fail. - imbalance.subsume(T::Currency::slash(&i.who, safe_mul_rational(i.value)).0) + imbalance.subsume(T::Currency::slash(&i.who, per_u64 * rest_slash).0) } } } @@ -986,26 +1049,35 @@ impl Module { } else { let exposure = Self::stakers(stash); let total = exposure.total.max(One::one()); - // FIXME #1572: avoid overflow - let safe_mul_rational = |b| b * reward / total; + for i in &exposure.others { - let nom_payout = safe_mul_rational(i.value); - imbalance.maybe_subsume(Self::make_payout(&i.who, nom_payout)); + let per_u64 = Perbill::from_rational_approximation(i.value, total); + imbalance.maybe_subsume(Self::make_payout(&i.who, per_u64 * reward)); } - safe_mul_rational(exposure.own) + + let per_u64 = Perbill::from_rational_approximation(exposure.own, total); + per_u64 * reward }; imbalance.maybe_subsume(Self::make_payout(stash, validator_cut + off_the_table)); T::Reward::on_unbalanced(imbalance); } - /// Session has just ended. Provide the validator set for the next session if it's an era-end. - fn new_session(session_index: SessionIndex) -> Option> { + /// Session has just ended. Provide the validator set for the next session if it's an era-end, along + /// with the exposure of the prior validator set. + fn new_session(session_index: SessionIndex) + -> Option<(Vec, Vec<(T::AccountId, Exposure>)>)> + { // accumulate good session reward let reward = Self::current_session_reward(); >::mutate(|r| *r += reward); - if >::take() || session_index % T::SessionsPerEra::get() == 0 { - Self::new_era() + if ForceNewEra::take() || session_index % T::SessionsPerEra::get() == 0 { + let validators = T::SessionInterface::validators(); + let prior = validators.into_iter() + .map(|v| { let e = Self::stakers(&v); (v, e) }) + .collect(); + + Self::new_era(session_index).map(move |new| (new, prior)) } else { None } @@ -1015,7 +1087,7 @@ impl Module { /// /// NOTE: This always happens immediately before a session change to ensure that new validators /// get a chance to set their session keys. - fn new_era() -> Option> { + fn new_era(start_session_index: SessionIndex) -> Option> { // Payout let reward = >::take(); if !reward.is_zero() { @@ -1032,7 +1104,26 @@ impl Module { } // Increment current era. - >::mutate(|s| *s += 1); + let current_era = CurrentEra::mutate(|s| { *s += 1; *s }); + let bonding_duration = T::BondingDuration::get(); + + if current_era > bonding_duration { + let first_kept = current_era - bonding_duration; + BondedEras::mutate(|bonded| { + bonded.push((current_era, start_session_index)); + + // prune out everything that's from before the first-kept index. + let n_to_prune = bonded.iter() + .take_while(|&&(era_idx, _)| era_idx < first_kept) + .count(); + + bonded.drain(..n_to_prune); + + if let Some(&(_, first_session)) = bonded.first() { + T::SessionInterface::prune_historical_up_to(first_session); + } + }) + } // Reassign all Stakers. let (slot_stake, maybe_new_validators) = Self::select_validators(); @@ -1049,7 +1140,7 @@ impl Module { /// Select a new validator set from the assembled stakers and their role preferences. /// - /// Returns the new `SlotStake` value. + /// Returns the new `SlotStake` value and a set of newly selected _stash_ IDs. fn select_validators() -> (BalanceOf, Option>) { let maybe_elected_set = elect::( Self::validator_count() as usize, @@ -1077,7 +1168,7 @@ impl Module { let ratio_of = |b, p| (p as ExtendedBalance).saturating_mul(to_votes(b)) / ACCURACY; // Compute the actual stake from nominator's ratio. - let mut assignments_with_stakes = assignments.iter().map(|(n, a)|( + let assignments_with_stakes = assignments.iter().map(|(n, a)|( n.clone(), Self::slashable_balance_of(n), a.iter().map(|(acc, r)| ( @@ -1111,17 +1202,22 @@ impl Module { } } - // This optimization will most likely be only applied off-chain. - let do_equalize = false; - if do_equalize { - let tolerance = 10 as u128; - let iterations = 10 as usize; - phragmen::equalize::( - &mut assignments_with_stakes, - &mut exposures, - tolerance, - iterations - ); + if cfg!(feature = "equalize") { + let tolerance = 0_u128; + let iterations = 2_usize; + let mut assignments_with_votes = assignments_with_stakes.iter() + .map(|a| ( + a.0.clone(), a.1, + a.2.iter() + .map(|e| (e.0.clone(), e.1, to_votes(e.2))) + .collect::>() + )) + .collect::, + Vec<(T::AccountId, ExtendedBalance, ExtendedBalance)> + )>>(); + equalize::(&mut assignments_with_votes, &mut exposures, tolerance, iterations); } // Clear Stakers and reduce their slash_count. @@ -1141,14 +1237,14 @@ impl Module { } >::insert(c.clone(), e.clone()); } + + // Update slot stake. >::put(&slot_stake); - // Set the new validator set. + // Set the new validator set in sessions. >::put(&elected_stashes); - let validators = elected_stashes.into_iter() - .map(|s| Self::bonded(s).unwrap_or_default()) - .collect::>(); - (slot_stake, Some(validators)) + + (slot_stake, Some(elected_stashes)) } else { // There were not enough candidates for even our minimal level of functionality. // This is bad. @@ -1161,7 +1257,22 @@ impl Module { } fn apply_force_new_era() { - >::put(true); + ForceNewEra::put(true); + } + + /// Remove all associated data of a stash account from the staking system. + /// + /// This is called : + /// - Immediately when an account's balance falls below existential deposit. + /// - after a `withdraw_unbond()` call that frees all of a stash's bonded balance. + fn kill_stash(stash: &T::AccountId) { + if let Some(controller) = >::take(stash) { + >::remove(&controller); + } + >::remove(stash); + >::remove(stash); + >::remove(stash); + >::remove(stash); } /// Call when a validator is determined to be offline. `count` is the @@ -1210,7 +1321,7 @@ impl Module { .map(|x| x.min(slash_exposure)) .unwrap_or(slash_exposure); let _ = Self::slash_validator(&stash, slash); - let _ = >::disable(&controller); + let _ = T::SessionInterface::disable_validator(&stash); RawEvent::OfflineSlash(stash.clone(), slash) } else { @@ -1222,20 +1333,50 @@ impl Module { } } -impl OnSessionEnding for Module { - fn on_session_ending(i: SessionIndex) -> Option> { - Self::new_session(i + 1) +impl session::OnSessionEnding for Module { + fn on_session_ending(_ending: SessionIndex, start_session: SessionIndex) -> Option> { + Self::new_session(start_session - 1).map(|(new, _old)| new) + } +} + +impl OnSessionEnding>> for Module { + fn on_session_ending(_ending: SessionIndex, start_session: SessionIndex) + -> Option<(Vec, Vec<(T::AccountId, Exposure>)>)> + { + Self::new_session(start_session - 1) } } impl OnFreeBalanceZero for Module { fn on_free_balance_zero(stash: &T::AccountId) { - if let Some(controller) = >::take(stash) { - >::remove(&controller); - } - >::remove(stash); - >::remove(stash); - >::remove(stash); - >::remove(stash); + Self::kill_stash(stash); + } +} + +/// A `Convert` implementation that finds the stash of the given controller account, +/// if any. +pub struct StashOf(rstd::marker::PhantomData); + +impl Convert> for StashOf { + fn convert(controller: T::AccountId) -> Option { + >::ledger(&controller).map(|l| l.stash) + } +} + +/// A typed conversion from stash account ID to the current exposure of nominators +/// on that account. +pub struct ExposureOf(rstd::marker::PhantomData); + +impl Convert>>> + for ExposureOf +{ + fn convert(validator: T::AccountId) -> Option>> { + Some(>::stakers(&validator)) + } +} + +impl SelectInitialValidators for Module { + fn select_initial_validators() -> Option> { + >::select_validators().1 } } diff --git a/srml/staking/src/mock.rs b/srml/staking/src/mock.rs index ea4fcbd8f9f012995875ec0a58baf3420fd73655..246b6f96be7f396816d3ac257f21af8ddcf51e0e 100644 --- a/srml/staking/src/mock.rs +++ b/srml/staking/src/mock.rs @@ -17,17 +17,21 @@ //! Test utilities use std::{collections::HashSet, cell::RefCell}; -use primitives::{BuildStorage, Perbill}; +use primitives::Perbill; use primitives::traits::{IdentityLookup, Convert, OpaqueKeys, OnInitialize}; use primitives::testing::{Header, UintAuthorityId}; use substrate_primitives::{H256, Blake2Hasher}; use runtime_io; -use srml_support::{impl_outer_origin, parameter_types, assert_ok, traits::Currency}; -use crate::{EraIndex, GenesisConfig, Module, Trait, StakerStatus, ValidatorPrefs, RewardDestination}; +use srml_support::{assert_ok, impl_outer_origin, parameter_types, EnumerableStorageMap}; +use srml_support::traits::{Currency, Get}; +use crate::{EraIndex, GenesisConfig, Module, Trait, StakerStatus, + ValidatorPrefs, RewardDestination, Nominators +}; /// The AccountId alias in this test module. pub type AccountId = u64; pub type BlockNumber = u64; +pub type Balance = u64; /// Simple structure that exposes how u64 currency can be represented as... u64. pub struct CurrencyToVoteHandler; @@ -42,6 +46,7 @@ impl Convert for CurrencyToVoteHandler { thread_local! { static SESSION: RefCell<(Vec, HashSet)> = RefCell::new(Default::default()); + static EXISTENTIAL_DEPOSIT: RefCell = RefCell::new(0); } pub struct TestSessionHandler; @@ -56,14 +61,21 @@ impl session::SessionHandler for TestSessionHandler { SESSION.with(|d| { let mut d = d.borrow_mut(); let value = d.0[validator_index]; - println!("on_disabled {} -> {}", validator_index, value); d.1.insert(value); }) } } pub fn is_disabled(validator: AccountId) -> bool { - SESSION.with(|d| d.borrow().1.contains(&validator)) + let stash = Staking::ledger(&validator).unwrap().stash; + SESSION.with(|d| d.borrow().1.contains(&stash)) +} + +pub struct ExistentialDeposit; +impl Get for ExistentialDeposit { + fn get() -> u64 { + EXISTENTIAL_DEPOSIT.with(|v| *v.borrow()) + } } impl_outer_origin!{ @@ -73,6 +85,9 @@ impl_outer_origin!{ // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, PartialEq, Eq, Debug)] pub struct Test; +parameter_types! { + pub const BlockHashCount: u64 = 250; +} impl system::Trait for Test { type Origin = Origin; type Index = u64; @@ -83,30 +98,55 @@ impl system::Trait for Test { type Lookup = IdentityLookup; type Header = Header; type Event = (); + type BlockHashCount = BlockHashCount; +} +parameter_types! { + pub const TransferFee: u64 = 0; + pub const CreationFee: u64 = 0; + pub const TransactionBaseFee: u64 = 0; + pub const TransactionByteFee: u64 = 0; } impl balances::Trait for Test { - type Balance = u64; + type Balance = Balance; type OnFreeBalanceZero = Staking; type OnNewAccount = (); type Event = (); type TransactionPayment = (); type TransferPayment = (); type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type TransferFee = TransferFee; + type CreationFee = CreationFee; + type TransactionBaseFee = TransactionBaseFee; + type TransactionByteFee = TransactionByteFee; } parameter_types! { pub const Period: BlockNumber = 1; pub const Offset: BlockNumber = 0; } impl session::Trait for Test { - type OnSessionEnding = Staking; + type OnSessionEnding = session::historical::NoteHistoricalRoot; type Keys = UintAuthorityId; type ShouldEndSession = session::PeriodicSessions; type SessionHandler = TestSessionHandler; type Event = (); + type ValidatorId = AccountId; + type ValidatorIdOf = crate::StashOf; + type SelectInitialValidators = Staking; +} + +impl session::historical::Trait for Test { + type FullIdentification = crate::Exposure; + type FullIdentificationOf = crate::ExposureOf; +} + +parameter_types! { + pub const MinimumPeriod: u64 = 5; } impl timestamp::Trait for Test { type Moment = u64; type OnTimestampSet = (); + type MinimumPeriod = MinimumPeriod; } parameter_types! { pub const SessionsPerEra: session::SessionIndex = 3; @@ -121,30 +161,31 @@ impl Trait for Test { type Reward = (); type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; + type SessionInterface = Self; } pub struct ExtBuilder { existential_deposit: u64, - current_era: EraIndex, reward: u64, validator_pool: bool, nominate: bool, validator_count: u32, minimum_validator_count: u32, fair: bool, + num_validators: Option, } impl Default for ExtBuilder { fn default() -> Self { Self { existential_deposit: 0, - current_era: 0, reward: 10, validator_pool: false, nominate: true, validator_count: 2, minimum_validator_count: 0, - fair: true + fair: true, + num_validators: None, } } } @@ -154,10 +195,6 @@ impl ExtBuilder { self.existential_deposit = existential_deposit; self } - pub fn _current_era(mut self, current_era: EraIndex) -> Self { - self.current_era = current_era; - self - } pub fn validator_pool(mut self, validator_pool: bool) -> Self { self.validator_pool = validator_pool; self @@ -178,19 +215,27 @@ impl ExtBuilder { self.fair = is_fair; self } + pub fn num_validators(mut self, num_validators: u32) -> Self { + self.num_validators = Some(num_validators); + self + } + pub fn set_associated_consts(&self) { + EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit); + } pub fn build(self) -> runtime_io::TestExternalities { - let (mut t, mut c) = system::GenesisConfig::::default().build_storage().unwrap(); + self.set_associated_consts(); + let (mut t, mut c) = system::GenesisConfig::default().build_storage::().unwrap(); let balance_factor = if self.existential_deposit > 0 { 256 } else { 1 }; - let validators = if self.validator_pool { vec![10, 20, 30, 40] } else { vec![10, 20] }; - let _ = session::GenesisConfig::{ - // NOTE: if config.nominate == false then 100 is also selected in the initial round. - validators, - keys: vec![], - }.assimilate_storage(&mut t, &mut c); + + let num_validators = self.num_validators.unwrap_or(self.validator_count); + let validators = (0..num_validators) + .map(|x| ((x + 1) * 10 + 1) as u64) + .collect::>(); + let _ = balances::GenesisConfig::{ balances: vec![ (1, 10 * balance_factor), @@ -208,13 +253,9 @@ impl ExtBuilder { (100, 2000 * balance_factor), (101, 2000 * balance_factor), ], - transaction_base_fee: 0, - transaction_byte_fee: 0, - existential_deposit: self.existential_deposit, - transfer_fee: 0, - creation_fee: 0, vesting: vec![], }.assimilate_storage(&mut t, &mut c); + let stake_21 = if self.fair { 1000 } else { 2000 }; let stake_31 = if self.validator_pool { balance_factor * 1000 } else { 1 }; let status_41 = if self.validator_pool { @@ -224,7 +265,7 @@ impl ExtBuilder { }; let nominated = if self.nominate { vec![11, 21] } else { vec![] }; let _ = GenesisConfig::{ - current_era: self.current_era, + current_era: 0, stakers: vec![ (11, 10, balance_factor * 1000, StakerStatus::::Validator), (21, 20, stake_21, StakerStatus::::Validator), @@ -241,9 +282,11 @@ impl ExtBuilder { offline_slash_grace: 0, invulnerables: vec![], }.assimilate_storage(&mut t, &mut c); - let _ = timestamp::GenesisConfig::{ - minimum_period: 5, + + let _ = session::GenesisConfig:: { + keys: validators.iter().map(|x| (*x, UintAuthorityId(*x))).collect(), }.assimilate_storage(&mut t, &mut c); + let mut ext = t.into(); runtime_io::with_externalities(&mut ext, || { let validators = Session::validators(); @@ -261,20 +304,52 @@ pub type Session = session::Module; pub type Timestamp = timestamp::Module; pub type Staking = Module; -pub fn check_exposure(acc: u64) { - let expo = Staking::stakers(&acc); - assert_eq!(expo.total as u128, expo.own as u128 + expo.others.iter().map(|e| e.value as u128).sum::()); -} - pub fn check_exposure_all() { Staking::current_elected().into_iter().for_each(|acc| check_exposure(acc)); } -pub fn assert_total_expo(acc: u64, val: u64) { - let expo = Staking::stakers(&acc); +pub fn check_nominator_all() { + >::enumerate().for_each(|(acc, _)| check_nominator_exposure(acc)); +} + +/// Check for each selected validator: expo.total = Sum(expo.other) + expo.own +pub fn check_exposure(stash: u64) { + assert_is_stash(stash); + let expo = Staking::stakers(&stash); + assert_eq!( + expo.total as u128, expo.own as u128 + expo.others.iter().map(|e| e.value as u128).sum::(), + "wrong total exposure for {:?}: {:?}", stash, expo, + ); +} + +/// Check that for each nominator: slashable_balance > sum(used_balance) +/// Note: we might not consume all of a nominator's balance, but we MUST NOT over spend it. +pub fn check_nominator_exposure(stash: u64) { + assert_is_stash(stash); + let mut sum = 0; + Staking::current_elected() + .iter() + .map(|v| Staking::stakers(v)) + .for_each(|e| e.others.iter() + .filter(|i| i.who == stash) + .for_each(|i| sum += i.value)); + let nominator_stake = Staking::slashable_balance_of(&stash); + // a nominator cannot over-spend. + assert!( + nominator_stake >= sum, + "failed: Nominator({}) stake({}) >= sum divided({})", stash, nominator_stake, sum, + ); +} + +pub fn assert_total_expo(stash: u64, val: u64) { + let expo = Staking::stakers(&stash); assert_eq!(expo.total, val); } +pub fn assert_is_stash(acc: u64) { + assert!(Staking::bonded(&acc).is_some(), "Not a stash."); +} + pub fn bond_validator(acc: u64, val: u64) { // a = controller // a + 1 = stash @@ -292,10 +367,13 @@ pub fn bond_nominator(acc: u64, val: u64, target: Vec) { } pub fn start_session(session_index: session::SessionIndex) { + // Compensate for session delay + let session_index = session_index + 1; for i in 0..(session_index - Session::current_index()) { System::set_block_number((i + 1).into()); Session::on_initialize(System::block_number()); } + assert_eq!(Session::current_index(), session_index); } @@ -303,3 +381,7 @@ pub fn start_era(era_index: EraIndex) { start_session((era_index * 3).into()); assert_eq!(Staking::current_era(), era_index); } + +pub fn validator_controllers() -> Vec { + Session::validators().into_iter().map(|s| Staking::bonded(&s).expect("no controller for validator")).collect() +} diff --git a/srml/staking/src/phragmen.rs b/srml/staking/src/phragmen.rs index 50f63323bb3fb043e24f6adaa2f1ad2ea1f01507..39480bf689e7b60a3f672d4c41bbf1e656b6a5a2 100644 --- a/srml/staking/src/phragmen.rs +++ b/srml/staking/src/phragmen.rs @@ -19,7 +19,7 @@ use rstd::{prelude::*, collections::btree_map::BTreeMap}; use primitives::{PerU128}; use primitives::traits::{Zero, Convert, Saturating}; -use crate::{BalanceOf, Assignment, RawAssignment, ExpoMap, Trait, ValidatorPrefs}; +use crate::{BalanceOf, RawAssignment, ExpoMap, Trait, ValidatorPrefs, IndividualExposure}; type Fraction = PerU128; /// Wrapper around the type used as the _safe_ wrapper around a `balance`. @@ -275,7 +275,7 @@ pub fn elect( /// /// No value is returned from the function and the `expo_map` parameter is updated. pub fn equalize( - assignments: &mut Vec<(T::AccountId, BalanceOf, Vec>)>, + assignments: &mut Vec<(T::AccountId, BalanceOf, Vec<(T::AccountId, ExtendedBalance, ExtendedBalance)>)>, expo_map: &mut ExpoMap, tolerance: ExtendedBalance, iterations: usize, @@ -297,19 +297,19 @@ pub fn equalize( fn do_equalize( nominator: &T::AccountId, budget_balance: BalanceOf, - elected_edges_balance: &mut Vec>, + elected_edges: &mut Vec<(T::AccountId, ExtendedBalance, ExtendedBalance)>, expo_map: &mut ExpoMap, tolerance: ExtendedBalance ) -> ExtendedBalance { - let to_votes = |b: BalanceOf| , u64>>::convert(b) as ExtendedBalance; - let to_balance = |v: ExtendedBalance| >>::convert(v); + let to_votes = |b: BalanceOf| + , u64>>::convert(b) as ExtendedBalance; + let to_balance = |v: ExtendedBalance| + >>::convert(v); let budget = to_votes(budget_balance); - // Convert all stakes to extended. Result is Vec<(Acc, Ratio, Balance)> - let mut elected_edges = elected_edges_balance - .into_iter() - .map(|e| (e.0.clone(), e.1, to_votes(e.2))) - .collect::>(); + // Nothing to do. This nominator had nothing useful. + // Defensive only. Assignment list should always be populated. + if elected_edges.is_empty() { return 0; } let stake_used = elected_edges .iter() @@ -350,18 +350,20 @@ fn do_equalize( elected_edges.iter_mut().for_each(|e| { if let Some(expo) = expo_map.get_mut(&e.0) { expo.total = expo.total.saturating_sub(to_balance(e.2)); + expo.others.retain(|i_expo| i_expo.who != *nominator); } e.2 = 0; }); - elected_edges.sort_unstable_by_key(|e| e.2); + elected_edges.sort_unstable_by_key(|e| + if let Some(e) = expo_map.get(&e.0) { e.total } else { Zero::zero() } + ); let mut cumulative_stake: ExtendedBalance = 0; let mut last_index = elected_edges.len() - 1; elected_edges.iter_mut().enumerate().for_each(|(idx, e)| { if let Some(expo) = expo_map.get_mut(&e.0) { let stake: ExtendedBalance = to_votes(expo.total); - let stake_mul = stake.saturating_mul(idx as ExtendedBalance); let stake_sub = stake_mul.saturating_sub(cumulative_stake); if stake_sub > budget { @@ -383,14 +385,9 @@ fn do_equalize( .saturating_add(last_stake) .saturating_sub(to_votes(expo.total)); expo.total = expo.total.saturating_add(to_balance(e.2)); - if let Some(i_expo) = expo.others.iter_mut().find(|i| i.who == nominator.clone()) { - i_expo.value = to_balance(e.2); - } + expo.others.push(IndividualExposure { who: nominator.clone(), value: to_balance(e.2)}); } }); - // Store back the individual edge weights. - elected_edges.iter().enumerate().for_each(|(idx, e)| elected_edges_balance[idx].2 = to_balance(e.2)); - difference } diff --git a/srml/staking/src/tests.rs b/srml/staking/src/tests.rs index 180ce130ae414f434dba72269a830574e9a5dea3..5987d9800d963d79b70413c93b2c605617fa6e53 100644 --- a/srml/staking/src/tests.rs +++ b/srml/staking/src/tests.rs @@ -52,10 +52,30 @@ fn basic_setup_works() { assert_eq!(Staking::ledger(100), Some(StakingLedger { stash: 101, total: 500, active: 500, unlocking: vec![] })); assert_eq!(Staking::nominators(101), vec![11, 21]); - // Account 10 is exposed by 1000 * balance_factor from their own stash in account 11 + the default nominator vote - assert_eq!(Staking::stakers(11), Exposure { total: 1125, own: 1000, others: vec![ IndividualExposure { who: 101, value: 125 }] }); - // Account 20 is exposed by 1000 * balance_factor from their own stash in account 21 + the default nominator vote - assert_eq!(Staking::stakers(21), Exposure { total: 1375, own: 1000, others: vec![ IndividualExposure { who: 101, value: 375 }] }); + if cfg!(feature = "equalize") { + assert_eq!( + Staking::stakers(11), + Exposure { total: 1250, own: 1000, others: vec![ IndividualExposure { who: 101, value: 250 }] } + ); + assert_eq!( + Staking::stakers(21), + Exposure { total: 1250, own: 1000, others: vec![ IndividualExposure { who: 101, value: 250 }] } + ); + // initial slot_stake + assert_eq!(Staking::slot_stake(), 1250); + } else { + assert_eq!( + Staking::stakers(11), + Exposure { total: 1125, own: 1000, others: vec![ IndividualExposure { who: 101, value: 125 }] } + ); + assert_eq!( + Staking::stakers(21), + Exposure { total: 1375, own: 1000, others: vec![ IndividualExposure { who: 101, value: 375 }] } + ); + // initial slot_stake + assert_eq!(Staking::slot_stake(), 1125); + } + // The number of validators required. assert_eq!(Staking::validator_count(), 2); @@ -67,8 +87,6 @@ fn basic_setup_works() { // initial rewards assert_eq!(Staking::current_session_reward(), 10); - // initial slot_stake - assert_eq!(Staking::slot_stake(), 1125); // Naive // initial slash_count of validators assert_eq!(Staking::slash_count(&11), 0); @@ -76,6 +94,7 @@ fn basic_setup_works() { // All exposures must be correct. check_exposure_all(); + check_nominator_all(); }); } @@ -127,7 +146,7 @@ fn invulnerability_should_work() { with_externalities(&mut ExtBuilder::default().build(), || { // Make account 11 invulnerable - assert_ok!(Staking::set_invulnerables(vec![11])); + assert_ok!(Staking::set_invulnerables(Origin::ROOT, vec![11])); // Give account 11 some funds let _ = Balances::make_free_balance_be(&11, 70); // There is no slash grace -- slash immediately. @@ -194,12 +213,15 @@ fn offline_grace_should_delay_slashing() { // Set offline slash grace let offline_slash_grace = 1; - assert_ok!(Staking::set_offline_slash_grace(offline_slash_grace)); + assert_ok!(Staking::set_offline_slash_grace(Origin::ROOT, offline_slash_grace)); assert_eq!(Staking::offline_slash_grace(), 1); // Check unstake_threshold is 3 (default) let default_unstake_threshold = 3; - assert_eq!(Staking::validators(&11), ValidatorPrefs { unstake_threshold: default_unstake_threshold, validator_payment: 0 }); + assert_eq!( + Staking::validators(&11), + ValidatorPrefs { unstake_threshold: default_unstake_threshold, validator_payment: 0 } + ); // Check slash count is zero assert_eq!(Staking::slash_count(&11), 0); @@ -257,7 +279,7 @@ fn max_unstake_threshold_works() { validator_payment: 0, }); - >::put(Perbill::from_fraction(0.0001)); + OfflineSlash::put(Perbill::from_fraction(0.0001)); // Report each user 1 more than the max_unstake_threshold Staking::on_offline_validator(10, MAX_UNSTAKE_THRESHOLD as usize + 1); @@ -389,18 +411,18 @@ fn multi_era_reward_should_work() { // Set payee to controller assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); - start_session(1); + start_session(0); // session triggered: the reward value stashed should be 10 assert_eq!(Staking::current_session_reward(), session_reward); assert_eq!(Staking::current_era_reward(), session_reward); - start_session(2); + start_session(1); assert_eq!(Staking::current_session_reward(), session_reward); assert_eq!(Staking::current_era_reward(), 2*session_reward); - start_session(3); + start_session(2); // 1 + sum of of the session rewards accumulated let recorded_balance = 1 + 3*session_reward; @@ -411,13 +433,13 @@ fn multi_era_reward_should_work() { assert_eq!(Staking::current_session_reward(), new_session_reward); // fast forward to next era: - start_session(5); + start_session(4); // intermediate test. assert_eq!(Staking::current_era_reward(), 2*new_session_reward); // new era is triggered here. - start_session(6); + start_session(5); // pay time assert_eq!(Balances::total_balance(&10), 3*new_session_reward + recorded_balance); @@ -436,70 +458,52 @@ fn staking_should_work() { .build(), || { // remember + compare this along with the test. - assert_eq_uvec!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(validator_controllers(), vec![20, 10]); // put some money in account that we'll use. for i in 1..5 { let _ = Balances::make_free_balance_be(&i, 2000); } // --- Block 1: - System::set_block_number(1); - Session::on_initialize(System::block_number()); - assert_eq!(Staking::current_era(), 0); - + start_session(1); // add a new candidate for being a validator. account 3 controlled by 4. assert_ok!(Staking::bond(Origin::signed(3), 4, 1500, RewardDestination::Controller)); assert_ok!(Staking::validate(Origin::signed(4), ValidatorPrefs::default())); // No effects will be seen so far. - assert_eq_uvec!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(validator_controllers(), vec![20, 10]); // --- Block 2: - System::set_block_number(2); - Session::on_initialize(System::block_number()); - assert_eq!(Staking::current_era(), 0); + start_session(2); // No effects will be seen so far. Era has not been yet triggered. - assert_eq_uvec!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(validator_controllers(), vec![20, 10]); - // --- Block 3: the validators will now change. - System::set_block_number(3); - Session::on_initialize(System::block_number()); - - // 2 only voted for 4 and 20 - assert_eq!(Session::validators().len(), 2); - assert_eq_uvec!(Session::validators(), vec![20, 4]); + // --- Block 3: the validators will now be queued. + start_session(3); assert_eq!(Staking::current_era(), 1); + // --- Block 4: the validators will now be changed. + start_session(4); + assert_eq_uvec!(validator_controllers(), vec![20, 4]); // --- Block 4: Unstake 4 as a validator, freeing up the balance stashed in 3 - System::set_block_number(4); - Session::on_initialize(System::block_number()); - // 4 will chill Staking::chill(Origin::signed(4)).unwrap(); - // nothing should be changed so far. - assert_eq_uvec!(Session::validators(), vec![20, 4]); - assert_eq!(Staking::current_era(), 1); - - // --- Block 5: nothing. 4 is still there. - System::set_block_number(5); - Session::on_initialize(System::block_number()); - assert_eq_uvec!(Session::validators(), vec![20, 4]); - assert_eq!(Staking::current_era(), 1); - + start_session(5); + assert_eq_uvec!(validator_controllers(), vec![20, 4]); // --- Block 6: 4 will not be a validator. - System::set_block_number(6); - Session::on_initialize(System::block_number()); - assert_eq!(Staking::current_era(), 2); - assert_eq!(Session::validators().contains(&4), false); - assert_eq_uvec!(Session::validators(), vec![20, 10]); + start_session(7); + assert_eq_uvec!(validator_controllers(), vec![20, 10]); // Note: the stashed value of 4 is still lock - assert_eq!(Staking::ledger(&4), Some(StakingLedger { stash: 3, total: 1500, active: 1500, unlocking: vec![] })); + assert_eq!( + Staking::ledger(&4), + Some(StakingLedger { stash: 3, total: 1500, active: 1500, unlocking: vec![] }) + ); // e.g. it cannot spend more than 500 that it has free from the total 2000 assert_noop!(Balances::reserve(&3, 501), "account liquidity restrictions prevent withdrawal"); assert_ok!(Balances::reserve(&3, 409)); @@ -512,22 +516,24 @@ fn less_than_needed_candidates_works() { .minimum_validator_count(1) .validator_count(4) .nominate(false) + .num_validators(3) .build(), || { assert_eq!(Staking::validator_count(), 4); assert_eq!(Staking::minimum_validator_count(), 1); - assert_eq_uvec!(Session::validators(), vec![30, 20, 10]); + assert_eq_uvec!(validator_controllers(), vec![30, 20, 10]); start_era(1); // Previous set is selected. NO election algorithm is even executed. - assert_eq_uvec!(Session::validators(), vec![30, 20, 10]); + assert_eq_uvec!(validator_controllers(), vec![30, 20, 10]); // But the exposure is updated in a simple way. No external votes exists. This is purely self-vote. assert_eq!(Staking::stakers(10).others.len(), 0); assert_eq!(Staking::stakers(20).others.len(), 0); assert_eq!(Staking::stakers(30).others.len(), 0); check_exposure_all(); + check_nominator_all(); }); } @@ -538,14 +544,19 @@ fn no_candidate_emergency_condition() { with_externalities(&mut ExtBuilder::default() .minimum_validator_count(10) .validator_count(15) + .num_validators(4) .validator_pool(true) .nominate(false) .build(), || { - assert_eq!(Staking::validator_count(), 15); // initial validators - assert_eq_uvec!(Session::validators(), vec![10, 20, 30, 40]); + assert_eq_uvec!(validator_controllers(), vec![10, 20, 30, 40]); + + // set the minimum validator count. + ::MinimumValidatorCount::put(10); + ::ValidatorCount::put(15); + assert_eq!(Staking::validator_count(), 15); let _ = Staking::chill(Origin::signed(10)); @@ -554,7 +565,7 @@ fn no_candidate_emergency_condition() { Session::on_initialize(System::block_number()); // Previous ones are elected. chill is invalidates. TODO: #2494 - assert_eq_uvec!(Session::validators(), vec![10, 20, 30, 40]); + assert_eq_uvec!(validator_controllers(), vec![10, 20, 30, 40]); assert_eq!(Staking::current_elected().len(), 0); }); } @@ -597,14 +608,13 @@ fn nominating_and_rewards_should_work() { // 10 with stake 400.0 20 with stake 600.0 30 with stake 0 // 4 has load 0.0005555555555555556 and supported // 10 with stake 600.0 20 with stake 400.0 40 with stake 0.0 - with_externalities(&mut ExtBuilder::default() .nominate(false) .validator_pool(true) .build(), || { // initial validators -- everyone is actually even. - assert_eq_uvec!(Session::validators(), vec![40, 30]); + assert_eq_uvec!(validator_controllers(), vec![40, 30]); // Set payee to controller assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); @@ -633,7 +643,7 @@ fn nominating_and_rewards_should_work() { start_era(1); // 10 and 20 have more votes, they will be chosen by phragmen. - assert_eq_uvec!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(validator_controllers(), vec![20, 10]); // OLD validators must have already received some rewards. assert_eq!(Balances::total_balance(&40), 1 + 3 * session_reward); @@ -641,18 +651,57 @@ fn nominating_and_rewards_should_work() { // ------ check the staked value of all parties. - // total expo of 10, with 1200 coming from nominators (externals), according to phragmen. - assert_eq!(Staking::stakers(11).own, 1000); - assert_eq!(Staking::stakers(11).total, 1000 + 800); - // 2 and 4 supported 10, each with stake 600, according to phragmen. - assert_eq!(Staking::stakers(11).others.iter().map(|e| e.value).collect::>>(), vec![400, 400]); - assert_eq!(Staking::stakers(11).others.iter().map(|e| e.who).collect::>>(), vec![3, 1]); - // total expo of 20, with 500 coming from nominators (externals), according to phragmen. - assert_eq!(Staking::stakers(21).own, 1000); - assert_eq!(Staking::stakers(21).total, 1000 + 1198); - // 2 and 4 supported 20, each with stake 250, according to phragmen. - assert_eq!(Staking::stakers(21).others.iter().map(|e| e.value).collect::>>(), vec![599, 599]); - assert_eq!(Staking::stakers(21).others.iter().map(|e| e.who).collect::>>(), vec![3, 1]); + if cfg!(feature = "equalize") { + // total expo of 10, with 1200 coming from nominators (externals), according to phragmen. + assert_eq!(Staking::stakers(11).own, 1000); + assert_eq!(Staking::stakers(11).total, 1000 + 999); + // 2 and 4 supported 10, each with stake 600, according to phragmen. + assert_eq!( + Staking::stakers(11).others.iter().map(|e| e.value).collect::>>(), + vec![599, 400] + ); + assert_eq!( + Staking::stakers(11).others.iter().map(|e| e.who).collect::>(), + vec![3, 1] + ); + // total expo of 20, with 500 coming from nominators (externals), according to phragmen. + assert_eq!(Staking::stakers(21).own, 1000); + assert_eq!(Staking::stakers(21).total, 1000 + 999); + // 2 and 4 supported 20, each with stake 250, according to phragmen. + assert_eq!( + Staking::stakers(21).others.iter().map(|e| e.value).collect::>>(), + vec![400, 599] + ); + assert_eq!( + Staking::stakers(21).others.iter().map(|e| e.who).collect::>(), + vec![3, 1] + ); + } else { + // total expo of 10, with 1200 coming from nominators (externals), according to phragmen. + assert_eq!(Staking::stakers(11).own, 1000); + assert_eq!(Staking::stakers(11).total, 1000 + 800); + // 2 and 4 supported 10, each with stake 600, according to phragmen. + assert_eq!( + Staking::stakers(11).others.iter().map(|e| e.value).collect::>>(), + vec![400, 400] + ); + assert_eq!( + Staking::stakers(11).others.iter().map(|e| e.who).collect::>(), + vec![3, 1] + ); + // total expo of 20, with 500 coming from nominators (externals), according to phragmen. + assert_eq!(Staking::stakers(21).own, 1000); + assert_eq!(Staking::stakers(21).total, 1000 + 1198); + // 2 and 4 supported 20, each with stake 250, according to phragmen. + assert_eq!( + Staking::stakers(21).others.iter().map(|e| e.value).collect::>>(), + vec![599, 599] + ); + assert_eq!( + Staking::stakers(21).others.iter().map(|e| e.who).collect::>(), + vec![3, 1] + ); + } // They are not chosen anymore assert_eq!(Staking::stakers(31).total, 0); @@ -662,20 +711,35 @@ fn nominating_and_rewards_should_work() { start_era(2); // next session reward. let new_session_reward = Staking::session_reward() * 3 * Staking::slot_stake(); - // nothing else will happen, era ends and rewards are paid again, - // it is expected that nominators will also be paid. See below - - // Nominator 2: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 20]'s reward. ==> 2/9 + 3/11 - assert_eq!(Balances::total_balance(&2), initial_balance + (2*new_session_reward/9 + 3*new_session_reward/11) - 1); - // Nominator 4: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 20]'s reward. ==> 2/9 + 3/11 - assert_eq!(Balances::total_balance(&4), initial_balance + (2*new_session_reward/9 + 3*new_session_reward/11) - 1); - // 10 got 800 / 1800 external stake => 8/18 =? 4/9 => Validator's share = 5/9 - assert_eq!(Balances::total_balance(&10), initial_balance + 5*new_session_reward/9); - // 10 got 1200 / 2200 external stake => 12/22 =? 6/11 => Validator's share = 5/11 - assert_eq!(Balances::total_balance(&20), initial_balance + 5*new_session_reward/11+ 2); + // NOTE: some addition or substraction (-2, -3, +1) are due to arithmetic approximations + if cfg!(feature = "equalize") { + // Both have: has [400/2000 ~ 1/5 from 10] + [600/2000 ~ 3/10 from 20]'s reward. ==> 1/5 + 3/10 = 1/2 + assert_eq!(Balances::total_balance(&2), initial_balance + new_session_reward/2 - 3); + assert_eq!(Balances::total_balance(&4), initial_balance + new_session_reward/2 - 3); + // Rest for validators. + assert_eq!(Balances::total_balance(&10), initial_balance + new_session_reward/2 + 1); + assert_eq!(Balances::total_balance(&20), initial_balance + new_session_reward/2 + 1); + } else { + // Nominator 2: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 20]'s reward. ==> 2/9 + 3/11 + assert_eq!( + Balances::total_balance(&2), + initial_balance + (2*new_session_reward/9 + 3*new_session_reward/11) - 2 + ); + // Nominator 4: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 20]'s reward. ==> 2/9 + 3/11 + assert_eq!( + Balances::total_balance(&4), + initial_balance + (2*new_session_reward/9 + 3*new_session_reward/11) - 2 + ); + + // 10 got 800 / 1800 external stake => 8/18 =? 4/9 => Validator's share = 5/9 + assert_eq!(Balances::total_balance(&10), initial_balance + 5*new_session_reward/9 - 1); + // 10 got 1200 / 2200 external stake => 12/22 =? 6/11 => Validator's share = 5/11 + assert_eq!(Balances::total_balance(&20), initial_balance + 5*new_session_reward/11 + 2); + } check_exposure_all(); + check_nominator_all(); }); } @@ -688,7 +752,7 @@ fn nominators_also_get_slashed() { assert_eq!(Staking::offline_slash_grace(), 0); // Account 10 has not been reported offline assert_eq!(Staking::slash_count(&10), 0); - >::put(Perbill::from_percent(12)); + OfflineSlash::put(Perbill::from_percent(12)); // Set payee to controller assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); @@ -722,6 +786,7 @@ fn nominators_also_get_slashed() { assert_eq!(Balances::total_balance(&10), initial_balance + 30 - validator_slash); assert_eq!(Balances::total_balance(&2), initial_balance - nominator_slash); check_exposure_all(); + check_nominator_all(); // Because slashing happened. assert!(is_disabled(10)); }); @@ -738,9 +803,15 @@ fn double_staking_should_fail() { || { let arbitrary_value = 5; // 2 = controller, 1 stashed => ok - assert_ok!(Staking::bond(Origin::signed(1), 2, arbitrary_value, RewardDestination::default())); + assert_ok!( + Staking::bond(Origin::signed(1), 2, arbitrary_value, + RewardDestination::default()) + ); // 4 = not used so far, 1 stashed => not allowed. - assert_noop!(Staking::bond(Origin::signed(1), 4, arbitrary_value, RewardDestination::default()), "stash already bonded"); + assert_noop!( + Staking::bond(Origin::signed(1), 4, arbitrary_value, + RewardDestination::default()), "stash already bonded" + ); // 1 = stashed => attempting to nominate should fail. assert_noop!(Staking::nominate(Origin::signed(1), vec![1]), "not a controller"); // 2 = controller => nominating should work. @@ -771,37 +842,37 @@ fn session_and_eras_work() { assert_eq!(Staking::current_era(), 0); // Block 1: No change. - start_session(1); + start_session(0); assert_eq!(Session::current_index(), 1); assert_eq!(Staking::current_era(), 0); // Block 2: Simple era change. - start_session(3); + start_session(2); assert_eq!(Session::current_index(), 3); assert_eq!(Staking::current_era(), 1); // Block 3: Schedule an era length change; no visible changes. - start_session(4); + start_session(3); assert_eq!(Session::current_index(), 4); assert_eq!(Staking::current_era(), 1); // Block 4: Era change kicks in. - start_session(6); + start_session(5); assert_eq!(Session::current_index(), 6); assert_eq!(Staking::current_era(), 2); // Block 5: No change. - start_session(7); + start_session(6); assert_eq!(Session::current_index(), 7); assert_eq!(Staking::current_era(), 2); // Block 6: No change. - start_session(8); + start_session(7); assert_eq!(Session::current_index(), 8); assert_eq!(Staking::current_era(), 2); // Block 7: Era increment. - start_session(9); + start_session(8); assert_eq!(Session::current_index(), 9); assert_eq!(Staking::current_era(), 3); }); @@ -1025,6 +1096,7 @@ fn validator_payment_prefs_work() { assert_eq!(Balances::total_balance(&2), 500 + shared_cut/2); check_exposure_all(); + check_nominator_all(); }); } @@ -1240,6 +1312,7 @@ fn slot_stake_is_least_staked_validator_and_exposure_defines_maximum_punishment( assert_eq!(Balances::free_balance(&11), 1000 + 30 - 51 /*5% of 1030*/ * 8 /*2**3*/); check_exposure_all(); + check_nominator_all(); }); } @@ -1403,15 +1476,13 @@ fn phragmen_poc_works() { // 10 with stake 166.66666666666674 20 with stake 333.33333333333326 30 with stake 0 // 4 has load 0.00075 and supported // 10 with stake 333.3333333333333 20 with stake 166.66666666666666 40 with stake 0.0 - - with_externalities(&mut ExtBuilder::default() .nominate(false) .validator_pool(true) .build(), || { // We don't really care about this. At this point everything is even. - assert_eq_uvec!(Session::validators(), vec![40, 30]); + assert_eq_uvec!(validator_controllers(), vec![40, 30]); // Set payees to Controller assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); @@ -1435,23 +1506,60 @@ fn phragmen_poc_works() { // New era => election algorithm will trigger start_era(1); - assert_eq_uvec!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(validator_controllers(), vec![20, 10]); - // with stake 1666 and 1333 respectively assert_eq!(Staking::stakers(11).own, 1000); - assert_eq!(Staking::stakers(11).total, 1000 + 332); assert_eq!(Staking::stakers(21).own, 1000); - assert_eq!(Staking::stakers(21).total, 1000 + 666); + + if cfg!(feature = "equalize") { + assert_eq!(Staking::stakers(11).total, 1000 + 499); + assert_eq!(Staking::stakers(21).total, 1000 + 499); + } else { + assert_eq!(Staking::stakers(11).total, 1000 + 332); + assert_eq!(Staking::stakers(21).total, 1000 + 666); + } // Nominator's stake distribution. - assert_eq!(Staking::stakers(11).others.iter().map(|e| e.value).collect::>>(), vec![166, 166]); - assert_eq!(Staking::stakers(11).others.iter().map(|e| e.value).sum::>(), 332); assert_eq!(Staking::stakers(11).others.iter().map(|e| e.who).collect::>>(), vec![3, 1]); - - assert_eq!(Staking::stakers(21).others.iter().map(|e| e.value).collect::>>(), vec![333, 333]); - assert_eq!(Staking::stakers(21).others.iter().map(|e| e.value).sum::>(), 666); assert_eq!(Staking::stakers(21).others.iter().map(|e| e.who).collect::>>(), vec![3, 1]); + + if cfg!(feature = "equalize") { + assert_eq_uvec!( + Staking::stakers(11).others.iter().map(|e| e.value).collect::>>(), + vec![333, 166] + ); + assert_eq!( + Staking::stakers(11).others.iter().map(|e| e.value).sum::>(), + 499 + ); + assert_eq_uvec!( + Staking::stakers(21).others.iter().map(|e| e.value).collect::>>(), + vec![333, 166] + ); + assert_eq!( + Staking::stakers(21).others.iter().map(|e| e.value).sum::>(), + 499 + ); + } else { + assert_eq_uvec!( + Staking::stakers(11).others.iter().map(|e| e.value).collect::>>(), + vec![166, 166] + ); + assert_eq!( + Staking::stakers(11).others.iter().map(|e| e.value).sum::>(), + 332 + ); + assert_eq_uvec!( + Staking::stakers(21).others.iter().map(|e| e.value).collect::>>(), + vec![333, 333] + ); + assert_eq!( + Staking::stakers(21).others.iter().map(|e| e.value).sum::>(), + 666 + ); + } check_exposure_all(); + check_nominator_all(); }); } @@ -1470,7 +1578,7 @@ fn phragmen_poc_2_works() { // 30 is elected with stake 1344.2622950819673 and score 0.0007439024390243903 with_externalities(&mut ExtBuilder::default().nominate(false).build(), || { // initial setup of 10 and 20, both validators - assert_eq_uvec!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(validator_controllers(), vec![20, 10]); // Bond [30, 31] as the third validator assert_ok!(Staking::bond_extra(Origin::signed(31), 999)); @@ -1502,6 +1610,7 @@ fn phragmen_poc_2_works() { (1, vec![(11, 4294967296)]), ]); check_exposure_all(); + check_nominator_all(); }) } @@ -1515,7 +1624,7 @@ fn switching_roles() { // Reset reward destination for i in &[10, 20] { assert_ok!(Staking::set_payee(Origin::signed(*i), RewardDestination::Controller)); } - assert_eq_uvec!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(validator_controllers(), vec![20, 10]); // put some money in account that we'll use. for i in 1..7 { let _ = Balances::deposit_creating(&i, 5000); } @@ -1532,48 +1641,44 @@ fn switching_roles() { assert_ok!(Staking::validate(Origin::signed(6), ValidatorPrefs::default())); // new block - System::set_block_number(1); - Session::on_initialize(System::block_number()); + start_session(1); // no change - assert_eq_uvec!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(validator_controllers(), vec![20, 10]); // new block - System::set_block_number(2); - Session::on_initialize(System::block_number()); + start_session(2); // no change - assert_eq_uvec!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(validator_controllers(), vec![20, 10]); // new block --> ne era --> new validators - System::set_block_number(3); - Session::on_initialize(System::block_number()); + start_session(3); // with current nominators 10 and 5 have the most stake - assert_eq_uvec!(Session::validators(), vec![6, 10]); + assert_eq_uvec!(validator_controllers(), vec![6, 10]); // 2 decides to be a validator. Consequences: assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default())); // new stakes: // 10: 1000 self vote - // 20: 1000 self vote + 500 vote + // 20: 1000 self vote + 250 vote // 6 : 1000 self vote - // 2 : 2000 self vote + 500 vote. + // 2 : 2000 self vote + 250 vote. // Winners: 20 and 2 - System::set_block_number(4); - Session::on_initialize(System::block_number()); - assert_eq_uvec!(Session::validators(), vec![6, 10]); + start_session(4); + assert_eq_uvec!(validator_controllers(), vec![6, 10]); - System::set_block_number(5); - Session::on_initialize(System::block_number()); - assert_eq_uvec!(Session::validators(), vec![6, 10]); + start_session(5); + assert_eq_uvec!(validator_controllers(), vec![6, 10]); // ne era - System::set_block_number(6); - Session::on_initialize(System::block_number()); - assert_eq_uvec!(Session::validators(), vec![2, 20]); + start_session(6); + assert_eq_uvec!(validator_controllers(), vec![2, 20]); + check_exposure_all(); + check_nominator_all(); }); } @@ -1584,7 +1689,7 @@ fn wrong_vote_is_null() { .validator_pool(true) .build(), || { - assert_eq_uvec!(Session::validators(), vec![40, 30]); + assert_eq_uvec!(validator_controllers(), vec![40, 30]); // put some money in account that we'll use. for i in 1..3 { let _ = Balances::deposit_creating(&i, 5000); } @@ -1599,7 +1704,7 @@ fn wrong_vote_is_null() { // new block start_era(1); - assert_eq_uvec!(Session::validators(), vec![20, 10]); + assert_eq_uvec!(validator_controllers(), vec![20, 10]); }); } @@ -1609,57 +1714,46 @@ fn bond_with_no_staked_value() { // Particularly when she votes and the candidate is elected. with_externalities(&mut ExtBuilder::default() .validator_count(3) + .existential_deposit(5) .nominate(false) .minimum_validator_count(1) .build(), || { - // setup - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); - let _ = Balances::deposit_creating(&3, 1000); - let initial_balance_2 = Balances::free_balance(&2); - let initial_balance_4 = Balances::free_balance(&4); - - // Stingy validator. - assert_ok!(Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller)); - assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default())); + // Can't bond with 1 + assert_noop!( + Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller), + "can not bond with value less than minimum balance" + ); + // bonded with absolute minimum value possible. + assert_ok!(Staking::bond(Origin::signed(1), 2, 5, RewardDestination::Controller)); + assert_eq!(Balances::locks(&1)[0].amount, 5); + + // unbonding even 1 will cause all to be unbonded. + assert_ok!(Staking::unbond(Origin::signed(2), 1)); + assert_eq!( + Staking::ledger(2), + Some(StakingLedger { + stash: 1, + active: 0, + total: 5, + unlocking: vec![UnlockChunk {value: 5, era: 3}] + }) + ); start_era(1); - - assert_eq_uvec!(Session::validators(), vec![30, 20, 10]); - - // min of 10, 20 and 30 (30 got a payout into staking so it raised it from 1 to 31). - assert_eq!(Staking::slot_stake(), 31); - - // make the stingy one elected. - assert_ok!(Staking::bond(Origin::signed(3), 4, 500, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(4), vec![1])); - - // no rewards paid to 2 and 4 yet - assert_eq!(Balances::free_balance(&2), initial_balance_2); - assert_eq!(Balances::free_balance(&4), initial_balance_4); - start_era(2); - // Stingy one is selected - assert_eq_uvec!(Session::validators(), vec![20, 10, 2]); - assert_eq!(Staking::stakers(1), Exposure { - own: 1, - total: 501, - others: vec![IndividualExposure { who: 3, value: 500}], - }); - // New slot stake. - assert_eq!(Staking::slot_stake(), 501); - - // no rewards paid to 2 and 4 yet - assert_eq!(Balances::free_balance(&2), initial_balance_2); - assert_eq!(Balances::free_balance(&4), initial_balance_4); + // not yet removed. + assert_ok!(Staking::withdraw_unbonded(Origin::signed(2))); + assert!(Staking::ledger(2).is_some()); + assert_eq!(Balances::locks(&1)[0].amount, 5); start_era(3); - let reward = Staking::current_session_reward() * 3; - // 2 will not get a reward of only 1 - // 4 will get the rest - assert_eq!(Balances::free_balance(&2), initial_balance_2 + 3); - assert_eq!(Balances::free_balance(&4), initial_balance_4 + reward - 3); + // poof. Account 1 is removed from the staking system. + assert_ok!(Staking::withdraw_unbonded(Origin::signed(2))); + assert!(Staking::ledger(2).is_none()); + assert_eq!(Balances::locks(&1).len(), 0); + }); } @@ -1688,7 +1782,7 @@ fn bond_with_little_staked_value_bounded_by_slot_stake() { // 2 is elected. // and fucks up the slot stake. - assert_eq_uvec!(Session::validators(), vec![20, 10, 2]); + assert_eq_uvec!(validator_controllers(), vec![20, 10, 2]); assert_eq!(Staking::slot_stake(), 1); // Old ones are rewarded. @@ -1698,7 +1792,7 @@ fn bond_with_little_staked_value_bounded_by_slot_stake() { start_era(2); - assert_eq_uvec!(Session::validators(), vec![20, 10, 2]); + assert_eq_uvec!(validator_controllers(), vec![20, 10, 2]); assert_eq!(Staking::slot_stake(), 1); let reward = Staking::current_session_reward(); @@ -1707,12 +1801,13 @@ fn bond_with_little_staked_value_bounded_by_slot_stake() { // same for 10 assert_eq!(Balances::free_balance(&10), initial_balance_10 + 30 + reward.max(3)); check_exposure_all(); + check_nominator_all(); }); } +#[cfg(feature = "equalize")] #[test] -#[ignore] // Enable this once post-processing is on. fn phragmen_linear_worse_case_equalize() { with_externalities(&mut ExtBuilder::default() .nominate(false) @@ -1720,7 +1815,6 @@ fn phragmen_linear_worse_case_equalize() { .fair(true) .build(), || { - for i in &[10, 20, 30, 40] { assert_ok!(Staking::set_payee(Origin::signed(*i), RewardDestination::Controller)); } bond_validator(50, 1000); bond_validator(60, 1000); @@ -1734,32 +1828,27 @@ fn phragmen_linear_worse_case_equalize() { bond_nominator(120, 1000, vec![51, 61]); bond_nominator(130, 1000, vec![61, 71]); - assert_eq_uvec!(Session::validators(), vec![40, 30]); - assert_ok!(Staking::set_validator_count(7)); + for i in &[10, 20, 30, 40, 50, 60, 70] { + assert_ok!(Staking::set_payee(Origin::signed(*i), RewardDestination::Controller)); + } - System::set_block_number(1); - Session::on_initialize(System::block_number()); + assert_eq_uvec!(validator_controllers(), vec![40, 30]); + assert_ok!(Staking::set_validator_count(Origin::ROOT, 7)); - assert_eq_uvec!(Session::validators(), vec![10, 60, 40, 20, 50, 30, 70]); + start_era(1); - // Sequential Phragmén with post processing gives - // 10 is elected with stake 3000.0 and score 0.00025 - // 20 is elected with stake 2017.7421569824219 and score 0.0005277777777777777 - // 30 is elected with stake 2008.8712884829595 and score 0.0003333333333333333 - // 40 is elected with stake 2000.0001049958742 and score 0.0005555555555555556 - // 50 is elected with stake 2000.0001049958742 and score 0.0003333333333333333 - // 60 is elected with stake 1991.128921508789 and score 0.0004444444444444444 - // 70 is elected with stake 1982.2574230340813 and score 0.0007222222222222222 - - check_exposure_all(); + assert_eq_uvec!(validator_controllers(), vec![10, 60, 40, 20, 50, 30, 70]); assert_eq!(Staking::stakers(11).total, 3000); - assert_eq!(Staking::stakers(21).total, 2209); - assert_eq!(Staking::stakers(31).total, 2027); - assert_eq!(Staking::stakers(41).total, 2010); - assert_eq!(Staking::stakers(51).total, 2010); - assert_eq!(Staking::stakers(61).total, 1998); - assert_eq!(Staking::stakers(71).total, 1983); + assert_eq!(Staking::stakers(21).total, 2254); + assert_eq!(Staking::stakers(31).total, 2254); + assert_eq!(Staking::stakers(41).total, 1926); + assert_eq!(Staking::stakers(51).total, 1871); + assert_eq!(Staking::stakers(61).total, 1892); + assert_eq!(Staking::stakers(71).total, 1799); + + check_exposure_all(); + check_nominator_all(); }) } @@ -1773,13 +1862,14 @@ fn phragmen_chooses_correct_number_of_validators() { .build(), || { assert_eq!(Staking::validator_count(), 1); - assert_eq!(Session::validators().len(), 1); + assert_eq!(validator_controllers().len(), 1); System::set_block_number(1); Session::on_initialize(System::block_number()); - assert_eq!(Session::validators().len(), 1); + assert_eq!(validator_controllers().len(), 1); check_exposure_all(); + check_nominator_all(); }) } @@ -1797,8 +1887,9 @@ fn phragmen_score_should_be_accurate_on_large_stakes() { start_era(1); - assert_eq!(Session::validators(), vec![4, 2]); + assert_eq!(validator_controllers(), vec![4, 2]); check_exposure_all(); + check_nominator_all(); }) } @@ -1819,7 +1910,7 @@ fn phragmen_should_not_overflow_validators() { start_era(1); - assert_eq_uvec!(Session::validators(), vec![4, 2]); + assert_eq_uvec!(validator_controllers(), vec![4, 2]); // This test will fail this. Will saturate. // check_exposure_all(); @@ -1845,7 +1936,7 @@ fn phragmen_should_not_overflow_nominators() { start_era(1); - assert_eq_uvec!(Session::validators(), vec![4, 2]); + assert_eq_uvec!(validator_controllers(), vec![4, 2]); // Saturate. assert_eq!(Staking::stakers(3).total, u64::max_value()); @@ -1867,7 +1958,7 @@ fn phragmen_should_not_overflow_ultimate() { start_era(1); - assert_eq_uvec!(Session::validators(), vec![4, 2]); + assert_eq_uvec!(validator_controllers(), vec![4, 2]); // Saturate. assert_eq!(Staking::stakers(3).total, u64::max_value()); @@ -1919,32 +2010,8 @@ fn phragmen_large_scale_test() { start_era(1); - // For manual inspection - println!("Validators are {:?}", Session::validators()); - println!("Validators are {:#?}", - Session::validators() - .iter() - .map(|v| (v.clone(), Staking::stakers(v+1))) - .collect::)>>() - ); - - // Each exposure => total == own + sum(others) check_exposure_all(); - - // aside from some error, stake must be divided correctly - let individual_expo_sum: u128 = Session::validators() - .iter() - .map(|v| Staking::stakers(v+1)) - .fold(0u128, |s, v| if v.others.len() > 0 { s + v.others[0].value as u128 } else { s }); - assert!( - 990000000000000000 - individual_expo_sum < 100, - format!( - "Nominator stake = {} / SUM(individual expo) = {} / diff = {}", - 990000000000000000u64, - individual_expo_sum, - 990000000000000000 - individual_expo_sum - ) - ); + check_nominator_all(); }) } @@ -1970,8 +2037,42 @@ fn phragmen_large_scale_test_2() { // Each exposure => total == own + sum(others) check_exposure_all(); + check_nominator_all(); assert_total_expo(3, nom_budget / 2 + c_budget); assert_total_expo(5, nom_budget / 2 + c_budget); }) } + +#[test] +fn reward_validator_slashing_validator_doesnt_overflow() { + with_externalities(&mut ExtBuilder::default() + .build(), + || { + let stake = u32::max_value() as u64 * 2; + let reward_slash = u32::max_value() as u64 * 2; + + // Assert multiplication overflows in balance arithmetic. + assert!(stake.checked_mul(reward_slash).is_none()); + + // Set staker + let _ = Balances::make_free_balance_be(&11, stake); + >::insert(&11, Exposure { total: stake, own: stake, others: vec![] }); + + // Check reward + Staking::reward_validator(&11, reward_slash); + assert_eq!(Balances::total_balance(&11), stake * 2); + + // Set staker + let _ = Balances::make_free_balance_be(&11, stake); + let _ = Balances::make_free_balance_be(&2, stake); + >::insert(&11, Exposure { total: stake, own: 1, others: vec![ + IndividualExposure { who: 2, value: stake - 1 } + ]}); + + // Check slashing + Staking::slash_validator(&11, reward_slash); + assert_eq!(Balances::total_balance(&11), stake - 1); + assert_eq!(Balances::total_balance(&2), 1); + }) +} diff --git a/srml/sudo/Cargo.toml b/srml/sudo/Cargo.toml index 29ef579516fd58d7fe52f7611a3a678753b539ed..7a25075390d890307a996f096138d6392670c7a1 100644 --- a/srml/sudo/Cargo.toml +++ b/srml/sudo/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] serde = { version = "1.0", optional = true } -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } sr-std = { path = "../../core/sr-std", default-features = false } sr-io = { path = "../../core/sr-io", default-features = false } sr-primitives = { path = "../../core/sr-primitives", default-features = false } diff --git a/srml/support/Cargo.toml b/srml/support/Cargo.toml index 22635106dfa4e6204329f5066d850b7fef328e57..88cad9651a81e994bb9ca147f25214bbc5860bde 100644 --- a/srml/support/Cargo.toml +++ b/srml/support/Cargo.toml @@ -6,11 +6,12 @@ edition = "2018" [dependencies] serde = { version = "1.0", optional = true, features = ["derive"] } -codec = { package = "parity-codec", version = "3.5.1", default-features = false, features = ["derive"] } +codec = { package = "parity-codec", version = "4.1.1", default-features = false, features = ["derive"] } srml-metadata = { path = "../metadata", default-features = false } sr-std = { path = "../../core/sr-std", default-features = false } runtime_io = { package = "sr-io", path = "../../core/sr-io", default-features = false } sr-primitives = { path = "../../core/sr-primitives", default-features = false } +substrate-primitives = { path = "../../core/primitives", default-features = false } inherents = { package = "substrate-inherents", path = "../../core/inherents", default-features = false } srml-support-procedural = { path = "./procedural" } paste = "0.1" diff --git a/srml/support/procedural/src/lib.rs b/srml/support/procedural/src/lib.rs index 280d2a317d14e51070cdb3c5c409c3d93cb7654d..b8bcb15de1b4b31f461c1911009c39c6995d2e20 100644 --- a/srml/support/procedural/src/lib.rs +++ b/srml/support/procedural/src/lib.rs @@ -98,7 +98,7 @@ use proc_macro::TokenStream; /// /// Storage items are accessible in multiple ways: /// -/// * The structure: `Foo::` +/// * The structure: `Foo` or `Foo::` depending if the value type is generic or not. /// * The `Store` trait structure: ` as Store>::Foo` /// * The getter on the module that calls get on the structure: `Module::::foo()` /// @@ -136,9 +136,36 @@ use proc_macro::TokenStream; /// trait Store for Module, I: Instance=DefaultInstance> as Example {} /// ``` /// -/// Then the genesis config is generated with two generic parameters (i.e. `GenesisConfig`) -/// and storage items are accessible using two generic parameters, e.g.: -/// `>::get()` or `Dummy::::get()`. +/// Accessing the structure no requires the instance as generic parameter: +/// * `Foo::` if the value type is not generic +/// * `Foo::` if the value type is generic +/// +/// ## Where clause +/// +/// This macro supports a where clause which will be replicated to all generated types. +/// +/// ```nocompile +/// trait Store for Module as Example where T::AccountId: std::fmt::Display {} +/// ``` +/// +/// ## Limitations +/// +/// # Instancing and generic `GenesisConfig` +/// +/// If your module supports instancing and you see an error like `parameter `I` is never used` for +/// your `decl_storage!`, you are hitting a limitation of the current implementation. You probably +/// try to use an associated type of a non-instantiable trait. To solve this, add the following to +/// your macro call: +/// +/// ```nocompile +/// add_extra_genesis { +/// config(phantom): std::marker::PhantomData, +/// } +/// ... +/// +/// This adds a field to your `GenesisConfig` with the name `phantom` that you can initialize with +/// `Default::default()`. +/// #[proc_macro] pub fn decl_storage(input: TokenStream) -> TokenStream { storage::transformation::decl_storage_impl(input) diff --git a/srml/support/procedural/src/storage/impls.rs b/srml/support/procedural/src/storage/impls.rs index b481a4242053954cb66d2ee5dbf05a47d0a0c729..d5dc91635bbc9aafa74a4dcade8d1d4ce9efd81a 100644 --- a/srml/support/procedural/src/storage/impls.rs +++ b/srml/support/procedural/src/storage/impls.rs @@ -14,10 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . +use crate::storage::transformation::{DeclStorageTypeInfos, InstanceOpts}; + +use srml_support_procedural_tools::syn_ext as ext; use proc_macro2::TokenStream as TokenStream2; -use syn; +use syn::Ident; use quote::quote; -use crate::storage::transformation::{DeclStorageTypeInfos, InstanceOpts}; pub fn option_unwrap(is_option: bool) -> TokenStream2 { if !is_option { @@ -45,6 +47,7 @@ pub(crate) struct Impls<'a, I: Iterator> { pub cratename: &'a syn::Ident, pub name: &'a syn::Ident, pub attrs: I, + pub where_clause: &'a Option, } impl<'a, I: Iterator> Impls<'a, I> { @@ -60,6 +63,7 @@ impl<'a, I: Iterator> Impls<'a, I> { prefix, name, attrs, + where_clause, .. } = self; let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos; @@ -79,7 +83,6 @@ impl<'a, I: Iterator> Impls<'a, I> { }; let InstanceOpts { - comma_instance, equal_default_instance, bound_instantiable, instance, @@ -87,20 +90,39 @@ impl<'a, I: Iterator> Impls<'a, I> { } = instance_opts; let final_prefix = if let Some(instance) = instance { - let const_name = syn::Ident::new(&format!("{}{}", PREFIX_FOR, name.to_string()), proc_macro2::Span::call_site()); + let const_name = Ident::new(&format!("{}{}", PREFIX_FOR, name.to_string()), proc_macro2::Span::call_site()); quote!{ #instance::#const_name.as_bytes() } } else { quote!{ #prefix.as_bytes() } }; + let (struct_trait, impl_trait, trait_and_instance, where_clause) = if ext::type_contains_ident( + value_type, traitinstance + ) { + ( + quote!(#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance), + quote!(#traitinstance: #traittype, #instance #bound_instantiable), + quote!(#traitinstance, #instance), + where_clause.clone(), + ) + } else { + ( + quote!(#instance #bound_instantiable #equal_default_instance), + quote!(#instance #bound_instantiable), + quote!(#instance), + None, + ) + }; + // generator for value - quote!{ + quote! { #( #[ #attrs ] )* - #visibility struct #name<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance> - (#scrate::rstd::marker::PhantomData<(#traitinstance #comma_instance)>); + #visibility struct #name<#struct_trait>( + #scrate::rstd::marker::PhantomData<(#trait_and_instance)> + ) #where_clause; - impl<#traitinstance: #traittype, #instance #bound_instantiable> - #scrate::storage::hashed::generator::StorageValue<#typ> for #name<#traitinstance, #instance> + impl<#impl_trait> #scrate::storage::hashed::generator::StorageValue<#typ> + for #name<#trait_and_instance> #where_clause { type Query = #value_type; @@ -149,6 +171,7 @@ impl<'a, I: Iterator> Impls<'a, I> { prefix, name, attrs, + where_clause, .. } = self; let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos; @@ -170,7 +193,6 @@ impl<'a, I: Iterator> Impls<'a, I> { }; let InstanceOpts { - comma_instance, equal_default_instance, bound_instantiable, instance, @@ -184,14 +206,34 @@ impl<'a, I: Iterator> Impls<'a, I> { quote!{ #prefix.as_bytes() } }; + let trait_required = ext::type_contains_ident(value_type, traitinstance) + || ext::type_contains_ident(kty, traitinstance); + + let (struct_trait, impl_trait, trait_and_instance, where_clause) = if trait_required { + ( + quote!(#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance), + quote!(#traitinstance: #traittype, #instance #bound_instantiable), + quote!(#traitinstance, #instance), + where_clause.clone(), + ) + } else { + ( + quote!(#instance #bound_instantiable #equal_default_instance), + quote!(#instance #bound_instantiable), + quote!(#instance), + None, + ) + }; + // generator for map quote!{ #( #[ #attrs ] )* - #visibility struct #name<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance> - (#scrate::rstd::marker::PhantomData<(#traitinstance #comma_instance)>); + #visibility struct #name<#struct_trait>( + #scrate::rstd::marker::PhantomData<(#trait_and_instance)> + ) #where_clause; - impl<#traitinstance: #traittype, #instance #bound_instantiable> - #scrate::storage::hashed::generator::StorageMap<#kty, #typ> for #name<#traitinstance, #instance> + impl<#impl_trait> #scrate::storage::hashed::generator::StorageMap<#kty, #typ> + for #name<#trait_and_instance> #where_clause { type Query = #value_type; @@ -235,8 +277,8 @@ impl<'a, I: Iterator> Impls<'a, I> { } } - impl<#traitinstance: 'static + #traittype, #instance #bound_instantiable> - #scrate::storage::hashed::generator::AppendableStorageMap<#kty, #typ> for #name<#traitinstance, #instance> + impl<#impl_trait> #scrate::storage::hashed::generator::AppendableStorageMap<#kty, #typ> + for #name<#trait_and_instance> #where_clause {} } } @@ -253,11 +295,11 @@ impl<'a, I: Iterator> Impls<'a, I> { prefix, name, attrs, + where_clause, .. } = self; let InstanceOpts { - comma_instance, equal_default_instance, bound_instantiable, instance, @@ -265,7 +307,9 @@ impl<'a, I: Iterator> Impls<'a, I> { } = instance_opts; let final_prefix = if let Some(instance) = instance { - let const_name = syn::Ident::new(&format!("{}{}", PREFIX_FOR, name.to_string()), proc_macro2::Span::call_site()); + let const_name = Ident::new( + &format!("{}{}", PREFIX_FOR, name.to_string()), proc_macro2::Span::call_site() + ); quote!{ #instance::#const_name.as_bytes() } } else { quote!{ #prefix.as_bytes() } @@ -273,7 +317,9 @@ impl<'a, I: Iterator> Impls<'a, I> { // make sure to use different prefix for head and elements. let final_head_key = if let Some(instance) = instance { - let const_name = syn::Ident::new(&format!("{}{}", HEAD_KEY_FOR, name.to_string()), proc_macro2::Span::call_site()); + let const_name = Ident::new( + &format!("{}{}", HEAD_KEY_FOR, name.to_string()), proc_macro2::Span::call_site() + ); quote!{ #instance::#const_name.as_bytes() } } else { let final_head_key = format!("head of {}", prefix); @@ -283,8 +329,10 @@ impl<'a, I: Iterator> Impls<'a, I> { let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos; let option_simple_1 = option_unwrap(is_option); let name_lowercase = name.to_string().to_lowercase(); - let inner_module = syn::Ident::new(&format!("__linked_map_details_for_{}_do_not_use", name_lowercase), name.span()); - let linkage = syn::Ident::new(&format!("__LinkageFor{}DoNotUse", name), name.span()); + let inner_module = Ident::new( + &format!("__linked_map_details_for_{}_do_not_use", name_lowercase), name.span() + ); + let linkage = Ident::new(&format!("__LinkageFor{}DoNotUse", name), name.span()); let phantom_data = quote! { #scrate::rstd::marker::PhantomData }; let as_map = quote!{ > }; let put_or_insert = quote! { @@ -304,6 +352,38 @@ impl<'a, I: Iterator> Impls<'a, I> { } }; + let trait_required = ext::type_contains_ident(value_type, traitinstance) + || ext::type_contains_ident(kty, traitinstance); + + let (struct_trait, impl_trait, trait_and_instance) = if trait_required { + ( + quote!(#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance), + quote!(#traitinstance: #traittype, #instance #bound_instantiable), + quote!(#traitinstance, #instance), + ) + } else { + ( + quote!(#instance #bound_instantiable #equal_default_instance), + quote!(#instance #bound_instantiable), + quote!(#instance), + ) + }; + + let (where_clause, trait_where_clause) = if trait_required { + ( + where_clause.clone(), + where_clause.clone().map(|mut wc| { + wc.predicates.push(syn::parse_quote!(#traitinstance: 'static)); + wc + }).or_else(|| syn::parse_quote!(where #traitinstance: 'static)), + ) + } else { + ( + None, + None, + ) + }; + // generator for linked map let helpers = quote! { /// Linkage data of an element (it's successor and predecessor) @@ -337,15 +417,14 @@ impl<'a, I: Iterator> Impls<'a, I> { pub _data: #phantom_data, } - impl<'a, S: #scrate::HashedStorage<#scrate::#hasher>, #traitinstance: #traittype, #instance #bound_instantiable> - Iterator for Enumerator<'a, S, #kty, (#typ, #traitinstance, #instance)> - where #traitinstance: 'a + impl<'a, S: #scrate::HashedStorage<#scrate::#hasher>, #impl_trait> Iterator + for Enumerator<'a, S, #kty, (#typ, #trait_and_instance)> #where_clause { type Item = (#kty, #typ); fn next(&mut self) -> Option { let next = self.next.take()?; - let key_for = + let key_for = as #scrate::storage::hashed::generator::StorageMap<#kty, #typ>>::key_for(&next); let (val, linkage): (#typ, Linkage<#kty>) = self.storage.get(&*key_for) @@ -355,7 +434,7 @@ impl<'a, I: Iterator> Impls<'a, I> { } } - pub(crate) trait Utils<#traitinstance: #traittype, #instance #bound_instantiable> { + pub(crate) trait Utils<#struct_trait> { /// Update linkage when this element is removed. /// /// Takes care of updating previous and next elements points @@ -388,9 +467,11 @@ impl<'a, I: Iterator> Impls<'a, I> { let structure = quote! { #( #[ #attrs ] )* - #visibility struct #name<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance>(#phantom_data<(#traitinstance #comma_instance)>); + #visibility struct #name<#struct_trait>(#phantom_data<(#trait_and_instance)>); - impl<#traitinstance: #traittype, #instance #bound_instantiable> self::#inner_module::Utils<#traitinstance, #instance> for #name<#traitinstance, #instance> { + impl<#impl_trait> self::#inner_module::Utils<#trait_and_instance> + for #name<#trait_and_instance> #where_clause + { fn remove_linkage>( linkage: self::#inner_module::Linkage<#kty>, storage: &mut S, @@ -477,8 +558,8 @@ impl<'a, I: Iterator> Impls<'a, I> { #structure - impl<#traitinstance: #traittype, #instance #bound_instantiable> - #scrate::storage::hashed::generator::StorageMap<#kty, #typ> for #name<#traitinstance, #instance> + impl<#impl_trait> #scrate::storage::hashed::generator::StorageMap<#kty, #typ> + for #name<#trait_and_instance> #where_clause { type Query = #value_type; @@ -553,8 +634,8 @@ impl<'a, I: Iterator> Impls<'a, I> { } } - impl<#traitinstance: 'static + #traittype, #instance #bound_instantiable> - #scrate::storage::hashed::generator::EnumerableStorageMap<#kty, #typ> for #name<#traitinstance, #instance> + impl<#impl_trait> #scrate::storage::hashed::generator::EnumerableStorageMap<#kty, #typ> + for #name<#trait_and_instance> #trait_where_clause { fn head>(storage: &S) -> Option<#kty> { use self::#inner_module::Utils; @@ -562,18 +643,20 @@ impl<'a, I: Iterator> Impls<'a, I> { Self::read_head(storage) } - fn enumerate<'a, S>(storage: &'a S) -> #scrate::rstd::boxed::Box + 'a> - where - S: #scrate::HashedStorage<#scrate::#hasher>, - #kty: 'a, - #typ: 'a, + fn enumerate<'a, S>( + storage: &'a S + ) -> #scrate::rstd::boxed::Box + 'a> + where + S: #scrate::HashedStorage<#scrate::#hasher>, + #kty: 'a, + #typ: 'a, { use self::#inner_module::{Utils, Enumerator}; #scrate::rstd::boxed::Box::new(Enumerator { next: Self::read_head(storage), storage, - _data: #phantom_data::<(#typ, #traitinstance, #instance)>::default(), + _data: #phantom_data::<(#typ, #trait_and_instance)>::default(), }) } } @@ -598,13 +681,16 @@ impl<'a, I: Iterator> Impls<'a, I> { name, attrs, instance_opts, + where_clause, .. } = self; let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos; let option_simple_1 = option_unwrap(is_option); - let as_double_map = quote!{ > }; + let as_double_map = quote!{ + > + }; let mutate_impl = if !is_option { quote!{ @@ -620,7 +706,6 @@ impl<'a, I: Iterator> Impls<'a, I> { }; let InstanceOpts { - comma_instance, equal_default_instance, bound_instantiable, instance, @@ -628,20 +713,41 @@ impl<'a, I: Iterator> Impls<'a, I> { } = instance_opts; let final_prefix = if let Some(instance) = instance { - let const_name = syn::Ident::new(&format!("{}{}", PREFIX_FOR, name.to_string()), proc_macro2::Span::call_site()); + let const_name = Ident::new( + &format!("{}{}", PREFIX_FOR, name.to_string()), proc_macro2::Span::call_site() + ); quote!{ #instance::#const_name.as_bytes() } } else { quote!{ #prefix.as_bytes() } }; + let (struct_trait, impl_trait, trait_and_instance, where_clause) = if ext::type_contains_ident( + value_type, traitinstance + ) || ext::type_contains_ident(k1ty, traitinstance) || ext::type_contains_ident(k2ty, traitinstance) + { + ( + quote!(#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance), + quote!(#traitinstance: #traittype, #instance #bound_instantiable), + quote!(#traitinstance, #instance), + where_clause.clone(), + ) + } else { + ( + quote!(#instance #bound_instantiable #equal_default_instance), + quote!(#instance #bound_instantiable), + quote!(#instance), + None, + ) + }; + // generator for double map quote!{ #( #[ #attrs ] )* - #visibility struct #name<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance> - (#scrate::rstd::marker::PhantomData<(#traitinstance #comma_instance)>); + #visibility struct #name<#struct_trait> + (#scrate::rstd::marker::PhantomData<(#trait_and_instance)>); - impl<#traitinstance: #traittype, #instance #bound_instantiable> - #scrate::storage::unhashed::generator::StorageDoubleMap<#k1ty, #k2ty, #typ> for #name<#traitinstance, #instance> + impl<#impl_trait> #scrate::storage::unhashed::generator::StorageDoubleMap<#k1ty, #k2ty, #typ> + for #name<#trait_and_instance> #where_clause { type Query = #value_type; @@ -686,9 +792,7 @@ impl<'a, I: Iterator> Impls<'a, I> { #mutate_impl ; ret } - } } - } } diff --git a/srml/support/procedural/src/storage/mod.rs b/srml/support/procedural/src/storage/mod.rs index 742c47d259350649319910376ea61fd5bc6ce937..4253206f44da064d5903362c3ed72aedbb51a0c7 100644 --- a/srml/support/procedural/src/storage/mod.rs +++ b/srml/support/procedural/src/storage/mod.rs @@ -65,9 +65,9 @@ struct StorageDefinition { pub mod_gt_token: Token![>], pub as_token: Token![as], pub crate_ident: Ident, + pub where_clause: Option, pub content: ext::Braces>, pub extra_genesis: ext::Opt, - pub extra_genesis_skip_phantom_data_field: ext::Opt, } #[derive(Parse, ToTokens, Debug)] @@ -82,12 +82,6 @@ struct AddExtraGenesis { pub content: ext::Braces, } -#[derive(Parse, ToTokens, Debug)] -struct ExtraGenesisSkipPhantomDataField { - pub genesis_phantom_keyword: keyword::extra_genesis_skip_phantom_data_field, - pub token: Token![;], -} - #[derive(Parse, ToTokens, Debug)] struct AddExtraGenesisContent { pub lines: ext::Punctuated, diff --git a/srml/support/procedural/src/storage/transformation.rs b/srml/support/procedural/src/storage/transformation.rs index 2827259420991ddd454b1d1c715599b3d854c33a..6f0cf93179eafb2c5379ec2cbe1be0883088503e 100644 --- a/srml/support/procedural/src/storage/transformation.rs +++ b/srml/support/procedural/src/storage/transformation.rs @@ -14,19 +14,20 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -// tag::description[] //! `decl_storage` macro transformation -// end::description[] use srml_support_procedural_tools::syn_ext as ext; -use srml_support_procedural_tools::{generate_crate_access, generate_hidden_includes, clean_type_string}; +use srml_support_procedural_tools::{ + generate_crate_access, generate_hidden_includes, clean_type_string +}; use proc_macro::TokenStream; -use proc_macro2::TokenStream as TokenStream2; +use proc_macro2::{TokenStream as TokenStream2, Span}; use syn::{ Ident, GenericParam, + WhereClause, spanned::Spanned, parse::{ Error, @@ -39,6 +40,9 @@ use quote::quote; use super::*; const NUMBER_OF_INSTANCE: usize = 16; +const DEFAULT_INSTANTIABLE_TRAIT_NAME: &str = "__GeneratedInstantiable"; +const DEFAULT_INSTANCE_NAME: &str = "__GeneratedInstance"; +const INHERENT_INSTANCE_NAME: &str = "__InherentHiddenInstance"; // try macro but returning tokenized error macro_rules! try_tok(( $expre : expr ) => { @@ -65,11 +69,15 @@ pub fn decl_storage_impl(input: TokenStream) -> TokenStream { crate_ident: cratename, content: ext::Braces { content: storage_lines, ..}, extra_genesis, - extra_genesis_skip_phantom_data_field, + where_clause, .. } = def; - let instance_opts = match get_instance_opts(mod_instance, mod_instantiable, mod_default_instance) { + let instance_opts = match get_instance_opts( + mod_instance, + mod_instantiable, + mod_default_instance + ) { Ok(opts) => opts, Err(err) => return err.to_compile_error().into(), }; @@ -104,7 +112,7 @@ pub fn decl_storage_impl(input: TokenStream) -> TokenStream { &instance_opts, &storage_lines, &extra_genesis.inner, - extra_genesis_skip_phantom_data_field.inner.is_some(), + &where_clause, )); let decl_storage_items = decl_storage_items( &scrate, @@ -113,7 +121,9 @@ pub fn decl_storage_impl(input: TokenStream) -> TokenStream { &instance_opts, &cratename, &storage_lines, + &where_clause, ); + let decl_store_items = decl_store_items( &storage_lines, ); @@ -134,6 +144,7 @@ pub fn decl_storage_impl(input: TokenStream) -> TokenStream { &traittype, &instance_opts, &storage_lines, + &where_clause, ); let InstanceOpts { @@ -150,19 +161,17 @@ pub fn decl_storage_impl(input: TokenStream) -> TokenStream { #decl_store_items } #store_default_struct - impl<#traitinstance: #traittype, #instance #bound_instantiable> #storetype for #module_ident<#traitinstance, #instance> { + impl<#traitinstance: #traittype, #instance #bound_instantiable> #storetype + for #module_ident<#traitinstance, #instance> #where_clause + { #impl_store_items } - impl<#traitinstance: 'static + #traittype, #instance #bound_instantiable> #module_ident<#traitinstance, #instance> { + impl<#traitinstance: 'static + #traittype, #instance #bound_instantiable> + #module_ident<#traitinstance, #instance> #where_clause + { #impl_store_fns #[doc(hidden)] - pub fn store_metadata() -> #scrate::metadata::StorageMetadata { - #scrate::metadata::StorageMetadata { - functions: #scrate::metadata::DecodeDifferent::Encode(#store_functions_to_metadata) , - } - } - #[doc(hidden)] - pub fn store_metadata_functions() -> &'static [#scrate::metadata::StorageFunctionMetadata] { + pub fn store_metadata_functions() -> &'static [#scrate::metadata::StorageEntryMetadata] { #store_functions_to_metadata } #[doc(hidden)] @@ -172,7 +181,6 @@ pub fn decl_storage_impl(input: TokenStream) -> TokenStream { } #extra_genesis - }; expanded.into() @@ -185,11 +193,10 @@ fn decl_store_extra_genesis( instance_opts: &InstanceOpts, storage_lines: &ext::Punctuated, extra_genesis: &Option, - extra_genesis_skip_phantom_data_field: bool, + where_clause: &Option, ) -> Result { let InstanceOpts { - comma_instance, equal_default_instance, bound_instantiable, instance, @@ -197,13 +204,14 @@ fn decl_store_extra_genesis( } = instance_opts; let mut is_trait_needed = false; - let mut has_trait_field = false; let mut serde_complete_bound = Vec::new(); let mut config_field = TokenStream2::new(); let mut config_field_default = TokenStream2::new(); let mut builders = TokenStream2::new(); - for sline in storage_lines.inner.iter() { + let mut assimilate_require_generic = instance.is_some(); + let mut builders_clone_bound = Vec::new(); + for sline in storage_lines.inner.iter() { let DeclStorageLine { attrs, name, @@ -217,9 +225,17 @@ fn decl_store_extra_genesis( let type_infos = get_type_infos(storage_type); - let opt_build; + let opt_build = build + .inner + .as_ref() + .map(|b| { + assimilate_require_generic |= ext::expr_contains_ident(&b.expr.content, traitinstance); + &b.expr.content + }) + .map(|b| quote!( #b )); + // need build line - if let Some(ref config) = config.inner { + let builder = if let Some(ref config) = config.inner { let ident = if let Some(ident) = config.expr.content.as_ref() { quote!( #ident ) } else if let Some(ref getter) = getter.inner { @@ -234,19 +250,37 @@ fn decl_store_extra_genesis( ) ); }; - if type_infos.kind.is_simple() && ext::has_parametric_type(type_infos.value_type, traitinstance) { + + if ext::type_contains_ident(type_infos.value_type, traitinstance) { is_trait_needed = true; - has_trait_field = true; + } + + if opt_build.is_none() { + builders_clone_bound.push(type_infos.value_type.clone()); } let value_type = &type_infos.value_type; serde_complete_bound.push(quote!( #value_type )); match type_infos.kind { - DeclStorageTypeInfosKind::Map { key_type, .. } => - serde_complete_bound.push(quote!( #key_type )), + DeclStorageTypeInfosKind::Map { key_type, .. } => { + serde_complete_bound.push(quote!( #key_type )); + is_trait_needed = is_trait_needed + || ext::type_contains_ident(key_type, traitinstance); + + if opt_build.is_none() { + builders_clone_bound.push(key_type.clone()); + } + }, DeclStorageTypeInfosKind::DoubleMap { key1_type, key2_type, .. } => { serde_complete_bound.push(quote!( #key1_type )); serde_complete_bound.push(quote!( #key2_type )); + is_trait_needed = is_trait_needed + || ext::type_contains_ident(key1_type, traitinstance) + || ext::type_contains_ident(key2_type, traitinstance); + if opt_build.is_none() { + builders_clone_bound.push(key1_type.clone()); + builders_clone_bound.push(key2_type.clone()); + } }, _ => {}, } @@ -270,8 +304,6 @@ fn decl_store_extra_genesis( quote!( #( #[ #attrs ] )* pub #ident: Vec<(#key1_type, #key2_type, #storage_type)>, ) }, }); - opt_build = Some(build.inner.as_ref().map(|b| &b.expr.content).map(|b|quote!( #b )) - .unwrap_or_else(|| quote!( (|config: &GenesisConfig<#traitinstance, #instance>| config.#ident.clone()) ))); let fielddefault = default_value.inner.as_ref().map(|d| &d.expr).map(|d| if type_infos.is_option { @@ -281,48 +313,74 @@ fn decl_store_extra_genesis( }).unwrap_or_else(|| quote!( Default::default() )); config_field_default.extend(quote!( #ident: #fielddefault, )); + + opt_build.or_else(|| Some(quote!( (|config: &Self| config.#ident.clone()) ))) } else { - opt_build = build.inner.as_ref().map(|b| &b.expr.content).map(|b| quote!( #b )); - } + opt_build + }; let typ = type_infos.typ; - if let Some(builder) = opt_build { - is_trait_needed = true; + if let Some(builder) = builder { builders.extend(match type_infos.kind { DeclStorageTypeInfosKind::Simple => { - quote!{{ - use #scrate::rstd::{cell::RefCell, marker::PhantomData}; - use #scrate::codec::{Encode, Decode}; + let struct_trait = if ext::type_contains_ident(&type_infos.value_type, traitinstance) { + assimilate_require_generic = true; + quote!(#traitinstance,) + } else { + quote!() + }; + quote!{{ let v = (#builder)(&self); - <#name<#traitinstance, #instance> as #scrate::storage::hashed::generator::StorageValue<#typ>>::put(&v, storage); + < + #name<#struct_trait #instance> as + #scrate::storage::hashed::generator::StorageValue<#typ> + >::put(&v, storage); }} }, DeclStorageTypeInfosKind::Map { key_type, .. } => { - quote!{{ - use #scrate::rstd::{cell::RefCell, marker::PhantomData}; - use #scrate::codec::{Encode, Decode}; + let struct_trait = if ext::type_contains_ident(&type_infos.value_type, traitinstance) + || ext::type_contains_ident(key_type, traitinstance) + { + assimilate_require_generic = true; + quote!(#traitinstance,) + } else { + quote!() + }; + quote!{{ let data = (#builder)(&self); - for (k, v) in data.into_iter() { - <#name<#traitinstance, #instance> as #scrate::storage::hashed::generator::StorageMap<#key_type, #typ>>::insert(&k, &v, storage); - } + data.into_iter().for_each(|(k, v)| { + < + #name<#struct_trait #instance> as + #scrate::storage::hashed::generator::StorageMap<#key_type, #typ> + >::insert(&k, &v, storage); + }); }} }, DeclStorageTypeInfosKind::DoubleMap { key1_type, key2_type, .. } => { - quote!{{ - use #scrate::rstd::{cell::RefCell, marker::PhantomData}; - use #scrate::codec::{Encode, Decode}; + let struct_trait = if ext::type_contains_ident(&type_infos.value_type, traitinstance) + || ext::type_contains_ident(key1_type, traitinstance) + || ext::type_contains_ident(key2_type, traitinstance) + { + assimilate_require_generic = true; + quote!(#traitinstance,) + } else { + quote!() + }; + quote!{{ let data = (#builder)(&self); - for (k1, k2, v) in data.into_iter() { - <#name<#traitinstance, #instance> as #scrate::storage::unhashed::generator::StorageDoubleMap<#key1_type, #key2_type, #typ>>::insert(&k1, &k2, &v, storage); - } + data.into_iter().for_each(|(k1, k2, v)| { + < + #name<#struct_trait #instance> as + #scrate::storage::unhashed::generator::StorageDoubleMap<#key1_type, #key2_type, #typ> + >::insert(&k1, &k2, &v, storage); + }); }} }, }); } - } let mut has_scall = false; @@ -341,9 +399,8 @@ fn decl_store_extra_genesis( default_value, .. }) => { - if ext::has_parametric_type(&extra_type, traitinstance) { + if ext::type_contains_ident(&extra_type, traitinstance) { is_trait_needed = true; - has_trait_field = true; } serde_complete_bound.push(quote!( #extra_type )); @@ -362,6 +419,7 @@ fn decl_store_extra_genesis( if has_scall { return Err(Error::new(expr.span(), "Only one build expression allowed for extra genesis")); } + assimilate_require_generic |= ext::expr_contains_ident(&expr.content, traitinstance); let content = &expr.content; scall = quote!( ( #content ) ); has_scall = true; @@ -370,7 +428,6 @@ fn decl_store_extra_genesis( } } - let serde_bug_bound = if !serde_complete_bound.is_empty() { let mut b_ser = String::new(); let mut b_dser = String::new(); @@ -393,55 +450,81 @@ fn decl_store_extra_genesis( || !config_field.is_empty() || !genesis_extrafields.is_empty() || !builders.is_empty(); - Ok(if is_extra_genesis_needed { - let (fparam_struct, fparam_impl, sparam, ph_field, ph_default) = if is_trait_needed { - if (has_trait_field && instance.is_none()) || extra_genesis_skip_phantom_data_field { - // no phantom data required - ( - quote!(<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance>), - quote!(<#traitinstance: #traittype, #instance #bound_instantiable>), - quote!(<#traitinstance, #instance>), - quote!(), - quote!(), - ) - } else { - // need phantom data - ( - quote!(<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance>), - quote!(<#traitinstance: #traittype, #instance #bound_instantiable>), - quote!(<#traitinstance, #instance>), + if is_extra_genesis_needed { + let (inherent_instance, inherent_bound_instantiable) = if instance.is_some() { + (instance.clone(), bound_instantiable.clone()) + } else { + let instantiable = Ident::new(DEFAULT_INSTANTIABLE_TRAIT_NAME, Span::call_site()); + ( + Some(Ident::new(DEFAULT_INSTANCE_NAME, Span::call_site())), + quote!(: #instantiable), + ) + }; - quote!{ - #[serde(skip)] - pub _genesis_phantom_data: #scrate::rstd::marker::PhantomData<(#traitinstance #comma_instance)>, - }, - quote!{ - _genesis_phantom_data: Default::default(), - }, - ) - } + let (fparam_struct, fparam_impl, sparam, build_storage_impl) = if is_trait_needed { + ( + quote!(<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance>), + quote!(<#traitinstance: #traittype, #instance #bound_instantiable>), + quote!(<#traitinstance, #instance>), + quote!(<#traitinstance: #traittype, #inherent_instance #inherent_bound_instantiable>), + ) } else { // do not even need type parameter - (quote!(), quote!(), quote!(), quote!(), quote!()) + ( + quote!(), + quote!(), + quote!(), + quote!(<#traitinstance: #traittype, #inherent_instance #inherent_bound_instantiable>), + ) }; - quote!{ + let (fn_generic, fn_traitinstance) = if !is_trait_needed && assimilate_require_generic { + ( + quote!( <#traitinstance: #traittype, #instance #bound_instantiable> ), + quote!( #traitinstance, #instance ) + ) + } else { + (quote!(), quote!()) + }; + + let impl_trait = quote!(BuildModuleGenesisStorage<#traitinstance, #inherent_instance>); + + let extend_where_clause = |to_extend: &mut WhereClause| { + if let Some(where_clause) = where_clause { + to_extend.predicates.extend(where_clause.predicates.iter().cloned()); + } + }; + + let mut genesis_where_clause: WhereClause = syn::parse_quote!( + where #( #builders_clone_bound: Clone ),* + ); + let mut fn_where_clause = genesis_where_clause.clone(); + + + let mut build_storage_where_clause = genesis_where_clause.clone(); + extend_where_clause(&mut build_storage_where_clause); + + if is_trait_needed { + extend_where_clause(&mut genesis_where_clause); + } else if assimilate_require_generic { + extend_where_clause(&mut fn_where_clause); + } + + let res = quote!{ #[derive(#scrate::Serialize, #scrate::Deserialize)] #[cfg(feature = "std")] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] #serde_bug_bound - pub struct GenesisConfig#fparam_struct { - #ph_field + pub struct GenesisConfig#fparam_struct #genesis_where_clause { #config_field #genesis_extrafields } #[cfg(feature = "std")] - impl#fparam_impl Default for GenesisConfig#sparam { + impl#fparam_impl Default for GenesisConfig#sparam #genesis_where_clause { fn default() -> Self { GenesisConfig { - #ph_default #config_field_default #genesis_extrafields_default } @@ -449,23 +532,83 @@ fn decl_store_extra_genesis( } #[cfg(feature = "std")] - impl#fparam_impl #scrate::runtime_primitives::BuildStorage for GenesisConfig#sparam { - fn assimilate_storage(self, r: &mut #scrate::runtime_primitives::StorageOverlay, c: &mut #scrate::runtime_primitives::ChildrenStorageOverlay) -> ::std::result::Result<(), String> { + impl#fparam_impl GenesisConfig#sparam #genesis_where_clause { + pub fn build_storage #fn_generic (self) -> std::result::Result< + ( + #scrate::runtime_primitives::StorageOverlay, + #scrate::runtime_primitives::ChildrenStorageOverlay, + ), + String + > #fn_where_clause { + let mut storage = Default::default(); + let mut child_storage = Default::default(); + self.assimilate_storage::<#fn_traitinstance>(&mut storage, &mut child_storage)?; + Ok((storage, child_storage)) + } + + /// Assimilate the storage for this module into pre-existing overlays. + pub fn assimilate_storage #fn_generic ( + self, + r: &mut #scrate::runtime_primitives::StorageOverlay, + c: &mut #scrate::runtime_primitives::ChildrenStorageOverlay, + ) -> std::result::Result<(), String> #fn_where_clause { let storage = r; #builders - let r = storage; - - #scall(r, c, &self); + #scall(storage, c, &self); Ok(()) } } - } + + #[cfg(feature = "std")] + impl#build_storage_impl #scrate::runtime_primitives::#impl_trait + for GenesisConfig#sparam #build_storage_where_clause + { + fn build_module_genesis_storage( + self, + r: &mut #scrate::runtime_primitives::StorageOverlay, + c: &mut #scrate::runtime_primitives::ChildrenStorageOverlay, + ) -> std::result::Result<(), String> { + self.assimilate_storage::<#fn_traitinstance> (r, c) + } + } + }; + + Ok(res) } else { - quote!() - }) + Ok(quote!()) + } +} + +fn create_and_impl_instance( + prefix: &str, + ident: &Ident, + doc: &TokenStream2, + const_names: &[(Ident, String)], + scrate: &TokenStream2, + instantiable: &Ident, +) -> TokenStream2 { + let mut const_impls = TokenStream2::new(); + + for (const_name, partial_const_value) in const_names { + let const_value = format!("{}{}", partial_const_value, prefix); + const_impls.extend(quote! { + const #const_name: &'static str = #const_value; + }); + } + + quote! { + // Those trait are derived because of wrong bounds for generics + #[cfg_attr(feature = "std", derive(Debug))] + #[derive(Clone, Eq, PartialEq, #scrate::codec::Encode, #scrate::codec::Decode)] + #doc + pub struct #ident; + impl #instantiable for #ident { + #const_impls + } + } } fn decl_storage_items( @@ -475,6 +618,7 @@ fn decl_storage_items( instance_opts: &InstanceOpts, cratename: &Ident, storage_lines: &ext::Punctuated, + where_clause: &Option, ) -> TokenStream2 { let mut impls = TokenStream2::new(); @@ -489,80 +633,101 @@ fn decl_storage_items( let build_prefix = |cratename, name| format!("{} {}", cratename, name); // Build Instantiable trait - if instance.is_some() { - let mut const_names = vec![]; + let mut const_names = vec![]; - for sline in storage_lines.inner.iter() { - let DeclStorageLine { - storage_type, - name, - .. - } = sline; + for sline in storage_lines.inner.iter() { + let DeclStorageLine { + storage_type, + name, + .. + } = sline; - let prefix = build_prefix(cratename, name); + let prefix = build_prefix(cratename, name); - let type_infos = get_type_infos(storage_type); + let type_infos = get_type_infos(storage_type); - let const_name = syn::Ident::new(&format!("{}{}", impls::PREFIX_FOR, name.to_string()), proc_macro2::Span::call_site()); - let partial_const_value = prefix.clone(); - const_names.push((const_name, partial_const_value)); + let const_name = syn::Ident::new( + &format!("{}{}", impls::PREFIX_FOR, name.to_string()), proc_macro2::Span::call_site() + ); + let partial_const_value = prefix.clone(); + const_names.push((const_name, partial_const_value)); - if let DeclStorageTypeInfosKind::Map { is_linked: true, .. } = type_infos.kind { - let const_name = syn::Ident::new(&format!("{}{}", impls::HEAD_KEY_FOR, name.to_string()), proc_macro2::Span::call_site()); - let partial_const_value = format!("head of {}", prefix); - const_names.push((const_name, partial_const_value)); - } + if let DeclStorageTypeInfosKind::Map { is_linked: true, .. } = type_infos.kind { + let const_name = syn::Ident::new( + &format!("{}{}", impls::HEAD_KEY_FOR, name.to_string()), proc_macro2::Span::call_site() + ); + let partial_const_value = format!("head of {}", prefix); + const_names.push((const_name, partial_const_value)); } + } - // Declare Instance trait - { - let mut const_impls = TokenStream2::new(); - for (const_name, _) in &const_names { - const_impls.extend(quote! { - const #const_name: &'static str; - }); - } + let instantiable = instantiable + .clone() + .unwrap_or_else(|| Ident::new(DEFAULT_INSTANTIABLE_TRAIT_NAME, Span::call_site())); - impls.extend(quote! { - /// Tag a type as an instance of a module. - /// - /// Defines storage prefixes, they must be unique. - pub trait #instantiable: 'static { - #const_impls - } + // Declare Instance trait + { + let mut const_impls = TokenStream2::new(); + for (const_name, _) in &const_names { + const_impls.extend(quote! { + const #const_name: &'static str; }); } + let hide = if instance.is_some() { + quote!() + } else { + quote!(#[doc(hidden)]) + }; + + impls.extend(quote! { + /// Tag a type as an instance of a module. + /// + /// Defines storage prefixes, they must be unique. + #hide + pub trait #instantiable: 'static { + #const_impls + } + }); + } + + if instance.is_some() { let instances = (0..NUMBER_OF_INSTANCE) .map(|i| { let name = format!("Instance{}", i); - let ident = syn::Ident::new(&name, proc_macro2::Span::call_site()); + let ident = Ident::new(&name, proc_macro2::Span::call_site()); (name, ident, quote! {#[doc=r"Module instance"]}) }) - .chain(default_instance.clone().map(|ident| (String::new(), ident, quote! {#[doc=r"Default module instance"]}))); + .chain( + default_instance + .clone() + .map(|ident| + (String::new(), ident, quote! {#[doc=r"Default module instance"]}) + ) + ); // Impl Instance trait for instances for (prefix, ident, doc) in instances { - let mut const_impls = TokenStream2::new(); + impls.extend( + create_and_impl_instance(&prefix, &ident, &doc, &const_names, scrate, &instantiable) + ); + } + } - for (const_name, partial_const_value) in &const_names { - let const_value = format!("{}{}", partial_const_value, prefix); - const_impls.extend(quote! { - const #const_name: &'static str = #const_value; - }); - } + // The name of the inherently available instance. + let inherent_instance = Ident::new(INHERENT_INSTANCE_NAME, Span::call_site()); - impls.extend(quote! { - // Those trait are derived because of wrong bounds for generics - #[cfg_attr(feature = "std", derive(Debug))] - #[derive(Clone, Eq, PartialEq, #scrate::codec::Encode, #scrate::codec::Decode)] - #doc - pub struct #ident; - impl #instantiable for #ident { - #const_impls - } - }); - } + if default_instance.is_some() { + impls.extend(quote! { + #[doc(hidden)] + pub type #inherent_instance = #default_instance; + }); + } else { + impls.extend( + create_and_impl_instance( + "", &inherent_instance, "e!(#[doc(hidden)]), &const_names, scrate, &instantiable + ) + ); } for sline in storage_lines.inner.iter() { @@ -593,6 +758,7 @@ fn decl_storage_items( prefix: build_prefix(cratename, name), name, attrs, + where_clause, }; let implementation = match kind { @@ -630,15 +796,39 @@ fn impl_store_items( instance: &Option, storage_lines: &ext::Punctuated, ) -> TokenStream2 { - storage_lines.inner.iter().map(|sline| &sline.name) - .fold(TokenStream2::new(), |mut items, name| { + storage_lines.inner + .iter() + .fold(TokenStream2::new(), |mut items, line| { + let name = &line.name; + let type_infos = get_type_infos(&line.storage_type); + let requires_trait = match type_infos.kind { + DeclStorageTypeInfosKind::Simple => { + ext::type_contains_ident(&type_infos.value_type, traitinstance) + }, + DeclStorageTypeInfosKind::Map { key_type, .. } => { + ext::type_contains_ident(&type_infos.value_type, traitinstance) + || ext::type_contains_ident(key_type, traitinstance) + } + DeclStorageTypeInfosKind::DoubleMap { key1_type, key2_type, .. } => { + ext::type_contains_ident(&type_infos.value_type, traitinstance) + || ext::type_contains_ident(key1_type, traitinstance) + || ext::type_contains_ident(key2_type, traitinstance) + } + }; + + let struct_trait = if requires_trait { + quote!(#traitinstance,) + } else { + quote!() + }; + items.extend( quote!( - type #name = #name<#traitinstance, #instance>; + type #name = #name<#struct_trait #instance>; ) ); items - }) + }) } fn impl_store_fns( @@ -669,29 +859,61 @@ fn impl_store_fns( let typ = type_infos.typ; let item = match type_infos.kind { DeclStorageTypeInfosKind::Simple => { + let struct_trait = if ext::type_contains_ident(&type_infos.value_type, traitinstance) { + quote!(#traitinstance,) + } else { + quote!() + }; + quote!{ #( #[ #attrs ] )* pub fn #get_fn() -> #value_type { - <#name<#traitinstance, #instance> as #scrate::storage::hashed::generator::StorageValue<#typ>> :: get(&#scrate::storage::RuntimeStorage) + <#name<#struct_trait #instance> as + #scrate::storage::hashed::generator::StorageValue<#typ>> :: get( + &#scrate::storage::RuntimeStorage + ) } } }, DeclStorageTypeInfosKind::Map { key_type, .. } => { + let struct_trait = if ext::type_contains_ident(&type_infos.value_type, traitinstance) + || ext::type_contains_ident(key_type, traitinstance) + { + quote!(#traitinstance,) + } else { + quote!() + }; + quote!{ #( #[ #attrs ] )* pub fn #get_fn>(key: K) -> #value_type { - <#name<#traitinstance, #instance> as #scrate::storage::hashed::generator::StorageMap<#key_type, #typ>> :: get(key.borrow(), &#scrate::storage::RuntimeStorage) + < + #name<#struct_trait #instance> as + #scrate::storage::hashed::generator::StorageMap<#key_type, #typ> + >::get(key.borrow(), &#scrate::storage::RuntimeStorage) } } } DeclStorageTypeInfosKind::DoubleMap { key1_type, key2_type, .. } => { + let struct_trait = if ext::type_contains_ident(&type_infos.value_type, traitinstance) + || ext::type_contains_ident(key1_type, traitinstance) + || ext::type_contains_ident(key2_type, traitinstance) + { + quote!(#traitinstance,) + } else { + quote!() + }; + quote!{ pub fn #get_fn(k1: KArg1, k2: KArg2) -> #value_type where KArg1: #scrate::rstd::borrow::Borrow<#key1_type>, KArg2: #scrate::rstd::borrow::Borrow<#key2_type>, { - <#name<#traitinstance> as #scrate::storage::unhashed::generator::StorageDoubleMap<#key1_type, #key2_type, #typ>> :: get(k1.borrow(), k2.borrow(), &#scrate::storage::RuntimeStorage) + < + #name<#struct_trait #instance> as + #scrate::storage::unhashed::generator::StorageDoubleMap<#key1_type, #key2_type, #typ> + >::get(k1.borrow(), k2.borrow(), &#scrate::storage::RuntimeStorage) } } } @@ -708,6 +930,7 @@ fn store_functions_to_metadata ( traittype: &syn::TypeParamBound, instance_opts: &InstanceOpts, storage_lines: &ext::Punctuated, + where_clause: &Option, ) -> (TokenStream2, TokenStream2) { let InstanceOpts { @@ -737,7 +960,7 @@ fn store_functions_to_metadata ( let stype = match type_infos.kind { DeclStorageTypeInfosKind::Simple => { quote!{ - #scrate::metadata::StorageFunctionType::Plain( + #scrate::metadata::StorageEntryType::Plain( #scrate::metadata::DecodeDifferent::Encode(#styp), ) } @@ -746,7 +969,7 @@ fn store_functions_to_metadata ( let hasher = hasher.into_metadata(); let kty = clean_type_string("e!(#key_type).to_string()); quote!{ - #scrate::metadata::StorageFunctionType::Map { + #scrate::metadata::StorageEntryType::Map { hasher: #scrate::metadata::#hasher, key: #scrate::metadata::DecodeDifferent::Encode(#kty), value: #scrate::metadata::DecodeDifferent::Encode(#styp), @@ -760,7 +983,7 @@ fn store_functions_to_metadata ( let k2ty = clean_type_string("e!(#key2_type).to_string()); let k2_hasher = key2_hasher.into_metadata(); quote!{ - #scrate::metadata::StorageFunctionType::DoubleMap { + #scrate::metadata::StorageEntryType::DoubleMap { hasher: #scrate::metadata::#hasher, key1: #scrate::metadata::DecodeDifferent::Encode(#k1ty), key2: #scrate::metadata::DecodeDifferent::Encode(#k2ty), @@ -772,11 +995,11 @@ fn store_functions_to_metadata ( }; let modifier = if type_infos.is_option { quote!{ - #scrate::metadata::StorageFunctionModifier::Optional + #scrate::metadata::StorageEntryModifier::Optional } } else { quote!{ - #scrate::metadata::StorageFunctionModifier::Default + #scrate::metadata::StorageEntryModifier::Default } }; let default = default_value.inner.as_ref().map(|d| &d.expr) @@ -799,8 +1022,9 @@ fn store_functions_to_metadata ( let str_name = name.to_string(); let struct_name = proc_macro2::Ident::new(&("__GetByteStruct".to_string() + &str_name), name.span()); let cache_name = proc_macro2::Ident::new(&("__CACHE_GET_BYTE_STRUCT_".to_string() + &str_name), name.span()); + let item = quote! { - #scrate::metadata::StorageFunctionMetadata { + #scrate::metadata::StorageEntryMetadata { name: #scrate::metadata::DecodeDifferent::Encode(#str_name), modifier: #modifier, ty: #stype, @@ -813,14 +1037,21 @@ fn store_functions_to_metadata ( }, }; items.extend(item); + let def_get = quote! { #[doc(hidden)] - pub struct #struct_name<#traitinstance, #instance #bound_instantiable #equal_default_instance>(pub #scrate::rstd::marker::PhantomData<(#traitinstance #comma_instance)>); + pub struct #struct_name< + #traitinstance, #instance #bound_instantiable #equal_default_instance + >(pub #scrate::rstd::marker::PhantomData<(#traitinstance #comma_instance)>); + #[cfg(feature = "std")] #[allow(non_upper_case_globals)] static #cache_name: #scrate::once_cell::sync::OnceCell<#scrate::rstd::vec::Vec> = #scrate::once_cell::sync::OnceCell::INIT; + #[cfg(feature = "std")] - impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::metadata::DefaultByte for #struct_name<#traitinstance, #instance> { + impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::metadata::DefaultByte + for #struct_name<#traitinstance, #instance> #where_clause + { fn default_byte(&self) -> #scrate::rstd::vec::Vec { use #scrate::codec::Encode; #cache_name.get_or_init(|| { @@ -829,8 +1060,11 @@ fn store_functions_to_metadata ( }).clone() } } + #[cfg(not(feature = "std"))] - impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::metadata::DefaultByte for #struct_name<#traitinstance, #instance> { + impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::metadata::DefaultByte + for #struct_name<#traitinstance, #instance> #where_clause + { fn default_byte(&self) -> #scrate::rstd::vec::Vec { use #scrate::codec::Encode; let def_val: #value_type = #default; @@ -838,6 +1072,7 @@ fn store_functions_to_metadata ( } } }; + default_getter_struct_def.extend(def_get); } (default_getter_struct_def, quote!{ @@ -874,15 +1109,6 @@ enum DeclStorageTypeInfosKind<'a> { } } -impl<'a> DeclStorageTypeInfosKind<'a> { - fn is_simple(&self) -> bool { - match *self { - DeclStorageTypeInfosKind::Simple => true, - _ => false, - } - } -} - fn get_type_infos(storage_type: &DeclStorageType) -> DeclStorageTypeInfos { let (value_type, kind) = match storage_type { DeclStorageType::Simple(ref st) => (st, DeclStorageTypeInfosKind::Simple), @@ -919,29 +1145,29 @@ fn get_type_infos(storage_type: &DeclStorageType) -> DeclStorageTypeInfos { #[derive(Default)] pub(crate) struct InstanceOpts { - pub instance: Option, - pub default_instance: Option, - pub instantiable: Option, + pub instance: Option, + pub default_instance: Option, + pub instantiable: Option, pub comma_instance: TokenStream2, pub equal_default_instance: TokenStream2, pub bound_instantiable: TokenStream2, } fn get_instance_opts( - instance: Option, - instantiable: Option, - default_instance: Option, -) -> syn::Result { - + instance: Option, + instantiable: Option, + default_instance: Option, +) -> Result { let right_syntax = "Should be $Instance: $Instantiable = $DefaultInstance"; match (instance, instantiable, default_instance) { - (Some(instance), Some(instantiable), default_instance_def) => { - let (equal_default_instance, default_instance) = if let Some(default_instance) = default_instance_def { - (quote!{= #default_instance}, Some(default_instance)) + (Some(instance), Some(instantiable), default_instance) => { + let (equal_default_instance, default_instance) = if let Some(def) = default_instance { + (quote!{= #def}, Some(def)) } else { - (quote!{}, None) + (quote!(), None) }; + Ok(InstanceOpts { comma_instance: quote!{, #instance}, equal_default_instance, @@ -952,8 +1178,35 @@ fn get_instance_opts( }) }, (None, None, None) => Ok(Default::default()), - (Some(instance), None, _) => Err(syn::Error::new(instance.span(), format!("Expect instantiable trait bound for instance: {}. {}", instance, right_syntax))), - (None, Some(instantiable), _) => Err(syn::Error::new(instantiable.span(), format!("Expect instance generic for bound instantiable: {}. {}", instantiable, right_syntax))), - (None, _, Some(default_instance)) => Err(syn::Error::new(default_instance.span(), format!("Expect instance generic for default instance: {}. {}", default_instance, right_syntax))), + (Some(instance), None, _) => Err( + Error::new( + instance.span(), + format!( + "Expect instantiable trait bound for instance: {}. {}", + instance, + right_syntax, + ) + ) + ), + (None, Some(instantiable), _) => Err( + Error::new( + instantiable.span(), + format!( + "Expect instance generic for bound instantiable: {}. {}", + instantiable, + right_syntax, + ) + ) + ), + (None, _, Some(default_instance)) => Err( + Error::new( + default_instance.span(), + format!( + "Expect instance generic for default instance: {}. {}", + default_instance, + right_syntax, + ) + ) + ), } } diff --git a/srml/support/procedural/tools/src/syn_ext.rs b/srml/support/procedural/tools/src/syn_ext.rs index 01177b9b3ed77ad3e7ba7f06bc56f0122947e15f..1033ebcce2de5b7da84e3d7ebc21bc0220ae4bfe 100644 --- a/srml/support/procedural/tools/src/syn_ext.rs +++ b/srml/support/procedural/tools/src/syn_ext.rs @@ -18,22 +18,17 @@ //! Extension to syn types, mainly for parsing // end::description[] -use syn::parse::{ - Parse, - ParseStream, - Result, -}; -use proc_macro2::TokenStream as T2; +use syn::{visit::{Visit, self}, parse::{Parse, ParseStream, Result}, Ident}; +use proc_macro2::{TokenStream, TokenTree}; use quote::{ToTokens, quote}; use std::iter::once; -use syn::Ident; use srml_support_procedural_tools_derive::{ToTokens, Parse}; /// stop parsing here getting remaining token as content /// Warn duplicate stream (part of) #[derive(Parse, ToTokens, Debug)] pub struct StopParse { - pub inner: T2, + pub inner: TokenStream, } // inner macro really dependant on syn naming convention, do not export @@ -55,8 +50,8 @@ macro_rules! groups_impl { } impl ToTokens for $name

{ - fn to_tokens(&self, tokens: &mut T2) { - let mut inner_stream = T2::new(); + fn to_tokens(&self, tokens: &mut TokenStream) { + let mut inner_stream = TokenStream::new(); self.content.to_tokens(&mut inner_stream); let token_tree: proc_macro2::TokenTree = proc_macro2::Group::new(proc_macro2::Delimiter::$deli, inner_stream).into(); @@ -107,7 +102,7 @@ impl Parse for PunctuatedInner { } impl ToTokens for PunctuatedInner { - fn to_tokens(&self, tokens: &mut T2) { + fn to_tokens(&self, tokens: &mut TokenStream) { self.inner.to_tokens(tokens) } } @@ -127,7 +122,7 @@ impl Parse for Meta { } impl ToTokens for Meta { - fn to_tokens(&self, tokens: &mut T2) { + fn to_tokens(&self, tokens: &mut TokenStream) { match self.inner { syn::Meta::Word(ref ident) => { let ident = ident.clone(); @@ -157,7 +152,7 @@ impl Parse for OuterAttributes { } impl ToTokens for OuterAttributes { - fn to_tokens(&self, tokens: &mut T2) { + fn to_tokens(&self, tokens: &mut TokenStream) { for att in self.inner.iter() { att.to_tokens(tokens); } @@ -182,121 +177,80 @@ impl Parse for Opt

{ } impl ToTokens for Opt

{ - fn to_tokens(&self, tokens: &mut T2) { + fn to_tokens(&self, tokens: &mut TokenStream) { if let Some(ref p) = self.inner { p.to_tokens(tokens); } } } -pub fn extract_type_option(typ: &syn::Type) -> Option { +pub fn extract_type_option(typ: &syn::Type) -> Option { if let syn::Type::Path(ref path) = typ { - path.path.segments.last().and_then(|v| { - if v.value().ident == "Option" { - if let syn::PathArguments::AngleBracketed(ref a) = v.value().arguments { - let args = &a.args; - Some(quote!{ #args }) - } else { - None - } - } else { - None + let v = path.path.segments.last()?; + if v.value().ident == "Option" { + if let syn::PathArguments::AngleBracketed(ref a) = v.value().arguments { + let args = &a.args; + return Some(quote!{ #args }) } - }) - } else { - None + } } -} -pub fn is_parametric_type_def(typ: &syn::Type, default: bool) -> bool { - match *typ { - syn::Type::Path(ref path) => { - path.path.segments.iter().any(|v| { - if let syn::PathArguments::AngleBracketed(..) = v.arguments { - true - } else { - false - } - }) - }, - syn::Type::Slice(ref inner) => is_parametric_type_def(&inner.elem, default), - syn::Type::Array(ref inner) => is_parametric_type_def(&inner.elem, default), - syn::Type::Ptr(ref inner) => is_parametric_type_def(&inner.elem, default), - syn::Type::Reference(ref inner) => is_parametric_type_def(&inner.elem, default), - syn::Type::BareFn(ref inner) => inner.variadic.is_some(), - syn::Type::Never(..) => false, - syn::Type::Tuple(ref inner) => - inner.elems.iter().any(|t| is_parametric_type_def(t, default)), - syn::Type::TraitObject(..) => true, - syn::Type::ImplTrait(..) => true, - syn::Type::Paren(ref inner) => is_parametric_type_def(&inner.elem, default), - syn::Type::Group(ref inner) => is_parametric_type_def(&inner.elem, default), - syn::Type::Infer(..) => true, - syn::Type::Macro(..) => default, - syn::Type::Verbatim(..) => default, - } + None } -/// check if type has any type parameter, defaults to true for some cases. -pub fn is_parametric_type(typ: &syn::Type) -> bool { - is_parametric_type_def(typ, true) +/// Auxialary structure to check if a given `Ident` is contained in an ast. +struct ContainsIdent<'a> { + ident: &'a Ident, + result: bool, } -fn has_parametric_type_def_in_path(path: &syn::Path, ident: &Ident, default: bool) -> bool { - path.segments.iter().any(|v| { - if ident == &v.ident { - return true; - } - if let syn::PathArguments::AngleBracketed(ref a) = v.arguments { - for arg in a.args.iter() { - if let syn::GenericArgument::Type(ref typ) = arg { - if has_parametric_type_def(typ, ident, default) { - return true; - } - } - // potentially missing matches here +impl<'ast> ContainsIdent<'ast> { + fn visit_tokenstream(&mut self, stream: TokenStream) { + stream.into_iter().for_each(|tt| + match tt { + TokenTree::Ident(id) => self.visit_ident(&id), + TokenTree::Group(ref group) => self.visit_tokenstream(group.stream()), + _ => {} } - false - } else { - false - } - }) + ) + } + fn visit_ident(&mut self, ident: &Ident) { + if ident == self.ident { + self.result = true; + } + } } -pub fn has_parametric_type_def(typ: &syn::Type, ident: &Ident, default: bool) -> bool { - match *typ { - syn::Type::Path(ref path) => has_parametric_type_def_in_path(&path.path, ident, default), - syn::Type::Slice(ref inner) => has_parametric_type_def(&inner.elem, ident, default), - syn::Type::Array(ref inner) => has_parametric_type_def(&inner.elem, ident, default), - syn::Type::Ptr(ref inner) => has_parametric_type_def(&inner.elem, ident, default), - syn::Type::Reference(ref inner) => has_parametric_type_def(&inner.elem, ident, default), - syn::Type::BareFn(ref inner) => inner.variadic.is_some(), - syn::Type::Never(..) => false, - syn::Type::Tuple(ref inner) => - inner.elems.iter().any(|t| has_parametric_type_def(t, ident, default)), - syn::Type::TraitObject(ref to) => { - to.bounds.iter().any(|bound| { - if let syn::TypeParamBound::Trait(ref t) = bound { - has_parametric_type_def_in_path(&t.path, ident, default) - } else { false } - }) - }, - syn::Type::ImplTrait(ref it) => { - it.bounds.iter().any(|bound| { - if let syn::TypeParamBound::Trait(ref t) = bound { - has_parametric_type_def_in_path(&t.path, ident, default) - } else { false } - }) - }, - syn::Type::Paren(ref inner) => has_parametric_type_def(&inner.elem, ident, default), - syn::Type::Group(ref inner) => has_parametric_type_def(&inner.elem, ident, default), - syn::Type::Infer(..) => default, - syn::Type::Macro(..) => default, - syn::Type::Verbatim(..) => default, + +impl<'ast> Visit<'ast> for ContainsIdent<'ast> { + fn visit_ident(&mut self, input: &'ast Ident) { + self.visit_ident(input); + } + + fn visit_macro(&mut self, input: &'ast syn::Macro) { + self.visit_tokenstream(input.tts.clone()); + visit::visit_macro(self, input); } } -/// check if type has a type parameter, defaults to true for some cases. -pub fn has_parametric_type(typ: &syn::Type, ident: &Ident) -> bool { - has_parametric_type_def(typ, ident, true) +/// Check if a `Type` contains the given `Ident`. +pub fn type_contains_ident(typ: &syn::Type, ident: &Ident) -> bool { + let mut visit = ContainsIdent { + result: false, + ident, + }; + + visit::visit_type(&mut visit, typ); + visit.result } + +/// Check if a `Expr` contains the given `Ident`. +pub fn expr_contains_ident(expr: &syn::Expr, ident: &Ident) -> bool { + let mut visit = ContainsIdent { + result: false, + ident, + }; + + visit::visit_expr(&mut visit, expr); + visit.result +} \ No newline at end of file diff --git a/srml/support/src/dispatch.rs b/srml/support/src/dispatch.rs index 37e40058252dd68c67a82af8946f1841cb8c6a69..f990cbd8d5a1e3d0a059d055a7fb2446b98688b6 100644 --- a/srml/support/src/dispatch.rs +++ b/srml/support/src/dispatch.rs @@ -17,12 +17,14 @@ //! Dispatch system. Contains a macro for defining runtime modules and //! generating values representing lazy module function calls. -pub use crate::rstd::prelude::{Vec, Clone, Eq, PartialEq}; +pub use crate::rstd::{result, prelude::{Vec, Clone, Eq, PartialEq}, marker}; #[cfg(feature = "std")] pub use std::fmt; -pub use crate::rstd::result; pub use crate::codec::{Codec, Decode, Encode, Input, Output, HasCompact, EncodeAsRef}; -pub use srml_metadata::{FunctionMetadata, DecodeDifferent, DecodeDifferentArray, FunctionArgumentMetadata}; +pub use srml_metadata::{ + FunctionMetadata, DecodeDifferent, DecodeDifferentArray, FunctionArgumentMetadata, + ModuleConstantMetadata, DefaultByte, DefaultByteGetter, +}; pub use sr_primitives::weights::{TransactionWeight, Weighable, Weight}; /// A type that cannot be instantiated. @@ -45,13 +47,13 @@ pub trait Dispatchable { /// Serializable version of Dispatchable. /// This value can be used as a "function" in an extrinsic. -pub trait Callable { +pub trait Callable { type Call: Dispatchable + Codec + Clone + PartialEq + Eq; } // dirty hack to work around serde_derive issue // https://github.com/rust-lang/rust/issues/51331 -pub type CallableCallFor = ::Call; +pub type CallableCallFor = >::Call; #[cfg(feature = "std")] pub trait Parameter: Codec + Clone + Eq + fmt::Debug {} @@ -102,6 +104,8 @@ impl Parameter for T where T: Codec + Clone + Eq {} /// * `origin`: Alias of `T::Origin`, declared by the [`impl_outer_origin!`](./macro.impl_outer_origin.html) macro. /// * `Result`: The expected return type from module functions. /// +/// The first parameter of dispatchable functions must always be `origin`. +/// /// ### Shorthand Example /// /// The macro automatically expands a shorthand function declaration to return the `Result` type. @@ -130,8 +134,7 @@ impl Parameter for T where T: Codec + Clone + Eq {} /// /// ### Privileged Function Example /// -/// If the `origin` param is omitted, the macro adds it as the first parameter and adds `ensure_root(origin)` -/// as the first line of the function. These functions are the same: +/// A privileged function checks that the origin of the call is `ROOT`. /// /// ``` /// # #[macro_use] @@ -140,14 +143,8 @@ impl Parameter for T where T: Codec + Clone + Eq {} /// # use srml_system::{self as system, Trait, ensure_signed, ensure_root}; /// decl_module! { /// pub struct Module for enum Call where origin: T::Origin { -/// -/// fn my_privileged_function() -> Result { -/// // Your implementation -/// Ok(()) -/// } -/// -/// fn my_function(origin) -> Result { -/// ensure_root(origin); +/// fn my_privileged_function(origin) -> Result { +/// ensure_root(origin)?; /// // Your implementation /// Ok(()) /// } @@ -181,6 +178,28 @@ impl Parameter for T where T: Codec + Clone + Eq {} /// # fn main() {} /// ``` /// +/// ## Where clause +/// +/// Besides the default `origin: T::Origin`, you can also pass other bounds to the module declaration. +/// This where bound will be replicated to all types generated by this macro. The chaining of multiple +/// trait bounds with `+` is not supported. If multiple bounds for one type are required, it needs to +/// be split up into multiple bounds. +/// +/// ``` +/// # #[macro_use] +/// # extern crate srml_support; +/// # use srml_support::dispatch::Result; +/// # use srml_system::{self as system, ensure_signed}; +/// pub trait Trait: system::Trait where Self::AccountId: From {} +/// +/// decl_module! { +/// pub struct Module for enum Call where origin: T::Origin, T::AccountId: From { +/// // Your implementation +/// } +/// } +/// # fn main() {} +/// ``` +/// /// ## Reserved Functions /// /// The following are reserved function signatures: @@ -204,15 +223,22 @@ macro_rules! decl_module { // Entry point #1. ( $(#[$attr:meta])* - pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> - for enum $call_type:ident where origin: $origin_type:ty { - $($t:tt)* + pub struct $mod_type:ident< + $trait_instance:ident: $trait_name:ident + $( , I: $instantiable:path $( = $module_default_instance:path )? )? + > + for enum $call_type:ident where origin: $origin_type:ty $(, $where_ty:ty: $where_bound:path )* { + $( $t:tt )* } ) => { $crate::decl_module!(@normalize $(#[$attr])* - pub struct $mod_type<$trait_instance: $trait_name$(, I: $instantiable $(= $module_default_instance)?)?> + pub struct $mod_type< + $trait_instance: $trait_name $(, I: $instantiable $(= $module_default_instance)?)? + > for enum $call_type where origin: $origin_type, system = system + { $( $where_ty: $where_bound ),* } + {} {} {} {} @@ -224,15 +250,26 @@ macro_rules! decl_module { // Entry point #2. ( $(#[$attr:meta])* - pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> - for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident { + pub struct $mod_type:ident< + $trait_instance:ident: $trait_name:ident + $( , I: $instantiable:path $( = $module_default_instance:path )? )? + > + for enum $call_type:ident where + origin: $origin_type:ty, + system = $system:ident + $(, $where_ty:ty: $where_bound:path )* + { $($t:tt)* } ) => { $crate::decl_module!(@normalize $(#[$attr])* - pub struct $mod_type<$trait_instance: $trait_name$(, I: $instantiable $(= $module_default_instance)?)?> + pub struct $mod_type< + $trait_instance: $trait_name $(, I: $instantiable $( = $module_default_instance )? )? + > for enum $call_type where origin: $origin_type, system = $system + { $( $where_ty: $where_bound ),* } + {} {} {} {} @@ -247,11 +284,13 @@ macro_rules! decl_module { $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident + { $( $other_where_bounds:tt )* } {} { $( $on_initialize:tt )* } { $( $on_finalize:tt )* } { $( $offchain:tt )* } - [ $($t:tt)* ] + { $( $constants:tt )* } + [ $( $dispatchables:tt )* ] $(#[doc = $doc_attr:tt])* $vis:vis fn deposit_event $(<$dpeg:ident $(, $dpeg_instance:ident)?>)* () = default; $($rest:tt)* @@ -260,11 +299,13 @@ macro_rules! decl_module { $(#[$attr])* pub struct $mod_type<$trait_instance: $trait_name$(, I: $instantiable $(= $module_default_instance)?)?> for enum $call_type where origin: $origin_type, system = $system + { $( $other_where_bounds )* } { $vis fn deposit_event $(<$dpeg $(, $dpeg_instance)?>)* () = default; } { $( $on_initialize )* } { $( $on_finalize )* } { $( $offchain )* } - [ $($t)* ] + { $( $constants )* } + [ $( $dispatchables )* ] $($rest)* ); }; @@ -272,11 +313,13 @@ macro_rules! decl_module { $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident + { $( $other_where_bounds:tt )* } {} { $( $on_initialize:tt )* } { $( $on_finalize:tt )* } { $( $offchain:tt )* } - [ $($t:tt)* ] + { $( $constants:tt )* } + [ $( $dispatchables:tt )* ] $(#[doc = $doc_attr:tt])* $vis:vis fn deposit_event $(<$dpeg:ident $(, $dpeg_instance:ident)?>)* ( $($param_name:ident : $param:ty),* @@ -287,11 +330,13 @@ macro_rules! decl_module { $(#[$attr])* pub struct $mod_type<$trait_instance: $trait_name$(, I: $instantiable $(= $module_default_instance)?)?> for enum $call_type where origin: $origin_type, system = $system + { $( $other_where_bounds )* } { $vis fn deposit_event $(<$dpeg $(, $dpeg_instance)?>)* ($( $param_name: $param ),* ) { $( $impl )* } } { $( $on_initialize )* } { $( $on_finalize )* } { $( $offchain )* } - [ $($t)* ] + { $( $constants )* } + [ $( $dispatchables )* ] $($rest)* ); }; @@ -299,11 +344,13 @@ macro_rules! decl_module { $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident + { $( $other_where_bounds:tt )* } { $( $deposit_event:tt )* } { $( $on_initialize:tt )* } {} { $( $offchain:tt )* } - [ $($t:tt)* ] + { $( $constants:tt )* } + [ $( $dispatchables:tt )* ] $(#[doc = $doc_attr:tt])* fn on_finalize($($param_name:ident : $param:ty),* ) { $( $impl:tt )* } $($rest:tt)* @@ -312,11 +359,13 @@ macro_rules! decl_module { $(#[$attr])* pub struct $mod_type<$trait_instance: $trait_name$(, I: $instantiable $(= $module_default_instance)?)?> for enum $call_type where origin: $origin_type, system = $system + { $( $other_where_bounds )* } { $( $deposit_event )* } { $( $on_initialize )* } { fn on_finalize( $( $param_name : $param ),* ) { $( $impl )* } } { $( $offchain )* } - [ $($t)* ] + { $( $constants )* } + [ $( $dispatchables )* ] $($rest)* ); }; @@ -324,11 +373,13 @@ macro_rules! decl_module { $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident + { $( $other_where_bounds:tt )* } { $( $deposit_event:tt )* } { $( $on_initialize:tt )* } {} { $( $offchain:tt )* } - [ $($t:tt)* ] + { $( $constants:tt )* } + [ $( $dispatchables:tt )* ] $(#[doc = $doc_attr:tt])* fn on_finalise($($param_name:ident : $param:ty),* ) { $( $impl:tt )* } $($rest:tt)* @@ -341,11 +392,13 @@ macro_rules! decl_module { $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident + { $( $other_where_bounds:tt )* } { $( $deposit_event:tt )* } {} { $( $on_finalize:tt )* } { $( $offchain:tt )* } - [ $($t:tt)* ] + { $( $constants:tt )* } + [ $( $dispatchables:tt )* ] $(#[doc = $doc_attr:tt])* fn on_initialize($($param_name:ident : $param:ty),* ) { $( $impl:tt )* } $($rest:tt)* @@ -354,11 +407,13 @@ macro_rules! decl_module { $(#[$attr])* pub struct $mod_type<$trait_instance: $trait_name$(, I: $instantiable $(= $module_default_instance)?)?> for enum $call_type where origin: $origin_type, system = $system + { $( $other_where_bounds )* } { $( $deposit_event )* } { fn on_initialize( $( $param_name : $param ),* ) { $( $impl )* } } { $( $on_finalize )* } { $( $offchain )* } - [ $($t)* ] + { $( $constants )* } + [ $( $dispatchables )* ] $($rest)* ); }; @@ -366,11 +421,13 @@ macro_rules! decl_module { $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident + { $( $other_where_bounds:tt )* } { $( $deposit_event:tt )* } {} { $( $on_finalize:tt )* } { $( $offchain:tt )* } - [ $($t:tt)* ] + { $( $constants:tt )* } + [ $( $dispatchables:tt )* ] $(#[doc = $doc_attr:tt])* fn on_initialise($($param_name:ident : $param:ty),* ) { $( $impl:tt )* } $($rest:tt)* @@ -381,42 +438,95 @@ macro_rules! decl_module { }; (@normalize $(#[$attr:meta])* - pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident> + pub struct $mod_type:ident< + $trait_instance:ident: $trait_name:ident + $(, I: $instantiable:path $(= $module_default_instance:path)?)? + > for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident + { $( $other_where_bounds:tt )* } { $( $deposit_event:tt )* } { $( $on_initialize:tt )* } { $( $on_finalize:tt )* } { } - [ $($t:tt)* ] + { $( $constants:tt )* } + [ $( $dispatchables:tt )* ] $(#[doc = $doc_attr:tt])* fn offchain_worker($($param_name:ident : $param:ty),* ) { $( $impl:tt )* } $($rest:tt)* ) => { $crate::decl_module!(@normalize $(#[$attr])* - pub struct $mod_type<$trait_instance: $trait_name> + pub struct $mod_type< + $trait_instance: $trait_name$(, I: $instantiable $(= $module_default_instance)?)? + > for enum $call_type where origin: $origin_type, system = $system + { $( $other_where_bounds )* } { $( $deposit_event )* } { $( $on_initialize )* } { $( $on_finalize )* } { fn offchain_worker( $( $param_name : $param ),* ) { $( $impl )* } } - [ $($t)* ] + { $( $constants )* } + [ $( $dispatchables )* ] + $($rest)* + ); + }; + + // This puts a constant in the parsed constants list. + (@normalize + $(#[$attr:meta])* + pub struct $mod_type:ident< + $trait_instance:ident: $trait_name:ident + $(, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)? + > + for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident + { $( $other_where_bounds:tt )* } + { $( $deposit_event:tt )* } + { $( $on_initialize:tt )* } + { $( $on_finalize:tt )* } + { $( $offchain:tt )* } + { $( $constants:tt )* } + [ $( $dispatchables:tt )* ] + $( #[doc = $doc_attr:tt] )* + const $name:ident: $ty:ty = $value:expr; + $( $rest:tt )* + ) => { + $crate::decl_module!(@normalize + $(#[$attr])* + pub struct $mod_type< + $trait_instance: $trait_name + $( , $instance: $instantiable $(= $module_default_instance)? )? + > + for enum $call_type where origin: $origin_type, system = $system + { $( $other_where_bounds )* } + { $( $deposit_event )* } + { $( $on_initialize )* } + { $( $on_finalize )* } + { $( $offchain )* } + { + $( $constants )* + $( #[doc = $doc_attr ] )* + $name: $ty = $value; + } + [ $( $dispatchables )* ] $($rest)* ); }; + // This puts the function statement into the [], decreasing `$rest` and moving toward finishing the parse. (@normalize $(#[$attr:meta])* pub struct $mod_type:ident< - $trait_instance:ident: - $trait_name:ident$(, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)? + $trait_instance:ident: $trait_name:ident + $(, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)? > for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident + { $( $other_where_bounds:tt )* } { $( $deposit_event:tt )* } { $( $on_initialize:tt )* } { $( $on_finalize:tt )* } { $( $offchain:tt )* } - [ $($t:tt)* ] + { $( $constants:tt )* } + [ $( $dispatchables:tt )* ] $(#[doc = $doc_attr:tt])* #[weight = $weight:expr] $fn_vis:vis fn $fn_name:ident( @@ -430,12 +540,14 @@ macro_rules! decl_module { $trait_instance: $trait_name$(, $instance: $instantiable $(= $module_default_instance)?)? > for enum $call_type where origin: $origin_type, system = $system + { $( $other_where_bounds )* } { $( $deposit_event )* } { $( $on_initialize )* } { $( $on_finalize )* } { $( $offchain )* } + { $( $constants )* } [ - $($t)* + $( $dispatchables )* $(#[doc = $doc_attr])* #[weight = $weight] $fn_vis fn $fn_name( @@ -454,11 +566,13 @@ macro_rules! decl_module { $trait_name:ident$(, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)? > for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident + { $( $other_where_bounds:tt )* } { $( $deposit_event:tt )* } { $( $on_initialize:tt )* } { $( $on_finalize:tt )* } { $( $offchain:tt )* } - [ $($t:tt)* ] + { $( $constants:tt )* } + [ $( $dispatchables:tt )* ] $(#[doc = $doc_attr:tt])* $fn_vis:vis fn $fn_name:ident( $from:ident $(, $(#[$codec_attr:ident])* $param_name:ident : $param:ty)* @@ -471,11 +585,13 @@ macro_rules! decl_module { $trait_instance: $trait_name$(, $instance: $instantiable $(= $module_default_instance)?)? > for enum $call_type where origin: $origin_type, system = $system + { $( $other_where_bounds )* } { $( $deposit_event )* } { $( $on_initialize )* } { $( $on_finalize )* } { $( $offchain )* } - [ $($t)* ] + { $( $constants )* } + [ $( $dispatchables )* ] $(#[doc = $doc_attr])* #[weight = $crate::dispatch::TransactionWeight::default()] $fn_vis fn $fn_name( @@ -489,11 +605,13 @@ macro_rules! decl_module { $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident + { $( $other_where_bounds:tt )* } { $( $deposit_event:tt )* } { $( $on_initialize:tt )* } { $( $on_finalize:tt )* } { $( $offchain:tt )* } - [ $($t:tt)* ] + { $( $constants:tt )* } + [ $( $dispatchables:tt )* ] $(#[doc = $doc_attr:tt])* $(#[weight = $weight:expr])? $fn_vis:vis fn $fn_name:ident( @@ -503,20 +621,21 @@ macro_rules! decl_module { ) => { compile_error!( "First parameter of dispatch should be marked `origin` only, with no type specified \ - (a bit like `self`). (For root-matching dispatches, ensure the first parameter does \ - not use the `T::Origin` type.)" - ) + (a bit like `self`)." + ); }; // Ignore any ident which is `origin` but has a type, regardless of the type token itself. (@normalize $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident + { $( $other_where_bounds:tt )* } { $( $deposit_event:tt )* } { $( $on_initialize:tt )* } { $( $on_finalize:tt )* } { $( $offchain:tt )* } - [ $($t:tt)* ] + { $( $constants:tt )* } + [ $( $dispatchables:tt )* ] $(#[doc = $doc_attr:tt])* $(#[weight = $weight:expr])? $fn_vis:vis fn $fn_name:ident( @@ -526,20 +645,21 @@ macro_rules! decl_module { ) => { compile_error!( "First parameter of dispatch should be marked `origin` only, with no type specified \ - (a bit like `self`). (For root-matching dispatches, ensure the first parameter does \ - not use the `T::Origin` type.)" - ) + (a bit like `self`)." + ); }; - // Add root if no origin is defined. + // Ignore any function missing `origin` as the first parameter. (@normalize $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident + { $( $other_where_bounds:tt )* } { $( $deposit_event:tt )* } { $( $on_initialize:tt )* } { $( $on_finalize:tt )* } { $( $offchain:tt )* } - [ $($t:tt)* ] + { $( $constants:tt )* } + [ $( $dispatchables:tt )* ] $(#[doc = $doc_attr:tt])* $(#[weight = $weight:expr])? $fn_vis:vis fn $fn_name:ident( @@ -547,23 +667,10 @@ macro_rules! decl_module { ) $( -> $result:ty )* { $( $impl:tt )* } $($rest:tt)* ) => { - $crate::decl_module!(@normalize - $(#[$attr])* - pub struct $mod_type<$trait_instance: $trait_name$(, $instance: $instantiable $(= $module_default_instance)?)?> - for enum $call_type where origin: $origin_type, system = $system - { $( $deposit_event )* } - { $( $on_initialize )* } - { $( $on_finalize )* } - { $( $offchain )* } - [ $($t)* ] - - $(#[doc = $doc_attr])* - $(#[weight = $weight])? - $fn_vis fn $fn_name( - root $( , $(#[$codec_attr])* $param_name : $param )* - ) $( -> $result )* { $( $impl )* } - - $($rest)* + compile_error!( + "Implicit conversion to privileged function has been removed. \ + First parameter of dispatch should be marked `origin`. \ + For root-matching dispatch, also add `ensure_root(origin)?`." ); }; // Last normalize step. Triggers `@imp` expansion which is the real expansion. @@ -571,37 +678,32 @@ macro_rules! decl_module { $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident + { $( $other_where_bounds:tt )* } { $( $deposit_event:tt )* } { $( $on_initialize:tt )* } { $( $on_finalize:tt )* } { $( $offchain:tt )* } - [ $($t:tt)* ] + { $( $constants:tt )* } + [ $( $dispatchables:tt )* ] ) => { $crate::decl_module!(@imp $(#[$attr])* pub struct $mod_type<$trait_instance: $trait_name$(, I: $instantiable $(= $module_default_instance)?)?> for enum $call_type where origin: $origin_type, system = $system { - $($t)* + $( $dispatchables )* } + { $( $other_where_bounds )* } { $( $deposit_event )* } { $( $on_initialize )* } { $( $on_finalize )* } { $( $offchain )* } + { $( $constants )* } ); }; // Implementation of Call enum's .dispatch() method. // TODO: this probably should be a different macro? - (@call - root - $mod_type:ident<$trait_instance:ident $(, $instance:ident)?> $fn_name:ident $origin:ident $system:ident [ $( $param_name:ident),* ] - ) => { - { - $system::ensure_root($origin)?; - <$mod_type<$trait_instance $(, $instance)?>>::$fn_name( $( $param_name ),* ) - } - }; (@call $ingore:ident $mod_type:ident<$trait_instance:ident $(, $instance:ident)?> $fn_name:ident $origin:ident $system:ident [ $( $param_name:ident),* ] @@ -613,14 +715,18 @@ macro_rules! decl_module { (@impl_deposit_event $module:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path)?>; $system:ident; + { $( $other_where_bounds:tt )* } ) => {}; (@impl_deposit_event $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; $system:ident; + { $( $other_where_bounds:tt )* } $vis:vis fn deposit_event$(<$event_trait_instance:ident $(, $event_instance:ident)?>)?() = default; ) => { - impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $module<$trait_instance $(, $instance)?> { + impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $module<$trait_instance $(, $instance)?> + where $( $other_where_bounds )* + { $vis fn deposit_event(event: Event$(<$event_trait_instance $(, $event_instance)?>)?) { <$system::Module<$trait_instance>>::deposit_event( <$trait_instance as $trait_name$(<$instance>)?>::Event::from(event).into() @@ -632,9 +738,12 @@ macro_rules! decl_module { (@impl_deposit_event $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; $system:ident; + { $( $other_where_bounds:tt )* } $vis:vis fn deposit_event($param:ident : $param_ty:ty) { $( $impl:tt )* } ) => { - impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $module<$trait_instance $(, $instance)?> { + impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $module<$trait_instance $(, $instance)?> + where $( $other_where_bounds )* + { $vis fn deposit_event($param: $param_ty) { $( $impl )* } @@ -643,11 +752,12 @@ macro_rules! decl_module { (@impl_on_initialize $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; + { $( $other_where_bounds:tt )* } fn on_initialize() { $( $impl:tt )* } ) => { impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OnInitialize<$trait_instance::BlockNumber> - for $module<$trait_instance$(, $instance)?> + for $module<$trait_instance$(, $instance)?> where $( $other_where_bounds )* { fn on_initialize(_block_number_not_used: $trait_instance::BlockNumber) { $( $impl )* } } @@ -655,11 +765,12 @@ macro_rules! decl_module { (@impl_on_initialize $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; + { $( $other_where_bounds:tt )* } fn on_initialize($param:ident : $param_ty:ty) { $( $impl:tt )* } ) => { impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OnInitialize<$trait_instance::BlockNumber> - for $module<$trait_instance$(, $instance)?> + for $module<$trait_instance$(, $instance)?> where $( $other_where_bounds )* { fn on_initialize($param: $param_ty) { $( $impl )* } } @@ -667,20 +778,22 @@ macro_rules! decl_module { (@impl_on_initialize $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; + { $( $other_where_bounds:tt )* } ) => { impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OnInitialize<$trait_instance::BlockNumber> - for $module<$trait_instance$(, $instance)?> + for $module<$trait_instance$(, $instance)?> where $( $other_where_bounds )* {} }; (@impl_on_finalize $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; + { $( $other_where_bounds:tt )* } fn on_finalize() { $( $impl:tt )* } ) => { impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OnFinalize<$trait_instance::BlockNumber> - for $module<$trait_instance$(, $instance)?> + for $module<$trait_instance$(, $instance)?> where $( $other_where_bounds )* { fn on_finalize(_block_number_not_used: $trait_instance::BlockNumber) { $( $impl )* } } @@ -688,11 +801,12 @@ macro_rules! decl_module { (@impl_on_finalize $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; + { $( $other_where_bounds:tt )* } fn on_finalize($param:ident : $param_ty:ty) { $( $impl:tt )* } ) => { impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OnFinalize<$trait_instance::BlockNumber> - for $module<$trait_instance$(, $instance)?> + for $module<$trait_instance$(, $instance)?> where $( $other_where_bounds )* { fn on_finalize($param: $param_ty) { $( $impl )* } } @@ -700,21 +814,23 @@ macro_rules! decl_module { (@impl_on_finalize $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; + { $( $other_where_bounds:tt )* } ) => { impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OnFinalize<$trait_instance::BlockNumber> - for $module<$trait_instance$(, $instance)?> + for $module<$trait_instance$(, $instance)?> where $( $other_where_bounds )* { } }; (@impl_offchain $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; + { $( $other_where_bounds:tt )* } fn offchain_worker() { $( $impl:tt )* } ) => { impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OffchainWorker<$trait_instance::BlockNumber> - for $module<$trait_instance$(, $instance)?> + for $module<$trait_instance$(, $instance)?> where $( $other_where_bounds )* { fn generate_extrinsics(_block_number_not_used: $trait_instance::BlockNumber) { $( $impl )* } } @@ -722,11 +838,12 @@ macro_rules! decl_module { (@impl_offchain $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; + { $( $other_where_bounds:tt )* } fn offchain_worker($param:ident : $param_ty:ty) { $( $impl:tt )* } ) => { impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OffchainWorker<$trait_instance::BlockNumber> - for $module<$trait_instance$(, $instance)?> + for $module<$trait_instance$(, $instance)?> where $( $other_where_bounds )* { fn generate_extrinsics($param: $param_ty) { $( $impl )* } } @@ -734,45 +851,14 @@ macro_rules! decl_module { (@impl_offchain $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; + { $( $other_where_bounds:tt )* } ) => { impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OffchainWorker<$trait_instance::BlockNumber> - for $module<$trait_instance$(, $instance)?> + for $module<$trait_instance$(, $instance)?> where $( $other_where_bounds )* {} }; - // Expansion for root dispatch functions with no specified result type. - (@impl_function - $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; - $origin_ty:ty; - root; - $(#[doc = $doc_attr:tt])* - $vis:vis fn $name:ident ( root $(, $param:ident : $param_ty:ty )* ) { $( $impl:tt )* } - ) => { - $(#[doc = $doc_attr])* - #[allow(unreachable_code)] - $vis fn $name($( $param: $param_ty ),* ) -> $crate::dispatch::Result { - { $( $impl )* } - Ok(()) - } - }; - - // Expansion for root dispatch functions with explicit return types. - (@impl_function - $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; - $origin_ty:ty; - root; - $(#[doc = $doc_attr:tt])* - $vis:vis fn $name:ident ( - root $(, $param:ident : $param_ty:ty )* - ) -> $result:ty { $( $impl:tt )* } - ) => { - $(#[doc = $doc_attr])* - $vis fn $name($( $param: $param_ty ),* ) -> $result { - $( $impl )* - } - }; - // Expansion for _origin_ dispatch functions with no return type. (@impl_function $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; @@ -784,10 +870,12 @@ macro_rules! decl_module { ) { $( $impl:tt )* } ) => { $(#[doc = $doc_attr])* + #[allow(unreachable_code)] $vis fn $name( $origin: $origin_ty $(, $param: $param_ty )* ) -> $crate::dispatch::Result { { $( $impl )* } + // May be unreachable. Ok(()) } }; @@ -813,6 +901,7 @@ macro_rules! decl_module { $( #[$attr:meta] )* $call_type:ident; <$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?> + { $( $other_where_bounds:tt )* } { $( $generated_variants:tt )* } { $( $current_params:tt )* } variant $fn_name:ident; @@ -826,6 +915,7 @@ macro_rules! decl_module { $( #[$attr] )* $call_type; <$trait_instance: $trait_name $(, $instance: $instantiable $(= $module_default_instance)? )?> + { $( $other_where_bounds )* } { $( $generated_variants )* } { $( $current_params )* @@ -843,6 +933,7 @@ macro_rules! decl_module { $( #[$attr:meta] )* $call_type:ident; <$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?> + { $( $other_where_bounds:tt )* } { $( $generated_variants:tt )* } { $( $current_params:tt )* } variant $fn_name:ident; @@ -855,6 +946,7 @@ macro_rules! decl_module { $( #[$attr] )* $call_type; <$trait_instance: $trait_name $(, $instance: $instantiable $(= $module_default_instance)? )?> + { $( $other_where_bounds )* } { $( $generated_variants )* } { $( $current_params )* @@ -870,6 +962,7 @@ macro_rules! decl_module { $( #[$attr:meta] )* $call_type:ident; <$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?> + { $( $other_where_bounds:tt )* } { $( $generated_variants:tt )* } { $( $current_params:tt )* } variant $fn_name:ident; @@ -884,6 +977,7 @@ macro_rules! decl_module { $( #[$attr] )* $call_type; <$trait_instance: $trait_name $(, $instance: $instantiable $(= $module_default_instance)? )?> + { $( $other_where_bounds )* } { $( $generated_variants )* #[allow(non_camel_case_types)] @@ -904,12 +998,15 @@ macro_rules! decl_module { $( #[$attr:meta] )* $call_type:ident; <$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?> + { $( $other_where_bounds:tt )* } { $( $generated_variants:tt )* } {} ) => { #[derive($crate::codec::Encode, $crate::codec::Decode)] $( #[$attr] )* - pub enum $call_type<$trait_instance: $trait_name$(, $instance: $instantiable $( = $module_default_instance)?)?> { + pub enum $call_type<$trait_instance: $trait_name$(, $instance: $instantiable $( = $module_default_instance)?)?> + where $( $other_where_bounds )* + { #[doc(hidden)] #[codec(skip)] __PhantomItem($crate::rstd::marker::PhantomData<($trait_instance $(, $instance)?)>, $crate::dispatch::Never), @@ -935,14 +1032,14 @@ macro_rules! decl_module { { $($fn_instance:ident: $fn_instantiable:path)? } )* } + { $( $other_where_bounds:tt )* } { $( $deposit_event:tt )* } { $( $on_initialize:tt )* } { $( $on_finalize:tt )* } { $( $offchain:tt )* } + { $( $constants:tt )* } ) => { - $crate::__check_reserved_fn_name! { - $($fn_name)* - } + $crate::__check_reserved_fn_name! { $( $fn_name )* } // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, Copy, PartialEq, Eq)] @@ -950,36 +1047,43 @@ macro_rules! decl_module { pub struct $mod_type< $trait_instance: $trait_name $(, $instance: $instantiable $( = $module_default_instance)?)? - >($crate::rstd::marker::PhantomData<($trait_instance $(, $instance)?)>); + >($crate::rstd::marker::PhantomData<($trait_instance $(, $instance)?)>) where + $( $other_where_bounds )*; $crate::decl_module! { @impl_on_initialize $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?>; + { $( $other_where_bounds )* } $( $on_initialize )* } $crate::decl_module! { @impl_on_finalize $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?>; + { $( $other_where_bounds )* } $( $on_finalize )* } $crate::decl_module! { @impl_offchain $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?>; + { $( $other_where_bounds )* } $( $offchain )* } $crate::decl_module! { @impl_deposit_event $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?>; $system; + { $( $other_where_bounds )* } $( $deposit_event )* } /// Can also be called using [`Call`]. /// /// [`Call`]: enum.Call.html - impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $mod_type<$trait_instance $(, $instance)?> { + impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $mod_type<$trait_instance $(, $instance)?> + where $( $other_where_bounds )* + { $( $crate::decl_module! { @impl_function @@ -999,6 +1103,7 @@ macro_rules! decl_module { $( #[$attr] )* $call_type; <$trait_instance: $trait_name $(, $instance: $instantiable $(= $module_default_instance)? )?> + { $( $other_where_bounds )* } {} {} $( @@ -1013,7 +1118,7 @@ macro_rules! decl_module { // Implement weight calculation function for Call impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Weighable - for $call_type<$trait_instance $(, $instance)?> + for $call_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )* { fn weight(&self, _len: usize) -> $crate::dispatch::Weight { match self { @@ -1026,7 +1131,7 @@ macro_rules! decl_module { // manual implementation of clone/eq/partialeq because using derive erroneously requires // clone/eq/partialeq from T. impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Clone - for $call_type<$trait_instance $(, $instance)?> + for $call_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )* { fn clone(&self) -> Self { match *self { @@ -1039,7 +1144,7 @@ macro_rules! decl_module { } } impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::PartialEq - for $call_type<$trait_instance $(, $instance)?> + for $call_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )* { fn eq(&self, _other: &Self) -> bool { match *self { @@ -1061,14 +1166,17 @@ macro_rules! decl_module { } } impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Eq - for $call_type<$trait_instance $(, $instance)?> + for $call_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )* {} #[cfg(feature = "std")] impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::fmt::Debug - for $call_type<$trait_instance $(, $instance)?> + for $call_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )* { - fn fmt(&self, _f: &mut $crate::dispatch::fmt::Formatter) -> $crate::dispatch::result::Result<(), $crate::dispatch::fmt::Error> { + fn fmt( + &self, + _f: &mut $crate::dispatch::fmt::Formatter, + ) -> $crate::dispatch::result::Result<(), $crate::dispatch::fmt::Error> { match *self { $( $call_type::$fn_name( $( ref $param_name ),* ) => @@ -1083,7 +1191,7 @@ macro_rules! decl_module { } impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Dispatchable - for $call_type<$trait_instance $(, $instance)?> + for $call_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )* { type Trait = $trait_instance; type Origin = $origin_type; @@ -1102,27 +1210,44 @@ macro_rules! decl_module { } } } - impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Callable - for $mod_type<$trait_instance $(, $instance)?> + impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Callable<$trait_instance> + for $mod_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )* { type Call = $call_type<$trait_instance $(, $instance)?>; } - impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $mod_type<$trait_instance $(, $instance)?> { + impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $mod_type<$trait_instance $(, $instance)?> + where $( $other_where_bounds )* + { #[doc(hidden)] - pub fn dispatch>(d: D, origin: D::Origin) -> $crate::dispatch::Result { + pub fn dispatch>( + d: D, + origin: D::Origin, + ) -> $crate::dispatch::Result { d.dispatch(origin) } } $crate::__dispatch_impl_metadata! { - $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?> $call_type $origin_type - {$( $(#[doc = $doc_attr])* fn $fn_name($from $(, $(#[$codec_attr])* $param_name : $param )*); )*} + $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?> + { $( $other_where_bounds )* } + $call_type $origin_type + { + $( + $(#[doc = $doc_attr])* + fn $fn_name($from $(, $(#[$codec_attr])* $param_name : $param )*); + )* + } + } + $crate::__impl_module_constants_metadata ! { + $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?> + { $( $other_where_bounds )* } + $( $constants )* } } } -pub trait IsSubType { - fn is_aux_sub_type(&self) -> Option<&::Call>; +pub trait IsSubType, R> { + fn is_aux_sub_type(&self) -> Option<&CallableCallFor>; } /// Implement a meta-dispatch module to dispatch to other dispatchers. @@ -1141,7 +1266,7 @@ macro_rules! impl_outer_dispatch { #[cfg_attr(feature = "std", derive(Debug))] pub enum $call_type { $( - $camelcase ( $crate::dispatch::CallableCallFor<$camelcase> ) + $camelcase ( $crate::dispatch::CallableCallFor<$camelcase, $runtime> ) ,)* } impl $crate::dispatch::Weighable for $call_type { @@ -1161,15 +1286,22 @@ macro_rules! impl_outer_dispatch { } } $( - impl $crate::dispatch::IsSubType<$camelcase> for $call_type { - fn is_aux_sub_type(&self) -> Option<&<$camelcase as $crate::dispatch::Callable>::Call> { - if let $call_type::$camelcase ( ref r ) = *self { - Some(r) - } else { - None + impl $crate::dispatch::IsSubType<$camelcase, $runtime> for $call_type { + #[allow(unreachable_patterns)] + fn is_aux_sub_type(&self) -> Option<&$crate::dispatch::CallableCallFor<$camelcase, $runtime>> { + match *self { + $call_type::$camelcase(ref r) => Some(r), + // May be unreachable + _ => None, } } } + + impl From<$crate::dispatch::CallableCallFor<$camelcase, $runtime>> for $call_type { + fn from(call: $crate::dispatch::CallableCallFor<$camelcase, $runtime>) -> Self { + $call_type::$camelcase(call) + } + } )* } } @@ -1180,9 +1312,12 @@ macro_rules! impl_outer_dispatch { macro_rules! __dispatch_impl_metadata { ( $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?> + { $( $other_where_bounds:tt )* } $($rest:tt)* ) => { - impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $mod_type<$trait_instance $(, $instance)?> { + impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $mod_type<$trait_instance $(, $instance)?> + where $( $other_where_bounds )* + { #[doc(hidden)] pub fn call_functions() -> &'static [$crate::dispatch::FunctionMetadata] { $crate::__call_to_functions!($($rest)*) @@ -1191,20 +1326,136 @@ macro_rules! __dispatch_impl_metadata { } } +/// Implement metadata for module constants. +#[macro_export] +#[doc(hidden)] +macro_rules! __impl_module_constants_metadata { + // Without instance + ( + $mod_type:ident<$trait_instance:ident: $trait_name:ident> + { $( $other_where_bounds:tt )* } + $( + $( #[doc = $doc_attr:tt] )* + $name:ident: $type:ty = $value:expr; + )* + ) => { + $crate::paste::item! { + $crate::__impl_module_constants_metadata! { + GENERATE_CODE + $mod_type<$trait_instance: $trait_name> + { $( $other_where_bounds )* } + $( + $( #[doc = $doc_attr] )* + [< $name DefaultByteGetter >] + $name<$trait_instance: $trait_name>: $type = $value; + )* + } + } + }; + // With instance + ( + $mod_type:ident<$trait_instance:ident: $trait_name:ident, $instance:ident: $instantiable:path> + { $( $other_where_bounds:tt )* } + $( + $( #[doc = $doc_attr:tt] )* + $name:ident: $type:ty = $value:expr; + )* + ) => { + $crate::paste::item! { + $crate::__impl_module_constants_metadata! { + GENERATE_CODE + $mod_type<$trait_instance: $trait_name, $instance: $instantiable> + { $( $other_where_bounds )* } + $( + $( #[doc = $doc_attr] )* + [< $name DefaultByteGetter >] + $name<$trait_instance: $trait_name, $instance: $instantiable>: $type = $value; + )* + } + } + }; + // Do the code generation + (GENERATE_CODE + $mod_type:ident<$trait_instance:ident: $trait_name:ident $(, $instance:ident: $instantiable:path)?> + { $( $other_where_bounds:tt )* } + $( + $( #[doc = $doc_attr:tt] )* + $default_byte_name:ident + $name:ident< + $const_trait_instance:ident: $const_trait_name:ident $( + , $const_instance:ident: $const_instantiable:path + )* + >: $type:ty = $value:expr; + )* + ) => { + impl<$trait_instance: 'static + $trait_name $(, $instance: $instantiable)?> + $mod_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )* + { + #[doc(hidden)] + pub fn module_constants_metadata() -> &'static [$crate::dispatch::ModuleConstantMetadata] { + // Create the `ByteGetter`s + $( + #[allow(non_upper_case_types)] + #[allow(non_camel_case_types)] + struct $default_byte_name< + $const_trait_instance: $const_trait_name $( + , $const_instance: $const_instantiable + )? + >($crate::dispatch::marker::PhantomData< + ($const_trait_instance $(, $const_instance)?) + >); + impl<$const_trait_instance: 'static + $const_trait_name $( + , $const_instance: $const_instantiable)? + > $crate::dispatch::DefaultByte + for $default_byte_name <$const_trait_instance $(, $const_instance)?> + { + fn default_byte(&self) -> $crate::dispatch::Vec { + let value: $type = $value; + $crate::dispatch::Encode::encode(&value) + } + } + )* + &[ + $( + $crate::dispatch::ModuleConstantMetadata { + name: $crate::dispatch::DecodeDifferent::Encode(stringify!($name)), + ty: $crate::dispatch::DecodeDifferent::Encode(stringify!($type)), + value: $crate::dispatch::DecodeDifferent::Encode( + $crate::dispatch::DefaultByteGetter( + &$default_byte_name::< + $const_trait_instance $(, $const_instance)? + >( + $crate::dispatch::marker::PhantomData + ) + ) + ), + documentation: $crate::dispatch::DecodeDifferent::Encode( + &[ $( $doc_attr ),* ] + ), + } + ),* + ] + } + } + } +} + /// Convert the list of calls into their JSON representation, joined by ",". #[macro_export] #[doc(hidden)] macro_rules! __call_to_functions { ( $call_type:ident $origin_type:ty - {$( + { + $( $(#[doc = $doc_attr:tt])* fn $fn_name:ident($from:ident $( , $(#[$codec_attr:ident])* $param_name:ident : $param:ty )* ); - )*} + )* + } ) => { $crate::__functions_to_metadata!(0; $origin_type;; $( fn $fn_name( $($(#[$codec_attr])* $param_name: $param ),* ); @@ -1286,7 +1537,7 @@ macro_rules! __function_to_metadata { compile_error!(concat!( "Invalid attribute for parameter `", stringify!($param_name), "`, the following attributes are supported: `#[compact]`" - )) + )); } } @@ -1329,28 +1580,33 @@ mod tests { use super::*; use crate::runtime_primitives::traits::{OnInitialize, OnFinalize}; - pub trait Trait { + pub trait Trait: system::Trait + Sized where Self::AccountId: From { type Origin; type BlockNumber: Into; + type Call: From>; } pub mod system { use super::Result; + pub trait Trait { + type AccountId; + } + pub fn ensure_root(_: R) -> Result { Ok(()) } } decl_module! { - pub struct Module for enum Call where origin: T::Origin { + pub struct Module for enum Call where origin: T::Origin, T::AccountId: From { /// Hi, this is a comment. fn aux_0(_origin) -> Result { unreachable!() } fn aux_1(_origin, #[compact] _data: u32) -> Result { unreachable!() } fn aux_2(_origin, _data: i32, _data2: String) -> Result { unreachable!() } #[weight = TransactionWeight::Basic(10, 100)] - fn aux_3() -> Result { unreachable!() } - fn aux_4(_data: i32) -> Result { unreachable!() } + fn aux_3(_origin) -> Result { unreachable!() } + fn aux_4(_origin, _data: i32) -> Result { unreachable!() } fn aux_5(_origin, _data: i32, #[compact] _data2: u32) -> Result { unreachable!() } fn on_initialize(n: T::BlockNumber) { if n.into() == 42 { panic!("on_initialize") } } @@ -1358,7 +1614,7 @@ mod tests { fn offchain_worker() {} #[weight = TransactionWeight::Max] - fn weighted() { unreachable!() } + fn weighted(_origin) { unreachable!() } } } @@ -1430,11 +1686,24 @@ mod tests { }, ]; - struct TraitImpl {} + pub struct TraitImpl {} impl Trait for TraitImpl { type Origin = u32; type BlockNumber = u32; + type Call = OuterCall; + } + + type Test = Module; + + impl_outer_dispatch! { + pub enum OuterCall for TraitImpl where origin: u32 { + self::Test, + } + } + + impl system::Trait for TraitImpl { + type AccountId = u32; } #[test] diff --git a/srml/support/src/event.rs b/srml/support/src/event.rs index 052e52d4f56463675dd5cc235da255bb7978aefc..857f42f49e8aaa2b9dfc2a2c49f6a1575a9883b2 100644 --- a/srml/support/src/event.rs +++ b/srml/support/src/event.rs @@ -136,6 +136,7 @@ macro_rules! decl_event { } impl Event { #[allow(dead_code)] + #[doc(hidden)] pub fn metadata() -> &'static [ $crate::event::EventMetadata ] { $crate::__events_to_metadata!(; $( $events )* ) } @@ -321,17 +322,15 @@ macro_rules! __events_to_metadata { } /// Constructs an Event type for a runtime. This is usually called automatically by the -/// construct_runtime macro. See also __create_decl_macro. +/// construct_runtime macro. #[macro_export] macro_rules! impl_outer_event { - // Macro transformations (to convert invocations with incomplete parameters to the canonical // form) - ( $(#[$attr:meta])* pub enum $name:ident for $runtime:ident { - $( $rest:tt $( <$t:ident $(, $rest_instance:path)? > )*, )* + $( $rest_event_without_system:tt )* } ) => { $crate::impl_outer_event!( @@ -339,14 +338,14 @@ macro_rules! impl_outer_event { $name; $runtime; system; - Modules { $( $rest $(<$t $(, $rest_instance)? >)*, )* }; + Modules { $( $rest_event_without_system )* }; ; ); }; ( $(#[$attr:meta])* pub enum $name:ident for $runtime:ident where system = $system:ident { - $( $rest:tt $( <$t:ident $(, $rest_instance:path)? > )*, )* + $( $rest_event_with_system:tt )* } ) => { $crate::impl_outer_event!( @@ -354,30 +353,74 @@ macro_rules! impl_outer_event { $name; $runtime; $system; - Modules { $( $rest $(<$t $(, $rest_instance)? >)*, )* }; + Modules { $( $rest_event_with_system )* }; ; ); }; + // Generic + Instance + ( + $(#[$attr:meta])*; + $name:ident; + $runtime:ident; + $system:ident; + Modules { + $module:ident $instance:ident, + $( $rest_event_generic_instance:tt )* + }; + $( $module_name:ident::Event $( <$generic_param:ident> )? $( { $generic_instance:ident } )?, )*; + ) => { + $crate::impl_outer_event!( + $( #[$attr] )*; + $name; + $runtime; + $system; + Modules { $( $rest_event_generic_instance )* }; + $( $module_name::Event $( <$generic_param> )? $( { $generic_instance } )?, )* $module::Event<$runtime>{ $instance },; + ); + }; + // Instance + ( + $(#[$attr:meta])*; + $name:ident; + $runtime:ident; + $system:ident; + Modules { + $module:ident $instance:ident, + $( $rest_event_instance:tt )* + }; + $( $module_name:ident::Event $( <$generic_param:ident> )? $( { $generic_instance:ident } )?, )*; + ) => { + $crate::impl_outer_event!( + $( #[$attr] )*; + $name; + $runtime; + $system; + Modules { $( $rest_event_instance )* }; + $( $module_name::Event $( <$generic_param> )* $( { $generic_instance } )?, )* $module::Event { $instance },; + ); + }; + // Generic ( $(#[$attr:meta])*; $name:ident; $runtime:ident; $system:ident; Modules { - $module:ident, - $( $rest:tt $( <$t:ident $(, $rest_instance:path)? > )*, )* + $module:ident, + $( $rest_event_generic:tt )* }; - $( $module_name:ident::Event $( <$generic_param:ident $(, $generic_instance:path)? > )*, )*; + $( $module_name:ident::Event $( <$generic_param:ident> )? $( { $generic_instance:ident } )?, )*; ) => { $crate::impl_outer_event!( $( #[$attr] )*; $name; $runtime; $system; - Modules { $( $rest $(<$t $(, $rest_instance)? >)*, )* }; - $( $module_name::Event $( <$generic_param $(, $generic_instance)? > )*, )* $module::Event<$runtime $(, $instance)? >,; + Modules { $( $rest_event_generic )* }; + $( $module_name::Event $( <$generic_param> )? $( { $generic_instance } )?, )* $module::Event<$runtime>,; ); }; + // No Generic and no Instance ( $(#[$attr:meta])*; $name:ident; @@ -385,30 +428,30 @@ macro_rules! impl_outer_event { $system:ident; Modules { $module:ident, - $( $rest:tt )* + $( $rest_event_no_generic_no_instance:tt )* }; - $( $module_name:ident::Event $( <$generic_param:ident $(, $generic_instance:path)? > )*, )*; + $( $module_name:ident::Event $( <$generic_param:ident> )? $( { $generic_instance:ident } )?, )*; ) => { $crate::impl_outer_event!( $( #[$attr] )*; $name; $runtime; $system; - Modules { $( $rest )* }; - $( $module_name::Event $( <$generic_param $(, $generic_instance)? > )*, )* $module::Event,; + Modules { $( $rest_event_no_generic_no_instance )* }; + $( $module_name::Event $( <$generic_param> )? $( { $generic_instance } )?, )* $module::Event,; ); }; // The main macro expansion that actually renders the Event enum code. - ( $(#[$attr:meta])*; $name:ident; $runtime:ident; $system:ident; Modules {}; - $( $module_name:ident::Event $( <$generic_param:ident $(, $generic_instance:path)? > )*, )*; + $( $module_name:ident::Event $( <$generic_param:ident> )? $( { $generic_instance:ident } )?, )*; ) => { + $crate::paste::item! { // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, PartialEq, Eq, $crate::codec::Encode, $crate::codec::Decode)] #[cfg_attr(feature = "std", derive(Debug))] @@ -417,7 +460,9 @@ macro_rules! impl_outer_event { pub enum $name { system($system::Event), $( - $module_name( $module_name::Event $( <$generic_param $(, $generic_instance)? > )* ), + [< $module_name $(_ $generic_instance )? >]( + $module_name::Event < $( $generic_param )? $(, $module_name::$generic_instance )? > + ), )* } impl From<$system::Event> for $name { @@ -426,17 +471,22 @@ macro_rules! impl_outer_event { } } $( - impl From<$module_name::Event $( <$generic_param $(, $generic_instance)? > )*> for $name { - fn from(x: $module_name::Event $( <$generic_param $(, $generic_instance)? > )*) -> Self { - $name::$module_name(x) + impl From<$module_name::Event < $( $generic_param, )? $( $module_name::$generic_instance )? >> for $name { + fn from(x: $module_name::Event < $( $generic_param, )? $( $module_name::$generic_instance )? >) -> Self { + $name::[< $module_name $(_ $generic_instance )? >](x) } } )* + } $crate::__impl_outer_event_json_metadata!( $runtime; $name; $system; - $( $module_name::Event $( <$generic_param $(, $generic_instance)? > )*, )*; + $( + $module_name::Event + < $( $generic_param )? $(, $module_name::$generic_instance )? > + $( $generic_instance )?, + )*; ); } } @@ -448,7 +498,7 @@ macro_rules! __impl_outer_event_json_metadata { $runtime:ident; $event_name:ident; $system:ident; - $( $module_name:ident::Event $( <$generic_param:ident $(, $generic_instance:path)? > )*, )*; + $( $module_name:ident::Event < $( $generic_params:path ),* > $( $instance:ident )?, )*; ) => { impl $runtime { #[allow(dead_code)] @@ -461,7 +511,7 @@ macro_rules! __impl_outer_event_json_metadata { , ( stringify!($module_name), $crate::event::FnEncode( - $module_name::Event $( ::<$generic_param $(, $generic_instance)? > )* ::metadata + $module_name::Event ::< $( $generic_params ),* > ::metadata ) ) )* @@ -472,14 +522,17 @@ macro_rules! __impl_outer_event_json_metadata { pub fn __module_events_system() -> &'static [$crate::event::EventMetadata] { system::Event::metadata() } - $( - #[allow(dead_code)] - $crate::paste::item!{ - pub fn [< __module_events_ $module_name >] () -> &'static [$crate::event::EventMetadata] { - $module_name::Event $( ::<$generic_param $(, $generic_instance)? > )* ::metadata() + + $crate::paste::item! { + $( + #[allow(dead_code)] + pub fn [< __module_events_ $module_name $( _ $instance )? >] () -> + &'static [$crate::event::EventMetadata] + { + $module_name::Event ::< $( $generic_params ),* > ::metadata() } - } - )* + )* + } } } } diff --git a/srml/support/src/lib.rs b/srml/support/src/lib.rs index ae825397a6ae4f0ae9f51324e9c50348b45f00de..361fef969b3a16c29bce5fa69106efda8ee36653 100644 --- a/srml/support/src/lib.rs +++ b/srml/support/src/lib.rs @@ -34,7 +34,9 @@ pub use once_cell; pub use paste; pub use sr_primitives as runtime_primitives; -pub use self::storage::hashed::generator::{HashedStorage, Twox256, Twox128, Blake2_256, Blake2_128, Twox64Concat}; +pub use self::storage::hashed::generator::{ + HashedStorage, Twox256, Twox128, Blake2_256, Blake2_128, Twox64Concat +}; pub use self::storage::unhashed::generator::UnhashedStorage; #[macro_use] @@ -64,6 +66,7 @@ pub use self::hashable::Hashable; pub use self::dispatch::{Parameter, Dispatchable, Callable, IsSubType}; pub use self::double_map::StorageDoubleMapWithHasher; pub use runtime_io::{print, storage_root}; +pub use runtime_primitives::ConsensusEngineId; /// Macro for easily creating a new implementation of the `Get` trait. Use similarly to /// how you would declare a `const`: @@ -82,19 +85,28 @@ pub use runtime_io::{print, storage_root}; /// ``` #[macro_export] macro_rules! parameter_types { - (pub const $name:ident: $type:ty = $value:expr; $( $rest:tt )*) => ( - pub struct $name; - $crate::parameter_types!{IMPL $name , $type , $value} - $crate::parameter_types!{ $( $rest )* } - ); - (const $name:ident: $type:ty = $value:expr; $( $rest:tt )*) => ( - struct $name; + ( + $( #[ $attr:meta ] )* + $vis:vis const $name:ident: $type:ty = $value:expr; + $( $rest:tt )* + ) => ( + $( #[ $attr ] )* + $vis struct $name; $crate::parameter_types!{IMPL $name , $type , $value} $crate::parameter_types!{ $( $rest )* } ); () => (); (IMPL $name:ident , $type:ty , $value:expr) => { - impl $crate::traits::Get<$type> for $name { fn get() -> $type { $value } } + impl $name { + fn get() -> $type { + $value + } + } + impl> $crate::traits::Get for $name { + fn get() -> I { + I::from($value) + } + } } } @@ -238,10 +250,9 @@ mod tests { use super::*; use codec::Codec; use runtime_io::{with_externalities, Blake2Hasher}; - use runtime_primitives::BuildStorage; pub use srml_metadata::{ - DecodeDifferent, StorageMetadata, StorageFunctionMetadata, - StorageFunctionType, StorageFunctionModifier, + DecodeDifferent, StorageEntryMetadata, + StorageEntryType, StorageEntryModifier, DefaultByte, DefaultByteGetter, StorageHasher }; pub use rstd::marker::PhantomData; @@ -257,9 +268,7 @@ mod tests { use super::Trait; decl_module! { - pub struct Module for enum Call where origin: T::Origin { - - } + pub struct Module for enum Call where origin: T::Origin {} } } use self::module::Module; @@ -285,10 +294,10 @@ mod tests { } fn new_test_ext() -> runtime_io::TestExternalities { - GenesisConfig::::default().build_storage().unwrap().0.into() + GenesisConfig::default().build_storage().unwrap().0.into() } - type Map = Data; + type Map = Data; #[test] fn linked_map_basic_insert_remove_should_work() { @@ -371,7 +380,7 @@ mod tests { #[test] fn double_map_basic_insert_remove_remove_prefix_should_work() { with_externalities(&mut new_test_ext(), || { - type DoubleMap = DataDM; + type DoubleMap = DataDM; // initialized during genesis assert_eq!(DoubleMap::get(&15u32, &16u32), 42u64); @@ -422,114 +431,112 @@ mod tests { }); } - const EXPECTED_METADATA: StorageMetadata = StorageMetadata { - functions: DecodeDifferent::Encode(&[ - StorageFunctionMetadata { - name: DecodeDifferent::Encode("Data"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Map{ - hasher: StorageHasher::Twox64Concat, - key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("u64"), is_linked: true - }, - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructData(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), + const EXPECTED_METADATA: &[StorageEntryMetadata] = &[ + StorageEntryMetadata { + name: DecodeDifferent::Encode("Data"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::Map{ + hasher: StorageHasher::Twox64Concat, + key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("u64"), is_linked: true }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("GenericData"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Map{ - hasher: StorageHasher::Twox128, - key: DecodeDifferent::Encode("T::BlockNumber"), - value: DecodeDifferent::Encode("T::BlockNumber"), - is_linked: true - }, - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructGenericData(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructData(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("GenericData"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::Map{ + hasher: StorageHasher::Twox128, + key: DecodeDifferent::Encode("T::BlockNumber"), + value: DecodeDifferent::Encode("T::BlockNumber"), + is_linked: true }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("GenericData2"), - modifier: StorageFunctionModifier::Optional, - ty: StorageFunctionType::Map{ - hasher: StorageHasher::Blake2_256, - key: DecodeDifferent::Encode("T::BlockNumber"), - value: DecodeDifferent::Encode("T::BlockNumber"), - is_linked: true - }, - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructGenericData2(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructGenericData(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("GenericData2"), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Map{ + hasher: StorageHasher::Blake2_256, + key: DecodeDifferent::Encode("T::BlockNumber"), + value: DecodeDifferent::Encode("T::BlockNumber"), + is_linked: true }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("DataDM"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::DoubleMap{ - hasher: StorageHasher::Twox64Concat, - key1: DecodeDifferent::Encode("u32"), - key2: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("u64"), - key2_hasher: StorageHasher::Blake2_256, - }, - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructDataDM(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructGenericData2(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("DataDM"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::DoubleMap{ + hasher: StorageHasher::Twox64Concat, + key1: DecodeDifferent::Encode("u32"), + key2: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("u64"), + key2_hasher: StorageHasher::Blake2_256, }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("GenericDataDM"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::DoubleMap{ - hasher: StorageHasher::Blake2_256, - key1: DecodeDifferent::Encode("T::BlockNumber"), - key2: DecodeDifferent::Encode("T::BlockNumber"), - value: DecodeDifferent::Encode("T::BlockNumber"), - key2_hasher: StorageHasher::Twox128, - }, - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructGenericDataDM(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructDataDM(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("GenericDataDM"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::DoubleMap{ + hasher: StorageHasher::Blake2_256, + key1: DecodeDifferent::Encode("T::BlockNumber"), + key2: DecodeDifferent::Encode("T::BlockNumber"), + value: DecodeDifferent::Encode("T::BlockNumber"), + key2_hasher: StorageHasher::Twox128, }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("GenericData2DM"), - modifier: StorageFunctionModifier::Optional, - ty: StorageFunctionType::DoubleMap{ - hasher: StorageHasher::Blake2_256, - key1: DecodeDifferent::Encode("T::BlockNumber"), - key2: DecodeDifferent::Encode("T::BlockNumber"), - value: DecodeDifferent::Encode("T::BlockNumber"), - key2_hasher: StorageHasher::Twox256, - }, - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructGenericData2DM(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructGenericDataDM(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("GenericData2DM"), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::DoubleMap{ + hasher: StorageHasher::Blake2_256, + key1: DecodeDifferent::Encode("T::BlockNumber"), + key2: DecodeDifferent::Encode("T::BlockNumber"), + value: DecodeDifferent::Encode("T::BlockNumber"), + key2_hasher: StorageHasher::Twox256, }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("AppendableDM"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::DoubleMap{ - hasher: StorageHasher::Blake2_256, - key1: DecodeDifferent::Encode("u32"), - key2: DecodeDifferent::Encode("T::BlockNumber"), - value: DecodeDifferent::Encode("Vec"), - key2_hasher: StorageHasher::Blake2_256, - }, - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructGenericData2DM(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructGenericData2DM(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("AppendableDM"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::DoubleMap{ + hasher: StorageHasher::Blake2_256, + key1: DecodeDifferent::Encode("u32"), + key2: DecodeDifferent::Encode("T::BlockNumber"), + value: DecodeDifferent::Encode("Vec"), + key2_hasher: StorageHasher::Blake2_256, }, - ]) - }; + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructGenericData2DM(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + ]; #[test] fn store_metadata() { - let metadata = Module::::store_metadata(); + let metadata = Module::::store_metadata_functions(); assert_eq!(EXPECTED_METADATA, metadata); } } diff --git a/srml/support/src/metadata.rs b/srml/support/src/metadata.rs index 9a6b671f7792e640067bef8f3706d71b15782e1a..bdb3671e3431546f223ae8116de76ac293808bf3 100644 --- a/srml/support/src/metadata.rs +++ b/srml/support/src/metadata.rs @@ -15,15 +15,11 @@ // along with Substrate. If not, see . pub use srml_metadata::{ - DecodeDifferent, FnEncode, RuntimeMetadata, - ModuleMetadata, RuntimeMetadataV5, - DefaultByteGetter, RuntimeMetadataPrefixed, - StorageMetadata, StorageFunctionMetadata, - StorageFunctionType, StorageFunctionModifier, - DefaultByte, StorageHasher + DecodeDifferent, FnEncode, RuntimeMetadata, ModuleMetadata, RuntimeMetadataV6, + DefaultByteGetter, RuntimeMetadataPrefixed, StorageEntryMetadata, + StorageEntryType, StorageEntryModifier, DefaultByte, StorageHasher }; - /// Implements the metadata support for the given runtime and all its modules. /// /// Example: @@ -40,8 +36,8 @@ macro_rules! impl_runtime_metadata { ) => { impl $runtime { pub fn metadata() -> $crate::metadata::RuntimeMetadataPrefixed { - $crate::metadata::RuntimeMetadata::V5 ( - $crate::metadata::RuntimeMetadataV5 { + $crate::metadata::RuntimeMetadata::V6 ( + $crate::metadata::RuntimeMetadataV6 { modules: $crate::__runtime_modules_to_metadata!($runtime;; $( $rest )*), } ).into() @@ -67,6 +63,11 @@ macro_rules! __runtime_modules_to_metadata { storage: $crate::__runtime_modules_to_metadata_calls_storage!($mod, $module $( <$instance> )?, $runtime, $(with $kw)*), calls: $crate::__runtime_modules_to_metadata_calls_call!($mod, $module $( <$instance> )?, $runtime, $(with $kw)*), event: $crate::__runtime_modules_to_metadata_calls_event!($mod, $module $( <$instance> )?, $runtime, $(with $kw)*), + constants: $crate::metadata::DecodeDifferent::Encode( + $crate::metadata::FnEncode( + $mod::$module::<$runtime $(, $mod::$instance )?>::module_constants_metadata + ) + ) }; $( $rest )* ) @@ -227,23 +228,31 @@ macro_rules! __runtime_modules_to_metadata_calls_storage { mod tests { use super::*; use srml_metadata::{ - EventMetadata, - StorageFunctionModifier, StorageFunctionType, FunctionMetadata, - StorageFunctionMetadata, - ModuleMetadata, RuntimeMetadataPrefixed + EventMetadata, StorageEntryModifier, StorageEntryType, FunctionMetadata, StorageEntryMetadata, + ModuleMetadata, RuntimeMetadataPrefixed, DefaultByte, ModuleConstantMetadata, DefaultByteGetter, }; - use crate::codec::{Encode, Decode}; + use codec::{Encode, Decode}; + use crate::traits::Get; mod system { + use super::*; + pub trait Trait { + const ASSOCIATED_CONST: u64 = 500; type Origin: Into, Self::Origin>> + From>; - type AccountId; - type BlockNumber; + type AccountId: From + Encode; + type BlockNumber: From + Encode; + type SomeValue: Get; } decl_module! { - pub struct Module for enum Call where origin: T::Origin {} + pub struct Module for enum Call where origin: T::Origin { + /// Hi, I am a comment. + const BlockNumber: T::BlockNumber = 100.into(); + const GetType: T::AccountId = T::SomeValue::get().into(); + const ASSOCIATED_CONST: u64 = T::ASSOCIATED_CONST.into(); + } } decl_event!( @@ -359,10 +368,15 @@ mod tests { type BlockNumber = u32; } + crate::parameter_types! { + pub const SystemValue: u32 = 600; + } + impl system::Trait for TestRuntime { type Origin = Origin; type AccountId = u32; type BlockNumber = u32; + type SomeValue = SystemValue; } impl_runtime_metadata!( @@ -372,76 +386,130 @@ mod tests { event_module2::Module with Event Storage Call, ); - const EXPECTED_METADATA: RuntimeMetadata = RuntimeMetadata::V5( - RuntimeMetadataV5 { - modules: DecodeDifferent::Encode(&[ - ModuleMetadata { - name: DecodeDifferent::Encode("system"), - prefix: DecodeDifferent::Encode(FnEncode(||"")), - storage: None, - calls: None, - event: Some(DecodeDifferent::Encode( - FnEncode(||&[ - EventMetadata { - name: DecodeDifferent::Encode("SystemEvent"), - arguments: DecodeDifferent::Encode(&[]), - documentation: DecodeDifferent::Encode(&[]) - } - ]) - )), - }, - ModuleMetadata { - name: DecodeDifferent::Encode("event_module"), - prefix: DecodeDifferent::Encode(FnEncode(||"")), - storage: None, - calls: Some( - DecodeDifferent::Encode(FnEncode(||&[ - FunctionMetadata { - name: DecodeDifferent::Encode("aux_0"), - arguments: DecodeDifferent::Encode(&[]), - documentation: DecodeDifferent::Encode(&[]), - } - ]))), - event: Some(DecodeDifferent::Encode( - FnEncode(||&[ - EventMetadata { - name: DecodeDifferent::Encode("TestEvent"), - arguments: DecodeDifferent::Encode(&["Balance"]), - documentation: DecodeDifferent::Encode(&[" Hi, I am a comment."]) - } - ]) - )), - }, - ModuleMetadata { - name: DecodeDifferent::Encode("event_module2"), - prefix: DecodeDifferent::Encode(FnEncode(||"TestStorage")), - storage: Some(DecodeDifferent::Encode( - FnEncode(||&[ - StorageFunctionMetadata { - name: DecodeDifferent::Encode("StorageMethod"), - modifier: StorageFunctionModifier::Optional, - ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")), - default: DecodeDifferent::Encode( - DefaultByteGetter( - &event_module2::__GetByteStructStorageMethod(::std::marker::PhantomData::) - ) - ), - documentation: DecodeDifferent::Encode(&[]), - } - ]) - )), - calls: Some(DecodeDifferent::Encode(FnEncode(||&[ ]))), - event: Some(DecodeDifferent::Encode( - FnEncode(||&[ - EventMetadata { - name: DecodeDifferent::Encode("TestEvent"), - arguments: DecodeDifferent::Encode(&["Balance"]), - documentation: DecodeDifferent::Encode(&[]) - } - ]) - )), - }, - ])} + struct ConstantBlockNumberByteGetter; + impl DefaultByte for ConstantBlockNumberByteGetter { + fn default_byte(&self) -> Vec { + 100u32.encode() + } + } + + struct ConstantGetTypeByteGetter; + impl DefaultByte for ConstantGetTypeByteGetter { + fn default_byte(&self) -> Vec { + SystemValue::get().encode() + } + } + + struct ConstantAssociatedConstByteGetter; + impl DefaultByte for ConstantAssociatedConstByteGetter { + fn default_byte(&self) -> Vec { + ::ASSOCIATED_CONST.encode() + } + } + + const EXPECTED_METADATA: RuntimeMetadata = RuntimeMetadata::V6( + RuntimeMetadataV6 { + modules: DecodeDifferent::Encode(&[ + ModuleMetadata { + name: DecodeDifferent::Encode("system"), + prefix: DecodeDifferent::Encode(FnEncode(|| "")), + storage: None, + calls: None, + event: Some(DecodeDifferent::Encode( + FnEncode(||&[ + EventMetadata { + name: DecodeDifferent::Encode("SystemEvent"), + arguments: DecodeDifferent::Encode(&[]), + documentation: DecodeDifferent::Encode(&[]) + } + ]) + )), + constants: DecodeDifferent::Encode( + FnEncode(|| &[ + ModuleConstantMetadata { + name: DecodeDifferent::Encode("BlockNumber"), + ty: DecodeDifferent::Encode("T::BlockNumber"), + value: DecodeDifferent::Encode( + DefaultByteGetter(&ConstantBlockNumberByteGetter) + ), + documentation: DecodeDifferent::Encode(&[" Hi, I am a comment."]), + }, + ModuleConstantMetadata { + name: DecodeDifferent::Encode("GetType"), + ty: DecodeDifferent::Encode("T::AccountId"), + value: DecodeDifferent::Encode( + DefaultByteGetter(&ConstantGetTypeByteGetter) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + ModuleConstantMetadata { + name: DecodeDifferent::Encode("ASSOCIATED_CONST"), + ty: DecodeDifferent::Encode("u64"), + value: DecodeDifferent::Encode( + DefaultByteGetter(&ConstantAssociatedConstByteGetter) + ), + documentation: DecodeDifferent::Encode(&[]), + } + ]) + ), + }, + ModuleMetadata { + name: DecodeDifferent::Encode("event_module"), + prefix: DecodeDifferent::Encode(FnEncode(|| "")), + storage: None, + calls: Some( + DecodeDifferent::Encode(FnEncode(|| &[ + FunctionMetadata { + name: DecodeDifferent::Encode("aux_0"), + arguments: DecodeDifferent::Encode(&[]), + documentation: DecodeDifferent::Encode(&[]), + } + ]))), + event: Some(DecodeDifferent::Encode( + FnEncode(||&[ + EventMetadata { + name: DecodeDifferent::Encode("TestEvent"), + arguments: DecodeDifferent::Encode(&["Balance"]), + documentation: DecodeDifferent::Encode(&[" Hi, I am a comment."]) + } + ]) + )), + constants: DecodeDifferent::Encode(FnEncode(|| &[])), + }, + ModuleMetadata { + name: DecodeDifferent::Encode("event_module2"), + prefix: DecodeDifferent::Encode(FnEncode(||"TestStorage")), + storage: Some(DecodeDifferent::Encode( + FnEncode(||&[ + StorageEntryMetadata { + name: DecodeDifferent::Encode("StorageMethod"), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Plain(DecodeDifferent::Encode("u32")), + default: DecodeDifferent::Encode( + DefaultByteGetter( + &event_module2::__GetByteStructStorageMethod( + std::marker::PhantomData:: + ) + ) + ), + documentation: DecodeDifferent::Encode(&[]), + } + ]) + )), + calls: Some(DecodeDifferent::Encode(FnEncode(|| &[]))), + event: Some(DecodeDifferent::Encode( + FnEncode(||&[ + EventMetadata { + name: DecodeDifferent::Encode("TestEvent"), + arguments: DecodeDifferent::Encode(&["Balance"]), + documentation: DecodeDifferent::Encode(&[]) + } + ]) + )), + constants: DecodeDifferent::Encode(FnEncode(|| &[])), + }, + ]) + } ); #[test] @@ -450,6 +518,6 @@ mod tests { let metadata_decoded = RuntimeMetadataPrefixed::decode(&mut &metadata_encoded[..]); let expected_metadata: RuntimeMetadataPrefixed = EXPECTED_METADATA.into(); - assert_eq!(expected_metadata, metadata_decoded.unwrap()); + pretty_assertions::assert_eq!(expected_metadata, metadata_decoded.unwrap()); } } diff --git a/srml/support/src/origin.rs b/srml/support/src/origin.rs index 9bc2cab8b9d178630144cfee9d44c3485fef0f1e..f3fec6e3ae6ce16909abd27487262923e8286ee2 100644 --- a/srml/support/src/origin.rs +++ b/srml/support/src/origin.rs @@ -24,24 +24,24 @@ macro_rules! impl_outer_origin { // Macro transformations (to convert invocations with incomplete parameters to the canonical // form) - ( $(#[$attr:meta])* pub enum $name:ident for $runtime:ident { - $( $module:ident $( <$generic:ident $(, $instance:path )? > )? ),* $(,)? + $( $rest_without_system:tt )* } ) => { $crate::impl_outer_origin! { $(#[$attr])* pub enum $name for $runtime where system = system { - $( $module $( <$generic $(, $instance )? > )?, )* + $( $rest_without_system )* } } }; + ( $(#[$attr:meta])* pub enum $name:ident for $runtime:ident where system = $system:ident { - $( $module:ident $( <$generic:ident $(, $instance:path )?> )? ),* $(,)? + $( $rest_with_system:tt )* } ) => { $crate::impl_outer_origin!( @@ -49,20 +49,41 @@ macro_rules! impl_outer_origin { $name; $runtime; $system; - Modules { $( $module $( <$generic $(, $instance )? > )*, )* }; + Modules { $( $rest_with_system )* }; ); }; - // Replace generic param with runtime + // Generic + Instance + ( + $(#[$attr:meta])*; + $name:ident; + $runtime:ident; + $system:ident; + Modules { + $module:ident $instance:ident + $(, $( $rest_module:tt )* )? + }; + $( $parsed:tt )* + ) => { + $crate::impl_outer_origin!( + $( #[$attr] )*; + $name; + $runtime; + $system; + Modules { $( $( $rest_module )* )? }; + $( $parsed )* $module <$runtime> { $instance }, + ); + }; + // Instance ( $(#[$attr:meta])*; $name:ident; $runtime:ident; $system:ident; Modules { - $module:ident $( )?, - $( $rest_module:tt )* + $module:ident $instance:ident + $(, $rest_module:tt )* }; $( $parsed:tt )* ) => { @@ -72,33 +93,80 @@ macro_rules! impl_outer_origin { $runtime; $system; Modules { $( $rest_module )* }; - $( $parsed )* $module $( <$runtime $(, $instance )? > )?, + $( $parsed )* $module { $instance }, ); }; - // The main macro expansion that actually renders the Origin enum code. + // Generic + ( + $(#[$attr:meta])*; + $name:ident; + $runtime:ident; + $system:ident; + Modules { + $module:ident + $(, $( $rest_module:tt )* )? + }; + $( $parsed:tt )* + ) => { + $crate::impl_outer_origin!( + $( #[$attr] )*; + $name; + $runtime; + $system; + Modules { $( $( $rest_module )* )? }; + $( $parsed )* $module <$runtime>, + ); + }; + // No Generic and no Instance + ( + $(#[$attr:meta])*; + $name:ident; + $runtime:ident; + $system:ident; + Modules { + $module:ident + $(, $( $rest_module:tt )* )? + }; + $( $parsed:tt )* + ) => { + $crate::impl_outer_origin!( + $( #[$attr] )*; + $name; + $runtime; + $system; + Modules { $( $( $rest_module )* )? }; + $( $parsed )* $module, + ); + }; + + // The main macro expansion that actually renders the Origin enum code. ( $(#[$attr:meta])*; $name:ident; $runtime:ident; $system:ident; Modules { }; - $( $module:ident $( <$generic_param:ident $(, $generic_instance:path )? > )* ,)* + $( $module:ident $( < $generic:ident > )? $( { $generic_instance:ident } )? ,)* ) => { - // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. - #[derive(Clone, PartialEq, Eq)] - #[cfg_attr(feature = "std", derive(Debug))] - $(#[$attr])* - #[allow(non_camel_case_types)] - pub enum $name { - system($system::Origin<$runtime>), - $( - $module($module::Origin $( <$generic_param $(, $generic_instance )? > )* ), - )* - #[allow(dead_code)] - Void($crate::Void) + $crate::paste::item! { + // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. + #[derive(Clone, PartialEq, Eq)] + #[cfg_attr(feature = "std", derive(Debug))] + $(#[$attr])* + #[allow(non_camel_case_types)] + pub enum $name { + system($system::Origin<$runtime>), + $( + [< $module $( _ $generic_instance )? >] + ($module::Origin < $( $generic, )? $( $module::$generic_instance )? > ), + )* + #[allow(dead_code)] + Void($crate::Void) + } } + #[allow(dead_code)] impl $name { pub const NONE: Self = $name::system($system::RawOrigin::None); @@ -127,23 +195,27 @@ macro_rules! impl_outer_origin { } } $( - impl From<$module::Origin $( <$generic_param $(, $generic_instance )? > )*> for $name { - fn from(x: $module::Origin $( <$generic_param $(, $generic_instance )? > )*) -> Self { - $name::$module(x) + $crate::paste::item! { + impl From<$module::Origin < $( $generic )? $(, $module::$generic_instance )? > > for $name { + fn from(x: $module::Origin < $( $generic )? $(, $module::$generic_instance )? >) -> Self { + $name::[< $module $( _ $generic_instance )? >](x) + } } - } - impl Into<$crate::rstd::result::Result< - $module::Origin $( <$generic_param $(, $generic_instance )? > )*, - $name - >> for $name { - fn into(self) -> $crate::rstd::result::Result< - $module::Origin $( <$generic_param $(, $generic_instance )? > )*, - Self - > { - if let $name::$module(l) = self { - Ok(l) - } else { - Err(self) + impl Into< + $crate::rstd::result::Result< + $module::Origin < $( $generic )? $(, $module::$generic_instance )? >, + $name, + >> + for $name { + fn into(self) -> $crate::rstd::result::Result< + $module::Origin < $( $generic )? $(, $module::$generic_instance )? >, + Self, + > { + if let $name::[< $module $( _ $generic_instance )? >](l) = self { + Ok(l) + } else { + Err(self) + } } } } diff --git a/srml/support/src/runtime.rs b/srml/support/src/runtime.rs index 6bccac0d4eff01def9000d1a23c809c84349aa9a..4461e37518698a3c145a726a58ece426c9759a3c 100644 --- a/srml/support/src/runtime.rs +++ b/srml/support/src/runtime.rs @@ -61,9 +61,9 @@ /// - `Module` /// - `Call` /// - `Storage` -/// - `Event` or `Event` (if the event is generic) or `Event` (if also over instance) -/// - `Origin` or `Origin` (if the origin is generic) or `Origin` (if also over instance) -/// - `Config` or `Config` (if the config is generic) or `Config` (if also over instance) +/// - `Event` or `Event` (if the event is generic) +/// - `Origin` or `Origin` (if the origin is generic) +/// - `Config` or `Config` (if the config is generic) /// - `Inherent $( (CALL) )*` - If the module provides/can check inherents. The optional parameter /// is for modules that use a `Call` from a different module as /// inherent. @@ -101,6 +101,7 @@ macro_rules! construct_runtime { $( $rest )* ); }; + // No modules given, expand to the default module set. ( { $( $preset:tt )* }; { $( $expanded:tt )* }; @@ -114,41 +115,17 @@ macro_rules! construct_runtime { $( $rest )* ); }; + // `default` identifier given, expand to default + given extra modules ( { $( $preset:tt )* }; { $( $expanded:tt )* }; $name:ident: $module:ident::{ default $(, - $modules:ident - $( <$modules_generic:ident $(, $modules_instance:ident)?> )* - $( ( $( $modules_args:ident ),* ) )* - )* - }, - $( $rest:tt )* - ) => { - $crate::construct_runtime!( - { $( $preset )* }; - { $( $expanded )* }; - $name: $module::{ - Module, Call, Storage, Event, Config - $(, - $modules $( <$modules_generic $(, $modules_instance)?> )* - $( ( $( $modules_args ),* ) )* - )* - }, - $( $rest )* - ); - }; - ( - { $( $preset:tt )* }; - { $( $expanded:tt )* }; - $name:ident: $module:ident::{ - $( $modules:ident $( <$modules_generic:ident> )* $( ( $( $modules_args:ident ),* ) )* - ),* + )* }, $( $rest:tt )* ) => { @@ -157,22 +134,24 @@ macro_rules! construct_runtime { { $( $expanded )* $name: $module::{ - $( + Module, Call, Storage, Event, Config + $(, $modules $( <$modules_generic> )* $( ( $( $modules_args ),* ) )* - ),* + )* }, }; $( $rest )* ); }; - ( // Instance module: we indicate the generic instance `I` with the full instance path + // Take all modules as given by the user. + ( { $( $preset:tt )* }; { $( $expanded:tt )* }; - $name:ident: $module:ident ::< $module_instance:ident >::{ + $name:ident: $module:ident :: $( < $module_instance:ident >:: )? { $( $modules:ident - $( <$modules_generic:ident $(, $modules_instance:ident )?> )* + $( <$modules_generic:ident> )* $( ( $( $modules_args:ident ),* ) )* ),* }, @@ -182,9 +161,9 @@ macro_rules! construct_runtime { { $( $preset )* }; { $( $expanded )* - $name: $module::<$module_instance>::{ + $name: $module:: $( < $module_instance >:: )? { $( - $modules $( <$modules_generic $(, $modules_instance=$module::$module_instance)?> )* + $modules $( <$modules_generic> )* $( ( $( $modules_args ),* ) )* ),* }, @@ -192,9 +171,7 @@ macro_rules! construct_runtime { $( $rest )* ); }; - // The main macro expansion that actually renders the Runtime code. - ( { $runtime:ident; @@ -207,7 +184,7 @@ macro_rules! construct_runtime { $name:ident: $module:ident :: $( < $module_instance:ident >:: )? { $( $modules:ident - $( <$modules_generic:ident $(, I=$modules_instance:path)?> )* + $( <$modules_generic:ident> )* $( ( $( $modules_args:ident ),* ) )* ),* }, @@ -223,19 +200,20 @@ macro_rules! construct_runtime { impl $crate::runtime_primitives::traits::GetRuntimeBlockType for $runtime { type RuntimeBlock = $block; } - $crate::__decl_instance_import!( - $( $( $module < $module_instance > )? )* - ); $crate::__decl_outer_event!( $runtime; $( - $name: $module:: $( < $module_instance >:: )? { $( $modules $( <$modules_generic $(, $modules_instance)?> )* ),* } + $name: $module:: $( < $module_instance >:: )? { + $( $modules $( <$modules_generic> )* ),* + } ),* ); $crate::__decl_outer_origin!( $runtime; $( - $name: $module:: $( < $module_instance >:: )? { $( $modules $( <$modules_generic $(, $modules_instance)?> )* ),* } + $name: $module:: $( < $module_instance >:: )? { + $( $modules $( <$modules_generic> )* ),* + } ),* ); $crate::__decl_all_modules!( @@ -265,7 +243,7 @@ macro_rules! construct_runtime { {}; $( $name: $module:: $( < $module_instance >:: )? { - $( $modules $( <$modules_generic $(, $modules_instance)?> )* ),* + $( $modules $( <$modules_generic> )* ),* }, )* ); @@ -307,7 +285,7 @@ macro_rules! __create_decl_macro { ( $runtime:ident; $d( $name:ident : $module:ident:: $d( < $module_instance:ident >:: )? { - $d( $modules:ident $d( <$modules_generic:ident $d(, $modules_instance:path)?> ),* ),* + $d( $modules:ident $d( <$modules_generic:ident> ),* ),* }),* ) => { $d crate::$macro_name!(@inner @@ -316,7 +294,7 @@ macro_rules! __create_decl_macro { {}; $d( $name: $module:: $d( < $module_instance >:: )? { - $d( $modules $d( <$modules_generic $d(, $modules_instance)?> )* ),* + $d( $modules $d( <$modules_generic> )* ),* }, )* ); @@ -342,7 +320,7 @@ macro_rules! __create_decl_macro { $d( $system:ident )?; { $d( $parsed:tt )* }; $name:ident : $module:ident:: < $module_instance:ident >:: { - $macro_enum_name <$event_generic:ident, $event_instance:path> $d(, $ignore:ident $d( <$ignor:ident $d(, $ignore_instance:path)?> )* )* + $macro_enum_name <$event_generic:ident> $d(, $ingore:ident $d( <$ignor:ident> )* )* }, $d( $rest:tt )* ) => { @@ -351,33 +329,17 @@ macro_rules! __create_decl_macro { $d( $system )?; { $d( $parsed )* - $module $module_instance <$event_generic, $event_instance>, + $module $module_instance <$event_generic>, }; $d( $rest )* ); }; - (@inner - $runtime:ident; - $d( $system:ident )?; - { $d( $parsed:tt )* }; - $name:ident : $module:ident:: < $module_instance:ident >:: { - $macro_enum_name $d( <$event_generic:ident> )* $d(, $ignore:ident $d( <$ignor:ident $d(, $ignore_instance:path)?> )* )* - }, - $d( $rest:tt )* - ) => { - compile_error!{concat!{ - "Module `", stringify!{$name}, "` must have `", stringify!{$macro_enum_name}, "`", - " but has `", stringify!{$macro_enum_name} $d(, "<", stringify!{$event_generic}, ">")*, "`", - ": Instantiated modules must have ", stringify!{$macro_enum_name}, - " generic over instance to be able to convert to outer ", stringify!{$macro_enum_name} - }} - }; (@inner $runtime:ident; $d( $system:ident )?; { $d( $parsed:tt )* }; $name:ident : $module:ident:: { - $macro_enum_name $d( <$event_generic:ident $d(, $event_instance:path)?> )* $d(, $ignore:ident $d( <$ignor:ident $d(, $ignore_instance:path)?> )* )* + $macro_enum_name $d( <$event_generic:ident> )* $d(, $ignore:ident $d( <$ignor:ident> )* )* }, $d( $rest:tt )* ) => { @@ -386,7 +348,7 @@ macro_rules! __create_decl_macro { $d( $system )?; { $d( $parsed )* - $module $d( <$event_generic $d(, $event_instance)?> )*, + $module $d( <$event_generic> )*, }; $d( $rest )* ); @@ -396,7 +358,7 @@ macro_rules! __create_decl_macro { $d( $system:ident )?; { $d( $parsed:tt )* }; $name:ident : $module:ident:: $d( < $module_instance:ident >:: )? { - $ignore:ident $d( <$ignor:ident $d(, $ignore_instance:path)?> )* $d(, $modules:ident $d( <$modules_generic:ident $d(, $modules_instance:path)?> )* )* + $ingore:ident $d( <$ignor:ident> )* $d(, $modules:ident $d( <$modules_generic:ident> )* )* }, $d( $rest:tt )* ) => { @@ -404,7 +366,7 @@ macro_rules! __create_decl_macro { $runtime; $d( $system )?; { $d( $parsed )* }; - $name: $module:: $d( < $module_instance >:: )? { $d( $modules $d( <$modules_generic $d(, $modules_instance)?> )* ),* }, + $name: $module:: $d( < $module_instance >:: )? { $d( $modules $d( <$modules_generic> )* ),* }, $d( $rest )* ); }; @@ -425,16 +387,13 @@ macro_rules! __create_decl_macro { (@inner $runtime:ident; $system:ident; - { $d( $parsed_modules:ident $d( $instance:ident )? $d( <$parsed_generic:ident $d(, $parsed_instance_full_path:path)?> )* ,)* }; + { $d( $parsed_modules:ident $d( $instance:ident )? $d( <$parsed_generic:ident> )? ,)* }; ) => { - $d crate::paste::item! { - $d crate::$macro_outer_name! { - - pub enum $macro_enum_name for $runtime where system = $system { - $d( - [< $parsed_modules $d(_ $instance )? >] $d( <$parsed_generic $d(, $parsed_instance_full_path)?> )*, - )* - } + $d crate::$macro_outer_name! { + pub enum $macro_enum_name for $runtime where system = $system { + $d( + $parsed_modules $d( $instance )? $d( <$parsed_generic> )?, + )* } } } @@ -668,7 +627,7 @@ macro_rules! __decl_runtime_metadata { } } -/// A private macro that generates GenesisConfig for the runtime. See impl_outer_config macro. +/// A private macro that generates GenesisConfig for the runtime. See `impl_outer_config!` macro. #[macro_export] #[doc(hidden)] macro_rules! __decl_outer_config { @@ -676,7 +635,8 @@ macro_rules! __decl_outer_config { $runtime:ident; { $( $parsed:tt )* }; $name:ident: $module:ident:: $( < $module_instance:ident >:: )? { - Config $(< $config_generic:ident $(, $config_instance:path)?>)? $(, $modules:ident $( <$modules_generic:ident $(, $modules_instance:path)?> )* )* + Config $( <$config_generic:ident> )? + $(, $modules:ident $( <$modules_generic:ident> )* )* }, $( $rest:tt )* ) => { @@ -684,7 +644,7 @@ macro_rules! __decl_outer_config { $runtime; { $( $parsed )* - $module::$name $( $module_instance )? $(<$config_generic $(, $config_instance)?>)?, + $module::$name $( $module_instance )? $( <$config_generic> )?, }; $( $rest )* ); @@ -693,14 +653,15 @@ macro_rules! __decl_outer_config { $runtime:ident; { $( $parsed:tt )* }; $name:ident: $module:ident:: $( < $module_instance:ident >:: )? { - $ignore:ident $( <$ignor:ident $(, $ignore_instance:path)?> )* $(, $modules:ident $( <$modules_generic:ident $(, $modules_instance:path)?> )* )* + $ingore:ident $( <$ignore_gen:ident> )* + $(, $modules:ident $( <$modules_generic:ident> )* )* }, $( $rest:tt )* ) => { $crate::__decl_outer_config!( $runtime; { $( $parsed )* }; - $name: $module:: $( < $module_instance >:: )? { $( $modules $( <$modules_generic $(, $modules_instance)?> )* ),* }, + $name: $module:: $( < $module_instance >:: )? { $( $modules $( <$modules_generic> )* ),* }, $( $rest )* ); }; @@ -718,13 +679,21 @@ macro_rules! __decl_outer_config { }; ( $runtime:ident; - {$( $parsed_modules:ident :: $parsed_name:ident $( $parsed_instance:ident )? $( < $parsed_generic:ident $(, $parsed_instance_full_path:path)? > )* ,)* }; + { + $( + $parsed_modules:ident :: $parsed_name:ident $( $parsed_instance:ident )? + $( + <$parsed_generic:ident> + )* + ,)* + }; ) => { $crate::paste::item! { $crate::runtime_primitives::impl_outer_config!( pub struct GenesisConfig for $runtime { $( - [< $parsed_name Config >] => [< $parsed_modules $( _ $parsed_instance)? >] $( < $parsed_generic $(, $parsed_instance_full_path)? > )*, + [< $parsed_name Config >] => + $parsed_modules $( $parsed_instance )? $( <$parsed_generic> )*, )* } ); diff --git a/srml/support/src/storage/child.rs b/srml/support/src/storage/child.rs new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/srml/support/src/storage/hashed/generator.rs b/srml/support/src/storage/hashed/generator.rs index 5a8b2f9d8f54b0fe4f51edb715aafa8614bf589a..cff375e1f634fa464f4a41c725be7d0f8f22aeaa 100644 --- a/srml/support/src/storage/hashed/generator.rs +++ b/srml/support/src/storage/hashed/generator.rs @@ -16,7 +16,7 @@ //! Abstract storage to use on HashedStorage trait -use crate::codec; +use crate::codec::{self, Encode}; use crate::rstd::prelude::{Vec, Box}; #[cfg(feature = "std")] use crate::storage::unhashed::generator::UnhashedStorage; @@ -184,6 +184,13 @@ pub trait StorageValue { storage.put(Self::key(), val) } + /// Store a value under this key into the provided storage instance; this can take any reference + /// type that derefs to `T` (and has `Encode` implemented). + /// Store a value under this key into the provided storage instance. + fn put_ref>(val: &Arg, storage: &mut S) where T: AsRef { + val.using_encoded(|b| storage.put_raw(Self::key(), b)) + } + /// Mutate this value fn mutate R, S: HashedStorage>(f: F, storage: &mut S) -> R; @@ -236,6 +243,17 @@ pub trait StorageMap { storage.put(&Self::key_for(key)[..], val); } + /// Store a value under this key into the provided storage instance; this can take any reference + /// type that derefs to `T` (and has `Encode` implemented). + /// Store a value under this key into the provided storage instance. + fn insert_ref>( + key: &K, + val: &Arg, + storage: &mut S + ) where V: AsRef { + val.using_encoded(|b| storage.put_raw(&Self::key_for(key)[..], b)) + } + /// Remove the value under a key. fn remove>(key: &K, storage: &mut S) { storage.kill(&Self::key_for(key)[..]); diff --git a/srml/support/src/storage/mod.rs b/srml/support/src/storage/mod.rs index a1891dade3b0c5b4010824c0bff8e641e18f9194..db9e4bc31d65721b009c7ba5bf3aa8b9fb8d7e60 100644 --- a/srml/support/src/storage/mod.rs +++ b/srml/support/src/storage/mod.rs @@ -149,6 +149,10 @@ pub trait StorageValue { /// Store a value under this key into the provided storage instance. fn put>(val: Arg); + /// Store a value under this key into the provided storage instance; this can take any reference + /// type that derefs to `T` (and has `Encode` implemented). + fn put_ref(val: &Arg) where T: AsRef; + /// Mutate the value fn mutate R>(f: F) -> R; @@ -180,6 +184,9 @@ impl StorageValue for U where U: hashed::generator::StorageValue fn put>(val: Arg) { U::put(val.borrow(), &mut RuntimeStorage) } + fn put_ref(val: &Arg) where T: AsRef { + U::put_ref(val, &mut RuntimeStorage) + } fn mutate R>(f: F) -> R { U::mutate(f, &mut RuntimeStorage) } @@ -216,6 +223,10 @@ pub trait StorageMap { /// Store a value to be associated with the given key from the map. fn insert, ValArg: Borrow>(key: KeyArg, val: ValArg); + /// Store a value under this key into the provided storage instance; this can take any reference + /// type that derefs to `T` (and has `Encode` implemented). + fn insert_ref, ValArg: ?Sized + Encode>(key: KeyArg, val: &ValArg) where V: AsRef; + /// Remove the value under a key. fn remove>(key: KeyArg); @@ -249,6 +260,10 @@ impl StorageMap for U where U: hashed::generator::S U::insert(key.borrow(), val.borrow(), &mut RuntimeStorage) } + fn insert_ref, ValArg: ?Sized + Encode>(key: KeyArg, val: &ValArg) where V: AsRef { + U::insert_ref(key.borrow(), val, &mut RuntimeStorage) + } + fn remove>(key: KeyArg) { U::remove(key.borrow(), &mut RuntimeStorage) } diff --git a/srml/support/src/storage/storage_items.rs b/srml/support/src/storage/storage_items.rs index 9d89b81e0d950b224f45e31e90aa460a35948230..f67dbf0529419c1d8790d1ab7d932b13c1ce6ad3 100644 --- a/srml/support/src/storage/storage_items.rs +++ b/srml/support/src/storage/storage_items.rs @@ -346,7 +346,7 @@ mod tests { // getters: pub / $default // we need at least one type which uses T, otherwise GenesisConfig will complain. GETU32 get(u32_getter): T::Origin; - pub PUBGETU32 get(pub_u32_getter) build(|config: &GenesisConfig| config.u32_getter_with_config): u32; + pub PUBGETU32 get(pub_u32_getter) build(|config: &GenesisConfig| config.u32_getter_with_config): u32; GETU32WITHCONFIG get(u32_getter_with_config) config(): u32; pub PUBGETU32WITHCONFIG get(pub_u32_getter_with_config) config(): u32; GETU32MYDEF get(u32_getter_mydef): Option = Some(4); @@ -390,333 +390,331 @@ mod tests { type BlockNumber = u32; } - const EXPECTED_METADATA: StorageMetadata = StorageMetadata { - functions: DecodeDifferent::Encode(&[ - StorageFunctionMetadata { - name: DecodeDifferent::Encode("U32"), - modifier: StorageFunctionModifier::Optional, - ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")), - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructU32(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[ " Hello, this is doc!" ]), + const EXPECTED_METADATA: &[StorageEntryMetadata] = &[ + StorageEntryMetadata { + name: DecodeDifferent::Encode("U32"), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Plain(DecodeDifferent::Encode("u32")), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructU32(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[ " Hello, this is doc!" ]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("PUBU32"), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Plain(DecodeDifferent::Encode("u32")), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructPUBU32(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("U32MYDEF"), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Plain(DecodeDifferent::Encode("u32")), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructU32MYDEF(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("PUBU32MYDEF"), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Plain(DecodeDifferent::Encode("u32")), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructPUBU32MYDEF(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("GETU32"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::Plain(DecodeDifferent::Encode("T::Origin")), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructGETU32(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("PUBGETU32"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::Plain(DecodeDifferent::Encode("u32")), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructPUBGETU32(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("GETU32WITHCONFIG"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::Plain(DecodeDifferent::Encode("u32")), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructGETU32WITHCONFIG(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("PUBGETU32WITHCONFIG"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::Plain(DecodeDifferent::Encode("u32")), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructPUBGETU32WITHCONFIG(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("GETU32MYDEF"), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Plain(DecodeDifferent::Encode("u32")), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructGETU32MYDEF(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("PUBGETU32MYDEF"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::Plain(DecodeDifferent::Encode("u32")), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructPUBGETU32MYDEF(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("GETU32WITHCONFIGMYDEF"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::Plain(DecodeDifferent::Encode("u32")), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructGETU32WITHCONFIGMYDEF(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("PUBGETU32WITHCONFIGMYDEF"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::Plain(DecodeDifferent::Encode("u32")), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructPUBGETU32WITHCONFIGMYDEF(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("PUBGETU32WITHCONFIGMYDEFOPT"), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Plain(DecodeDifferent::Encode("u32")), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructPUBGETU32WITHCONFIGMYDEFOPT(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + + StorageEntryMetadata { + name: DecodeDifferent::Encode("MAPU32"), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Map { + hasher: StorageHasher::Blake2_256, + key: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("String"), + is_linked: false, }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("PUBU32"), - modifier: StorageFunctionModifier::Optional, - ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")), - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructPUBU32(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructMAPU32(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("PUBMAPU32"), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Map { + hasher: StorageHasher::Blake2_256, + key: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("String"), + is_linked: false, }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("U32MYDEF"), - modifier: StorageFunctionModifier::Optional, - ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")), - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructU32MYDEF(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructPUBMAPU32(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("MAPU32MYDEF"), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Map { + hasher: StorageHasher::Blake2_256, + key: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("String"), + is_linked: false, }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("PUBU32MYDEF"), - modifier: StorageFunctionModifier::Optional, - ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")), - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructPUBU32MYDEF(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructMAPU32MYDEF(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("PUBMAPU32MYDEF"), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Map { + hasher: StorageHasher::Blake2_256, + key: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("String"), + is_linked: false, }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("GETU32"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Plain(DecodeDifferent::Encode("T::Origin")), - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructGETU32(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructPUBMAPU32MYDEF(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("GETMAPU32"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::Map { + hasher: StorageHasher::Blake2_256, + key: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("String"), + is_linked: false, }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("PUBGETU32"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")), - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructPUBGETU32(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructGETMAPU32(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("PUBGETMAPU32"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::Map { + hasher: StorageHasher::Blake2_256, + key: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("String"), + is_linked: false, }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("GETU32WITHCONFIG"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")), - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructGETU32WITHCONFIG(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructPUBGETMAPU32(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("GETMAPU32MYDEF"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::Map { + hasher: StorageHasher::Blake2_256, + key: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("String"), + is_linked: false, }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("PUBGETU32WITHCONFIG"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")), - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructPUBGETU32WITHCONFIG(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructGETMAPU32MYDEF(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("PUBGETMAPU32MYDEF"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::Map { + hasher: StorageHasher::Blake2_256, + key: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("String"), + is_linked: false, }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("GETU32MYDEF"), - modifier: StorageFunctionModifier::Optional, - ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")), - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructGETU32MYDEF(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructPUBGETMAPU32MYDEF(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("LINKEDMAPU32"), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Map { + hasher: StorageHasher::Blake2_256, + key: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("String"), + is_linked: true, }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("PUBGETU32MYDEF"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")), - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructPUBGETU32MYDEF(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructLINKEDMAPU32(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("PUBLINKEDMAPU32MYDEF"), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Map { + hasher: StorageHasher::Blake2_256, + key: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("String"), + is_linked: true, }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("GETU32WITHCONFIGMYDEF"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")), - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructGETU32WITHCONFIGMYDEF(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructPUBLINKEDMAPU32MYDEF(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("GETLINKEDMAPU32"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::Map { + hasher: StorageHasher::Blake2_256, + key: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("String"), + is_linked: true, }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("PUBGETU32WITHCONFIGMYDEF"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")), - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructPUBGETU32WITHCONFIGMYDEF(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructGETLINKEDMAPU32(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("PUBGETLINKEDMAPU32MYDEF"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::Map { + hasher: StorageHasher::Blake2_256, + key: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("String"), + is_linked: true, }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("PUBGETU32WITHCONFIGMYDEFOPT"), - modifier: StorageFunctionModifier::Optional, - ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")), - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructPUBGETU32WITHCONFIGMYDEFOPT(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), - }, - - StorageFunctionMetadata { - name: DecodeDifferent::Encode("MAPU32"), - modifier: StorageFunctionModifier::Optional, - ty: StorageFunctionType::Map { - hasher: StorageHasher::Blake2_256, - key: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("String"), - is_linked: false, - }, - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructMAPU32(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), - }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("PUBMAPU32"), - modifier: StorageFunctionModifier::Optional, - ty: StorageFunctionType::Map { - hasher: StorageHasher::Blake2_256, - key: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("String"), - is_linked: false, - }, - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructPUBMAPU32(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), - }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("MAPU32MYDEF"), - modifier: StorageFunctionModifier::Optional, - ty: StorageFunctionType::Map { - hasher: StorageHasher::Blake2_256, - key: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("String"), - is_linked: false, - }, - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructMAPU32MYDEF(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), - }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("PUBMAPU32MYDEF"), - modifier: StorageFunctionModifier::Optional, - ty: StorageFunctionType::Map { - hasher: StorageHasher::Blake2_256, - key: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("String"), - is_linked: false, - }, - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructPUBMAPU32MYDEF(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), - }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("GETMAPU32"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Map { - hasher: StorageHasher::Blake2_256, - key: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("String"), - is_linked: false, - }, - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructGETMAPU32(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), - }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("PUBGETMAPU32"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Map { - hasher: StorageHasher::Blake2_256, - key: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("String"), - is_linked: false, - }, - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructPUBGETMAPU32(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), - }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("GETMAPU32MYDEF"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Map { - hasher: StorageHasher::Blake2_256, - key: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("String"), - is_linked: false, - }, - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructGETMAPU32MYDEF(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), - }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("PUBGETMAPU32MYDEF"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Map { - hasher: StorageHasher::Blake2_256, - key: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("String"), - is_linked: false, - }, - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructPUBGETMAPU32MYDEF(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), - }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("LINKEDMAPU32"), - modifier: StorageFunctionModifier::Optional, - ty: StorageFunctionType::Map { - hasher: StorageHasher::Blake2_256, - key: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("String"), - is_linked: true, - }, - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructLINKEDMAPU32(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), - }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("PUBLINKEDMAPU32MYDEF"), - modifier: StorageFunctionModifier::Optional, - ty: StorageFunctionType::Map { - hasher: StorageHasher::Blake2_256, - key: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("String"), - is_linked: true, - }, - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructPUBLINKEDMAPU32MYDEF(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), - }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("GETLINKEDMAPU32"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Map { - hasher: StorageHasher::Blake2_256, - key: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("String"), - is_linked: true, - }, - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructGETLINKEDMAPU32(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), - }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("PUBGETLINKEDMAPU32MYDEF"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Map { - hasher: StorageHasher::Blake2_256, - key: DecodeDifferent::Encode("u32"), - value: DecodeDifferent::Encode("String"), - is_linked: true, - }, - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructPUBGETLINKEDMAPU32MYDEF(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), - }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("COMPLEXTYPE1"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Plain(DecodeDifferent::Encode("::std::vec::Vec<::Origin>")), - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructCOMPLEXTYPE1(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), - }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("COMPLEXTYPE2"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Plain(DecodeDifferent::Encode("(Vec)>>, u32)")), - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructCOMPLEXTYPE2(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), - }, - StorageFunctionMetadata { - name: DecodeDifferent::Encode("COMPLEXTYPE3"), - modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Plain(DecodeDifferent::Encode("([u32; 25])")), - default: DecodeDifferent::Encode( - DefaultByteGetter(&__GetByteStructCOMPLEXTYPE3(PhantomData::)) - ), - documentation: DecodeDifferent::Encode(&[]), - }, - ]) - }; + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructPUBGETLINKEDMAPU32MYDEF(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("COMPLEXTYPE1"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::Plain(DecodeDifferent::Encode("::std::vec::Vec<::Origin>")), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructCOMPLEXTYPE1(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("COMPLEXTYPE2"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::Plain(DecodeDifferent::Encode("(Vec)>>, u32)")), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructCOMPLEXTYPE2(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("COMPLEXTYPE3"), + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::Plain(DecodeDifferent::Encode("([u32; 25])")), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructCOMPLEXTYPE3(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + ]; #[test] fn store_metadata() { - let metadata = Module::::store_metadata(); + let metadata = Module::::store_metadata_functions(); assert_eq!(EXPECTED_METADATA, metadata); } #[test] fn check_genesis_config() { - let config = GenesisConfig::::default(); + let config = GenesisConfig::default(); assert_eq!(config.u32_getter_with_config, 0u32); assert_eq!(config.pub_u32_getter_with_config, 0u32); @@ -820,13 +818,13 @@ mod test_map_vec_append { use runtime_io::{with_externalities, TestExternalities}; with_externalities(&mut TestExternalities::default(), || { - let _ = >::append(1, &[1, 2, 3]); - let _ = >::append(1, &[4, 5]); - assert_eq!(>::get(1), vec![1, 2, 3, 4, 5]); + let _ = MapVec::append(1, &[1, 2, 3]); + let _ = MapVec::append(1, &[4, 5]); + assert_eq!(MapVec::get(1), vec![1, 2, 3, 4, 5]); - let _ = >::append(&[1, 2, 3]); - let _ = >::append(&[4, 5]); - assert_eq!(>::get(), vec![1, 2, 3, 4, 5]); + let _ = JustVec::append(&[1, 2, 3]); + let _ = JustVec::append(&[4, 5]); + assert_eq!(JustVec::get(), vec![1, 2, 3, 4, 5]); }); } } diff --git a/srml/support/src/traits.rs b/srml/support/src/traits.rs index 3b3c63e223ce14831368094bf3b882a929c89f74..86071a37a2720390cd93eaeccee136a598e4832f 100644 --- a/srml/support/src/traits.rs +++ b/srml/support/src/traits.rs @@ -18,11 +18,13 @@ //! //! NOTE: If you're looking for `parameter_types`, it has moved in to the top-level module. -use crate::rstd::result; +use crate::rstd::{result, marker::PhantomData, ops::Div}; use crate::codec::{Codec, Encode, Decode}; +use substrate_primitives::u32_trait::Value as U32; use crate::runtime_primitives::traits::{ - MaybeSerializeDebug, SimpleArithmetic + MaybeSerializeDebug, SimpleArithmetic, Saturating }; +use crate::runtime_primitives::ConsensusEngineId; use super::for_each_tuple; @@ -102,6 +104,51 @@ impl MakePayment for () { fn make_payment(_: &T, _: usize) -> Result<(), &'static str> { Ok(()) } } +/// A trait for finding the author of a block header based on the `PreRuntime` digests contained +/// within it. +pub trait FindAuthor { + /// Find the author of a block based on the pre-runtime digests. + fn find_author<'a, I>(digests: I) -> Option + where I: 'a + IntoIterator; +} + +impl FindAuthor for () { + fn find_author<'a, I>(_: I) -> Option + where I: 'a + IntoIterator + { + None + } +} + +/// A trait for verifying the seal of a header and returning the author. +pub trait VerifySeal { + /// Verify a header and return the author, if any. + fn verify_seal(header: &Header) -> Result, &'static str>; +} + +/// Something which can compute and check proofs of +/// a historical key owner and return full identification data of that +/// key owner. +pub trait KeyOwnerProofSystem { + /// The proof of membership itself. + type Proof: Codec; + /// The full identification of a key owner. + type FullIdentification: Codec; + + /// Prove membership of a key owner in the current block-state. + /// + /// This should typically only be called off-chain, since it may be + /// computationally heavy. + /// + /// Returns `Some` iff the key owner referred to by the given `key` is a + /// member of the current set. + fn prove(key: Key) -> Option; + + /// Check a proof of membership on-chain. Return `Some` iff the proof is + /// valid and recent enough to check. + fn check_proof(key: Key, proof: Self::Proof) -> Option; +} + /// Handler for when some currency "account" decreased in balance for /// some reason. /// @@ -255,6 +302,34 @@ impl< } } +/// Split an unbalanced amount two ways between a common divisor. +pub struct SplitTwoWays< + Balance, + Imbalance, + Part1, + Target1, + Part2, + Target2, +>(PhantomData<(Balance, Imbalance, Part1, Target1, Part2, Target2)>); + +impl< + Balance: From + Saturating + Div, + I: Imbalance, + Part1: U32, + Target1: OnUnbalanced, + Part2: U32, + Target2: OnUnbalanced, +> OnUnbalanced for SplitTwoWays +{ + fn on_unbalanced(amount: I) { + let total: u32 = Part1::VALUE + Part2::VALUE; + let amount1 = amount.peek().saturating_mul(Part1::VALUE.into()) / total.into(); + let (imb1, imb2) = amount.split(amount1); + Target1::on_unbalanced(imb1); + Target2::on_unbalanced(imb2); + } +} + /// Abstraction over a fungible assets system. pub trait Currency { /// The balance of an account. @@ -284,6 +359,21 @@ pub trait Currency { /// `ExistentialDeposit`. fn minimum_balance() -> Self::Balance; + /// Reduce the total issuance by `amount` and return the according imbalance. The imbalance will + /// typically be used to reduce an account by the same amount with e.g. `settle`. + /// + /// This is infallible, but doesn't guarantee that the entire `amount` is burnt, for example + /// in the case of underflow. + fn burn(amount: Self::Balance) -> Self::PositiveImbalance; + + /// Increase the total issuance by `amount` and return the according imbalance. The imbalance + /// will typically be used to increase an account by the same amount with e.g. + /// `resolve_into_existing` or `resolve_creating`. + /// + /// This is infallible, but doesn't guarantee that the entire `amount` is issued, for example + /// in the case of overflow. + fn issue(amount: Self::Balance) -> Self::NegativeImbalance; + /// The 'free' balance of a given account. /// /// This is the only balance that matters in terms of most operations on tokens. It alone @@ -340,17 +430,18 @@ pub trait Currency { value: Self::Balance ) -> result::Result; - /// Removes some free balance from `who` account for `reason` if possible. If `liveness` is `KeepAlive`, - /// then no less than `ExistentialDeposit` must be left remaining. - /// - /// This checks any locks, vesting, and liquidity requirements. If the removal is not possible, then it - /// returns `Err`. - fn withdraw( + /// Similar to deposit_creating, only accepts a `NegativeImbalance` and returns nothing on + /// success. + fn resolve_into_existing( who: &AccountId, - value: Self::Balance, - reason: WithdrawReason, - liveness: ExistenceRequirement, - ) -> result::Result; + value: Self::NegativeImbalance, + ) -> result::Result<(), Self::NegativeImbalance> { + let v = value.peek(); + match Self::deposit_into_existing(who, v) { + Ok(opposite) => Ok(drop(value.offset(opposite))), + _ => Err(value), + } + } /// Adds up to `value` to the free balance of `who`. If `who` doesn't exist, it is created. /// @@ -360,6 +451,45 @@ pub trait Currency { value: Self::Balance, ) -> Self::PositiveImbalance; + /// Similar to deposit_creating, only accepts a `NegativeImbalance` and returns nothing on + /// success. + fn resolve_creating( + who: &AccountId, + value: Self::NegativeImbalance, + ) { + let v = value.peek(); + drop(value.offset(Self::deposit_creating(who, v))); + } + + /// Removes some free balance from `who` account for `reason` if possible. If `liveness` is + /// `KeepAlive`, then no less than `ExistentialDeposit` must be left remaining. + /// + /// This checks any locks, vesting, and liquidity requirements. If the removal is not possible, + /// then it returns `Err`. + /// + /// If the operation is successful, this will return `Ok` with a `NegativeImbalance` whose value + /// is `value`. + fn withdraw( + who: &AccountId, + value: Self::Balance, + reason: WithdrawReason, + liveness: ExistenceRequirement, + ) -> result::Result; + + /// Similar to withdraw, only accepts a `PositiveImbalance` and returns nothing on success. + fn settle( + who: &AccountId, + value: Self::PositiveImbalance, + reason: WithdrawReason, + liveness: ExistenceRequirement, + ) -> result::Result<(), Self::PositiveImbalance> { + let v = value.peek(); + match Self::withdraw(who, v, reason, liveness) { + Ok(opposite) => Ok(drop(value.offset(opposite))), + _ => Err(value), + } + } + /// Ensure an account's free balance equals some value; this will create the account /// if needed. /// @@ -500,3 +630,22 @@ bitmask! { } } +impl WithdrawReasons { + /// Choose all variants except for `one`. + pub fn except(one: WithdrawReason) -> WithdrawReasons { + let mut mask = Self::all(); + mask.toggle(one); + mask + } +} + +/// Trait for type that can handle incremental changes to a set of account IDs. +pub trait ChangeMembers { + /// A number of members `_incoming` just joined the set and replaced some `_outgoing` ones. The + /// new set is thus given by `_new`. + fn change_members(_incoming: &[AccountId], _outgoing: &[AccountId], _new: &[AccountId]); +} + +impl ChangeMembers for () { + fn change_members(_incoming: &[T], _outgoing: &[T], _new_set: &[T]) {} +} diff --git a/srml/support/test/Cargo.toml b/srml/support/test/Cargo.toml index 44a3b8d8841a20cdffbf6e7f62eef052574f2a47..fa4529d71e623bac39a548a9b8a1a9a890ea9b20 100644 --- a/srml/support/test/Cargo.toml +++ b/srml/support/test/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] serde = { version = "1.0", default-features = false, features = ["derive"] } -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } runtime_io = { package = "sr-io", path = "../../../core/sr-io", default-features = false } srml-support = { version = "2", path = "../", default-features = false } inherents = { package = "substrate-inherents", path = "../../../core/inherents", default-features = false } diff --git a/srml/support/test/tests/final_keys.rs b/srml/support/test/tests/final_keys.rs index 549506df496c9505719ad0e07ff5a0c7fe84c480..888ef48cb2f7d516566ce5001da877bd271bff6a 100644 --- a/srml/support/test/tests/final_keys.rs +++ b/srml/support/test/tests/final_keys.rs @@ -17,7 +17,6 @@ use runtime_io::{with_externalities, Blake2Hasher}; use srml_support::{StorageValue, StorageMap, StorageDoubleMap}; use srml_support::storage::unhashed; -use srml_support::runtime_primitives::BuildStorage; use parity_codec::{Encode, Decode}; pub trait Trait { @@ -60,37 +59,37 @@ fn new_test_ext() -> runtime_io::TestExternalities { #[test] fn final_keys() { with_externalities(&mut new_test_ext(), || { - >::put(1); + Value::put(1); assert_eq!(unhashed::get::(&runtime_io::twox_128(b"Module Value")), Some(1u32)); - >::insert(1, 2); + Map::insert(1, 2); let mut k = b"Module Map".to_vec(); k.extend(1u32.encode()); assert_eq!(unhashed::get::(&runtime_io::blake2_256(&k)), Some(2u32)); - >::insert(1, 2); + Map2::insert(1, 2); let mut k = b"Module Map2".to_vec(); k.extend(1u32.encode()); assert_eq!(unhashed::get::(&runtime_io::twox_128(&k)), Some(2u32)); - >::insert(1, 2); + LinkedMap::insert(1, 2); let mut k = b"Module LinkedMap".to_vec(); k.extend(1u32.encode()); assert_eq!(unhashed::get::(&runtime_io::blake2_256(&k)), Some(2u32)); - >::insert(1, 2); + LinkedMap2::insert(1, 2); let mut k = b"Module LinkedMap2".to_vec(); k.extend(1u32.encode()); assert_eq!(unhashed::get::(&runtime_io::twox_128(&k)), Some(2u32)); - >::insert(1, 2, 3); + DoubleMap::insert(1, 2, 3); let mut k = b"Module DoubleMap".to_vec(); k.extend(1u32.encode()); let mut k = runtime_io::blake2_256(&k).to_vec(); k.extend(&runtime_io::blake2_256(&2u32.encode())); assert_eq!(unhashed::get::(&k), Some(3u32)); - >::insert(1, 2, 3); + DoubleMap2::insert(1, 2, 3); let mut k = b"Module DoubleMap2".to_vec(); k.extend(1u32.encode()); let mut k = runtime_io::twox_128(&k).to_vec(); diff --git a/srml/support/test/tests/genesisconfig.rs b/srml/support/test/tests/genesisconfig.rs new file mode 100644 index 0000000000000000000000000000000000000000..717c7105b587bf36b39c541af93699402a1335e4 --- /dev/null +++ b/srml/support/test/tests/genesisconfig.rs @@ -0,0 +1,44 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +pub trait Trait { + type BlockNumber: parity_codec::Codec + Default; + type Origin; +} + +srml_support::decl_module! { + pub struct Module for enum Call where origin: T::Origin {} +} + +srml_support::decl_storage! { + trait Store for Module as Example { + pub AppendableDM config(t): double_map u32, blake2_256(T::BlockNumber) => Vec; + } +} + +struct Test; + +impl Trait for Test { + type BlockNumber = u32; + type Origin = (); +} + +#[test] +fn init_genesis_config() { + GenesisConfig:: { + t: Default::default(), + }; +} \ No newline at end of file diff --git a/srml/support/test/tests/instance.rs b/srml/support/test/tests/instance.rs index f7b4a4bd3a2517506ca905dd7f723eef0f1a4822..62e7263b511be6948715dff5c4e923a7bbcbd473 100644 --- a/srml/support/test/tests/instance.rs +++ b/srml/support/test/tests/instance.rs @@ -13,84 +13,22 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . - #![recursion_limit="128"] use runtime_io::{with_externalities, Blake2Hasher}; -use srml_support::rstd::prelude::*; -use srml_support::rstd as rstd; -use srml_support::runtime_primitives::{generic, BuildStorage}; -use srml_support::runtime_primitives::traits::{BlakeTwo256, Block as _, Verify}; -use srml_support::Parameter; +use srml_support::{ + Parameter, traits::Get, parameter_types, + runtime_primitives::{generic, BuildStorage, traits::{BlakeTwo256, Block as _, Verify}}, +}; use inherents::{ ProvideInherent, InherentData, InherentIdentifier, RuntimeString, MakeFatalError }; use srml_support::{StorageValue, StorageMap, StorageDoubleMap}; use primitives::{H256, sr25519}; -pub trait Currency { -} - -// Mock -mod system { - use super::*; - - pub trait Trait: 'static + Eq + Clone { - type Origin: Into, Self::Origin>> - + From>; - type BlockNumber; - type Hash; - type AccountId; - type Event: From; - } - - pub type DigestItemOf = generic::DigestItem<::Hash>; - - srml_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin { - pub fn deposit_event(_event: T::Event) { - } - } - } - impl Module { - pub fn deposit_log(_item: DigestItemOf) { - unimplemented!(); - } - } - - srml_support::decl_event!( - pub enum Event { - ExtrinsicSuccess, - ExtrinsicFailed, - } - ); - - /// Origin for the system module. - #[derive(PartialEq, Eq, Clone)] - #[cfg_attr(feature = "std", derive(Debug))] - pub enum RawOrigin { - Root, - Signed(AccountId), - None, - } - - impl From> for RawOrigin { - fn from(s: Option) -> RawOrigin { - match s { - Some(who) => RawOrigin::Signed(who), - None => RawOrigin::None, - } - } - } +mod system; - pub type Origin = RawOrigin<::AccountId>; - - pub fn ensure_root(o: OuterOrigin) -> Result<(), &'static str> - where OuterOrigin: Into, OuterOrigin>> - { - o.into().map(|_| ()).map_err(|_| "bad origin: expected to be a root origin") - } -} +pub trait Currency {} // Test for: // * No default instance @@ -99,31 +37,48 @@ mod system { mod module1 { use super::*; - pub trait Trait: system::Trait { + pub trait Trait: system::Trait where ::BlockNumber: From { type Event: From> + Into<::Event>; type Origin: From>; + type SomeParameter: Get; + type GenericType: Default + Clone + parity_codec::Codec; } srml_support::decl_module! { - pub struct Module, I: InstantiableThing> for enum Call where origin: ::Origin { + pub struct Module, I: InstantiableThing> for enum Call where + origin: ::Origin, + T::BlockNumber: From + { + fn offchain_worker() {} + fn deposit_event() = default; - fn one() { + fn one(origin) { + system::ensure_root(origin)?; Self::deposit_event(RawEvent::AnotherVariant(3)); } } } srml_support::decl_storage! { - trait Store for Module, I: InstantiableThing> as Module1 { - pub Value config(value): u64; + trait Store for Module, I: InstantiableThing> as Module1 where + T::BlockNumber: From + std::fmt::Display + { + pub Value config(value): T::GenericType; pub Map: map u32 => u64; pub LinkedMap: linked_map u32 => u64; } + + add_extra_genesis { + config(test) : T::BlockNumber; + build(|_, _, config: &Self| { + println!("{}", config.test); + }); + } } srml_support::decl_event! { - pub enum Event where Phantom = rstd::marker::PhantomData { + pub enum Event where Phantom = std::marker::PhantomData { _Phantom(Phantom), AnotherVariant(u32), } @@ -131,14 +86,16 @@ mod module1 { #[derive(PartialEq, Eq, Clone)] #[cfg_attr(feature = "std", derive(Debug))] - pub enum Origin, I> { + pub enum Origin, I> where T::BlockNumber: From { Members(u32), - _Phantom(rstd::marker::PhantomData<(T, I)>), + _Phantom(std::marker::PhantomData<(T, I)>), } pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"12345678"; - impl, I: InstantiableThing> ProvideInherent for Module { + impl, I: InstantiableThing> ProvideInherent for Module where + T::BlockNumber: From + { type Call = Call; type Error = MakeFatalError; const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; @@ -147,7 +104,7 @@ mod module1 { unimplemented!(); } - fn check_inherent(_call: &Self::Call, _data: &InherentData) -> rstd::result::Result<(), Self::Error> { + fn check_inherent(_: &Self::Call, _: &InherentData) -> std::result::Result<(), Self::Error> { unimplemented!(); } } @@ -168,7 +125,9 @@ mod module2 { impl, I: Instance> Currency for Module {} srml_support::decl_module! { - pub struct Module, I: Instance=DefaultInstance> for enum Call where origin: ::Origin { + pub struct Module, I: Instance=DefaultInstance> for enum Call where + origin: ::Origin + { fn deposit_event() = default; } } @@ -180,7 +139,6 @@ mod module2 { pub LinkedMap config(linked_map): linked_map u64 => u64; pub DoubleMap config(double_map): double_map u64, blake2_256(u64) => u64; } - extra_genesis_skip_phantom_data_field; } srml_support::decl_event! { @@ -193,7 +151,7 @@ mod module2 { #[cfg_attr(feature = "std", derive(Debug))] pub enum Origin, I=DefaultInstance> { Members(u32), - _Phantom(rstd::marker::PhantomData<(T, I)>), + _Phantom(std::marker::PhantomData<(T, I)>), } pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"12345678"; @@ -207,7 +165,7 @@ mod module2 { unimplemented!(); } - fn check_inherent(_call: &Self::Call, _data: &InherentData) -> rstd::result::Result<(), Self::Error> { + fn check_inherent(_call: &Self::Call, _data: &InherentData) -> std::result::Result<(), Self::Error> { unimplemented!(); } } @@ -224,18 +182,25 @@ mod module3 { } srml_support::decl_module! { - pub struct Module for enum Call where origin: ::Origin { - } + pub struct Module for enum Call where origin: ::Origin {} } } +parameter_types! { + pub const SomeValue: u32 = 100; +} + impl module1::Trait for Runtime { type Event = Event; type Origin = Origin; + type SomeParameter = SomeValue; + type GenericType = u32; } impl module1::Trait for Runtime { type Event = Event; type Origin = Origin; + type SomeParameter = SomeValue; + type GenericType = u32; } impl module2::Trait for Runtime { type Amount = u16; @@ -282,12 +247,22 @@ srml_support::construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic { System: system::{Module, Call, Event}, - Module1_1: module1::::{Module, Call, Storage, Event, Config, Origin, Inherent}, - Module1_2: module1::::{Module, Call, Storage, Event, Config, Origin, Inherent}, + Module1_1: module1::::{ + Module, Call, Storage, Event, Config, Origin, Inherent + }, + Module1_2: module1::::{ + Module, Call, Storage, Event, Config, Origin, Inherent + }, Module2: module2::{Module, Call, Storage, Event, Config, Origin, Inherent}, - Module2_1: module2::::{Module, Call, Storage, Event, Config, Origin, Inherent}, - Module2_2: module2::::{Module, Call, Storage, Event, Config, Origin, Inherent}, - Module2_3: module2::::{Module, Call, Storage, Event, Config, Origin, Inherent}, + Module2_1: module2::::{ + Module, Call, Storage, Event, Config, Origin, Inherent + }, + Module2_2: module2::::{ + Module, Call, Storage, Event, Config, Origin, Inherent + }, + Module2_3: module2::::{ + Module, Call, Storage, Event, Config, Origin, Inherent + }, Module3: module3::{Module, Call}, } ); @@ -300,11 +275,11 @@ fn new_test_ext() -> runtime_io::TestExternalities { GenesisConfig{ module1_Instance1: Some(module1::GenesisConfig { value: 3, - .. Default::default() + test: 2, }), module1_Instance2: Some(module1::GenesisConfig { value: 4, - _genesis_phantom_data: Default::default(), + test: 5, }), module2: Some(module2::GenesisConfig { value: 4, @@ -326,48 +301,48 @@ fn new_test_ext() -> runtime_io::TestExternalities { #[test] fn storage_instance_independance() { with_externalities(&mut new_test_ext(), || { - let mut map = rstd::collections::btree_map::BTreeMap::new(); + let mut map = std::collections::btree_map::BTreeMap::new(); for key in [ module2::Value::::key().to_vec(), module2::Value::::key().to_vec(), module2::Value::::key().to_vec(), module2::Value::::key().to_vec(), - module2::Map::::prefix().to_vec(), - module2::Map::::prefix().to_vec(), - module2::Map::::prefix().to_vec(), - module2::Map::::prefix().to_vec(), - module2::LinkedMap::::prefix().to_vec(), - module2::LinkedMap::::prefix().to_vec(), - module2::LinkedMap::::prefix().to_vec(), - module2::LinkedMap::::prefix().to_vec(), - module2::DoubleMap::::prefix().to_vec(), - module2::DoubleMap::::prefix().to_vec(), - module2::DoubleMap::::prefix().to_vec(), - module2::DoubleMap::::prefix().to_vec(), - module2::Map::::key_for(0), - module2::Map::::key_for(0).to_vec(), - module2::Map::::key_for(0).to_vec(), - module2::Map::::key_for(0).to_vec(), - module2::LinkedMap::::key_for(0), - module2::LinkedMap::::key_for(0).to_vec(), - module2::LinkedMap::::key_for(0).to_vec(), - module2::LinkedMap::::key_for(0).to_vec(), - module2::Map::::key_for(1), - module2::Map::::key_for(1).to_vec(), - module2::Map::::key_for(1).to_vec(), - module2::Map::::key_for(1).to_vec(), - module2::LinkedMap::::key_for(1), - module2::LinkedMap::::key_for(1).to_vec(), - module2::LinkedMap::::key_for(1).to_vec(), - module2::LinkedMap::::key_for(1).to_vec(), - module2::DoubleMap::::prefix_for(1), - module2::DoubleMap::::prefix_for(1).to_vec(), - module2::DoubleMap::::prefix_for(1).to_vec(), - module2::DoubleMap::::prefix_for(1).to_vec(), - module2::DoubleMap::::key_for(1, 1), - module2::DoubleMap::::key_for(1, 1).to_vec(), - module2::DoubleMap::::key_for(1, 1).to_vec(), - module2::DoubleMap::::key_for(1, 1).to_vec(), + module2::Map::::prefix().to_vec(), + module2::Map::::prefix().to_vec(), + module2::Map::::prefix().to_vec(), + module2::Map::::prefix().to_vec(), + module2::LinkedMap::::prefix().to_vec(), + module2::LinkedMap::::prefix().to_vec(), + module2::LinkedMap::::prefix().to_vec(), + module2::LinkedMap::::prefix().to_vec(), + module2::DoubleMap::::prefix().to_vec(), + module2::DoubleMap::::prefix().to_vec(), + module2::DoubleMap::::prefix().to_vec(), + module2::DoubleMap::::prefix().to_vec(), + module2::Map::::key_for(0), + module2::Map::::key_for(0).to_vec(), + module2::Map::::key_for(0).to_vec(), + module2::Map::::key_for(0).to_vec(), + module2::LinkedMap::::key_for(0), + module2::LinkedMap::::key_for(0).to_vec(), + module2::LinkedMap::::key_for(0).to_vec(), + module2::LinkedMap::::key_for(0).to_vec(), + module2::Map::::key_for(1), + module2::Map::::key_for(1).to_vec(), + module2::Map::::key_for(1).to_vec(), + module2::Map::::key_for(1).to_vec(), + module2::LinkedMap::::key_for(1), + module2::LinkedMap::::key_for(1).to_vec(), + module2::LinkedMap::::key_for(1).to_vec(), + module2::LinkedMap::::key_for(1).to_vec(), + module2::DoubleMap::::prefix_for(1), + module2::DoubleMap::::prefix_for(1).to_vec(), + module2::DoubleMap::::prefix_for(1).to_vec(), + module2::DoubleMap::::prefix_for(1).to_vec(), + module2::DoubleMap::::key_for(1, 1), + module2::DoubleMap::::key_for(1, 1).to_vec(), + module2::DoubleMap::::key_for(1, 1).to_vec(), + module2::DoubleMap::::key_for(1, 1).to_vec(), ].iter() { assert!(map.insert(key, ()).is_none()) } @@ -378,9 +353,9 @@ fn storage_instance_independance() { fn storage_with_instance_basic_operation() { with_externalities(&mut new_test_ext(), || { type Value = module2::Value; - type Map = module2::Map; - type LinkedMap = module2::LinkedMap; - type DoubleMap = module2::DoubleMap; + type Map = module2::Map; + type LinkedMap = module2::LinkedMap; + type DoubleMap = module2::DoubleMap; assert_eq!(Value::exists(), true); assert_eq!(Value::get(), 4); @@ -432,4 +407,4 @@ fn storage_with_instance_basic_operation() { DoubleMap::remove(key1, key2); assert_eq!(DoubleMap::get(key1, key2), 0); }); -} +} \ No newline at end of file diff --git a/srml/support/test/tests/issue2219.rs b/srml/support/test/tests/issue2219.rs new file mode 100644 index 0000000000000000000000000000000000000000..185b5e24807a9fa936ed720a0aaa0beefe1d80c8 --- /dev/null +++ b/srml/support/test/tests/issue2219.rs @@ -0,0 +1,186 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +use srml_support::runtime_primitives::generic; +use srml_support::runtime_primitives::traits::{BlakeTwo256, Block as _, Verify}; +use srml_support::codec::{Encode, Decode}; +use primitives::{H256, sr25519}; +use serde::{Serialize, Deserialize}; + +mod system; + +mod module { + use super::*; + + pub type Request = ( + ::AccountId, + Role, + ::BlockNumber, + ); + pub type Requests = Vec>; + + #[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Debug)] + pub enum Role { + Storage, + } + + #[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Debug)] + pub struct RoleParameters { + // minimum actors to maintain - if role is unstaking + // and remaining actors would be less that this value - prevent or punish for unstaking + pub min_actors: u32, + + // the maximum number of spots available to fill for a role + pub max_actors: u32, + + // payouts are made at this block interval + pub reward_period: T::BlockNumber, + + // minimum amount of time before being able to unstake + pub bonding_period: T::BlockNumber, + + // how long tokens remain locked for after unstaking + pub unbonding_period: T::BlockNumber, + + // minimum period required to be in service. unbonding before this time is highly penalized + pub min_service_period: T::BlockNumber, + + // "startup" time allowed for roles that need to sync their infrastructure + // with other providers before they are considered in service and punishable for + // not delivering required level of service. + pub startup_grace_period: T::BlockNumber, + } + + impl Default for RoleParameters { + fn default() -> Self { + Self { + max_actors: 10, + reward_period: T::BlockNumber::default(), + unbonding_period: T::BlockNumber::default(), + + // not currently used + min_actors: 5, + bonding_period: T::BlockNumber::default(), + min_service_period: T::BlockNumber::default(), + startup_grace_period: T::BlockNumber::default(), + } + } + } + + pub trait Trait: system::Trait {} + + srml_support::decl_module! { + pub struct Module for enum Call where origin: T::Origin {} + } + + #[derive(Encode, Decode, Copy, Clone, Serialize, Deserialize)] + pub struct Data { + pub data: T::BlockNumber, + } + + impl Default for Data { + fn default() -> Self { + Self { + data: T::BlockNumber::default(), + } + } + } + + srml_support::decl_storage! { + trait Store for Module as Actors { + /// requirements to enter and maintain status in roles + pub Parameters get(parameters) build(|config: &GenesisConfig| { + if config.enable_storage_role { + let storage_params: RoleParameters = Default::default(); + vec![(Role::Storage, storage_params)] + } else { + vec![] + } + }): map Role => Option>; + + /// the roles members can enter into + pub AvailableRoles get(available_roles) build(|config: &GenesisConfig| { + if config.enable_storage_role { + vec![(Role::Storage)] + } else { + vec![] + } + }): Vec; + + /// Actors list + pub ActorAccountIds get(actor_account_ids) : Vec; + + /// actor accounts associated with a role + pub AccountIdsByRole get(account_ids_by_role) : map Role => Vec; + + /// tokens locked until given block number + pub Bondage get(bondage) : map T::AccountId => T::BlockNumber; + + /// First step before enter a role is registering intent with a new account/key. + /// This is done by sending a role_entry_request() from the new account. + /// The member must then send a stake() transaction to approve the request and enter the desired role. + /// The account making the request will be bonded and must have + /// sufficient balance to cover the minimum stake for the role. + /// Bonding only occurs after successful entry into a role. + pub RoleEntryRequests get(role_entry_requests) : Requests; + + /// Entry request expires after this number of blocks + pub RequestLifeTime get(request_life_time) config(request_life_time) : u64 = 0; + } + add_extra_genesis { + config(enable_storage_role): bool; + } + } +} + +pub type Signature = sr25519::Signature; +pub type AccountId = ::Signer; +pub type BlockNumber = u64; +pub type Index = u64; +pub type Header = generic::Header; +pub type Block = generic::Block; +pub type UncheckedExtrinsic = generic::UncheckedMortalCompactExtrinsic; + +impl system::Trait for Runtime { + type Hash = H256; + type Origin = Origin; + type BlockNumber = BlockNumber; + type AccountId = AccountId; + type Event = Event; +} + +impl module::Trait for Runtime {} + +srml_support::construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: system::{Module, Call, Event}, + Module: module::{Module, Call, Storage, Config}, + } +); + +#[test] +fn create_genesis_config() { + GenesisConfig { + module: Some(module::GenesisConfig { + request_life_time: 0, + enable_storage_role: true, + }) + }; +} \ No newline at end of file diff --git a/srml/support/test/tests/reserved_keyword/on_initialize.rs b/srml/support/test/tests/reserved_keyword/on_initialize.rs index c63153241ce8f3ce052d9e355e36aa3d5f860818..f9c2f5f7f0e5add4bdf3358e3330fec4123321eb 100644 --- a/srml/support/test/tests/reserved_keyword/on_initialize.rs +++ b/srml/support/test/tests/reserved_keyword/on_initialize.rs @@ -19,7 +19,7 @@ macro_rules! reserved { srml_support::decl_module! { pub struct Module for enum Call where origin: T::Origin { - fn $reserved() -> Result { unreachable!() } + fn $reserved(_origin) -> Result { unreachable!() } } } } diff --git a/srml/support/test/tests/system.rs b/srml/support/test/tests/system.rs new file mode 100644 index 0000000000000000000000000000000000000000..6483161211afcc3ab232c8d1fcfa2e71dce6e215 --- /dev/null +++ b/srml/support/test/tests/system.rs @@ -0,0 +1,52 @@ +use srml_support::codec::{Encode, Decode}; + +pub trait Trait: 'static + Eq + Clone { + type Origin: Into, Self::Origin>> + + From>; + + type BlockNumber: Decode + Encode + Clone + Default; + type Hash; + type AccountId: Encode + Decode; + type Event: From; +} + +srml_support::decl_module! { + pub struct Module for enum Call where origin: T::Origin { + pub fn deposit_event(_event: T::Event) { + } + } +} + +srml_support::decl_event!( + pub enum Event { + ExtrinsicSuccess, + ExtrinsicFailed, + } +); + +/// Origin for the system module. +#[derive(PartialEq, Eq, Clone)] +#[cfg_attr(feature = "std", derive(Debug))] +pub enum RawOrigin { + Root, + Signed(AccountId), + None, +} + +impl From> for RawOrigin { + fn from(s: Option) -> RawOrigin { + match s { + Some(who) => RawOrigin::Signed(who), + None => RawOrigin::None, + } + } +} + +pub type Origin = RawOrigin<::AccountId>; + +#[allow(dead_code)] +pub fn ensure_root(o: OuterOrigin) -> Result<(), &'static str> + where OuterOrigin: Into, OuterOrigin>> +{ + o.into().map(|_| ()).map_err(|_| "bad origin: expected to be a root origin") +} \ No newline at end of file diff --git a/srml/system/Cargo.toml b/srml/system/Cargo.toml index 5295d0708c429423ae926d370d210613a182c630..d6039499e15fbd470a2c14e310c84502f3d8fd34 100644 --- a/srml/system/Cargo.toml +++ b/srml/system/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] serde = { version = "1.0", optional = true, features = ["derive"] } safe-mix = { version = "1.0", default-features = false} -parity-codec = { version = "3.5", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } substrate-primitives = { path = "../../core/primitives", default-features = false } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } runtime_io = { package = "sr-io", path = "../../core/sr-io", default-features = false } diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index 73f8c942091e3203c7dc831c639225d83c6a8ce4..a55cb9be86ea435022f0598088a0883a6d570435 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -79,17 +79,15 @@ use rstd::map; use primitives::{generic, traits::{self, CheckEqual, SimpleArithmetic, SimpleBitOps, Hash, Member, MaybeDisplay, EnsureOrigin, CurrentHeight, BlockNumberToHash, MaybeSerializeDebugButNotDeserialize, MaybeSerializeDebug, StaticLookup, One, Bounded, Lookup, + Zero, }}; -#[cfg(any(feature = "std", test))] -use primitives::traits::Zero; use substrate_primitives::storage::well_known_keys; use srml_support::{ storage, decl_module, decl_event, decl_storage, StorageDoubleMap, StorageValue, - StorageMap, Parameter, for_each_tuple, traits::Contains + StorageMap, Parameter, for_each_tuple, traits::{Contains, Get}, }; use safe_mix::TripletMix; use parity_codec::{Encode, Decode}; -use crate::{self as system}; #[cfg(any(feature = "std", test))] use runtime_io::{twox_128, TestExternalities, Blake2Hasher}; @@ -184,6 +182,9 @@ pub trait Trait: 'static + Eq + Clone { /// The aggregated event type of the runtime. type Event: Parameter + Member + From; + + /// Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount: Get; } pub type DigestOf = generic::Digest<::Hash>; @@ -205,24 +206,28 @@ decl_module! { } /// Set the number of pages in the WebAssembly environment's heap. - fn set_heap_pages(pages: u64) { + fn set_heap_pages(origin, pages: u64) { + ensure_root(origin)?; storage::unhashed::put_raw(well_known_keys::HEAP_PAGES, &pages.encode()); } /// Set the new code. - pub fn set_code(new: Vec) { + pub fn set_code(origin, new: Vec) { + ensure_root(origin)?; storage::unhashed::put_raw(well_known_keys::CODE, &new); } /// Set some items of storage. - fn set_storage(items: Vec) { + fn set_storage(origin, items: Vec) { + ensure_root(origin)?; for i in &items { storage::unhashed::put_raw(&i.0, &i.1); } } /// Kill some items from storage. - fn kill_storage(keys: Vec) { + fn kill_storage(origin, keys: Vec) { + ensure_root(origin)?; for key in &keys { storage::unhashed::kill(&key); } @@ -357,7 +362,7 @@ decl_storage! { #[serde(with = "substrate_primitives::bytes")] config(code): Vec; - build(|storage: &mut primitives::StorageOverlay, _: &mut primitives::ChildrenStorageOverlay, config: &GenesisConfig| { + build(|storage: &mut primitives::StorageOverlay, _: &mut primitives::ChildrenStorageOverlay, config: &GenesisConfig| { use parity_codec::Encode; storage.insert(well_known_keys::CODE.to_vec(), config.code.clone()); @@ -485,14 +490,14 @@ impl Module { // Index of the to be added event. let event_idx = { - let old_event_count = >::get(); + let old_event_count = EventCount::get(); let new_event_count = match old_event_count.checked_add(1) { // We've reached the maximum number of events at this block, just // don't do anything and leave the event_count unaltered. None => return, Some(nc) => nc, }; - >::put(new_event_count); + EventCount::put(new_event_count); old_event_count }; @@ -524,12 +529,12 @@ impl Module { /// Gets extrinsics count. pub fn extrinsic_count() -> u32 { - >::get().unwrap_or_default() + ExtrinsicCount::get().unwrap_or_default() } /// Gets a total weight of all executed extrinsics. pub fn all_extrinsics_weight() -> u32 { - >::get().unwrap_or_default() + AllExtrinsicsWeight::get().unwrap_or_default() } /// Start the execution of a particular block. @@ -553,19 +558,31 @@ impl Module { *index = (*index + 1) % 81; }); >::kill(); - >::kill(); + EventCount::kill(); >::remove_prefix(&()); } /// Remove temporary "environment" entries in storage. pub fn finalize() -> T::Header { - >::kill(); - >::kill(); + ExtrinsicCount::kill(); + AllExtrinsicsWeight::kill(); let number = >::take(); let parent_hash = >::take(); let mut digest = >::take(); let extrinsics_root = >::take(); + + // move block hash pruning window by one block + let block_hash_count = ::get(); + if number > block_hash_count { + let to_remove = number - block_hash_count - One::one(); + + // keep genesis hash + if to_remove != Zero::zero() { + >::remove(to_remove); + } + } + let storage_root = T::Hashing::storage_root(); let storage_changes_root = T::Hashing::storage_changes_root(parent_hash); @@ -699,7 +716,7 @@ impl Module { /// NOTE: This function is called only when the block is being constructed locally. /// `execute_block` doesn't note any extrinsics. pub fn note_extrinsic(encoded_xt: Vec) { - >::insert(Self::extrinsic_index().unwrap_or_default(), encoded_xt); + ExtrinsicData::insert(Self::extrinsic_index().unwrap_or_default(), encoded_xt); } /// To be called immediately after an extrinsic has been applied. @@ -713,19 +730,19 @@ impl Module { let total_length = encoded_len.saturating_add(Self::all_extrinsics_weight()); storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &next_extrinsic_index); - >::put(&total_length); + AllExtrinsicsWeight::put(&total_length); } /// To be called immediately after `note_applied_extrinsic` of the last extrinsic of the block /// has been called. pub fn note_finished_extrinsics() { let extrinsic_index: u32 = storage::unhashed::take(well_known_keys::EXTRINSIC_INDEX).unwrap_or_default(); - >::put(extrinsic_index); + ExtrinsicCount::put(extrinsic_index); } /// Remove all extrinsic data and save the extrinsics trie root. pub fn derive_extrinsics() { - let extrinsics = (0..>::get().unwrap_or_default()).map(>::take).collect(); + let extrinsics = (0..ExtrinsicCount::get().unwrap_or_default()).map(ExtrinsicData::take).collect(); let xts_root = extrinsics_data_root::(extrinsics); >::put(xts_root); } @@ -766,10 +783,8 @@ mod tests { use super::*; use runtime_io::with_externalities; use substrate_primitives::H256; - use primitives::BuildStorage; - use primitives::traits::{BlakeTwo256, IdentityLookup}; - use primitives::testing::Header; - use srml_support::impl_outer_origin; + use primitives::{traits::{BlakeTwo256, IdentityLookup}, testing::Header}; + use srml_support::{impl_outer_origin, parameter_types}; impl_outer_origin!{ pub enum Origin for Test where system = super {} @@ -777,6 +792,11 @@ mod tests { #[derive(Clone, Eq, PartialEq)] pub struct Test; + + parameter_types! { + pub const BlockHashCount: u64 = 10; + } + impl Trait for Test { type Origin = Origin; type Index = u64; @@ -787,6 +807,7 @@ mod tests { type Lookup = IdentityLookup; type Header = Header; type Event = u16; + type BlockHashCount = BlockHashCount; } impl From for u16 { @@ -801,7 +822,7 @@ mod tests { type System = Module; fn new_test_ext() -> runtime_io::TestExternalities { - GenesisConfig::::default().build_storage().unwrap().0.into() + GenesisConfig::default().build_storage::().unwrap().0.into() } #[test] @@ -904,4 +925,37 @@ mod tests { ); }); } + + #[test] + fn prunes_block_hash_mappings() { + with_externalities(&mut new_test_ext(), || { + // simulate import of 15 blocks + for n in 1..=15 { + System::initialize( + &n, + &[n as u8 - 1; 32].into(), + &[0u8; 32].into(), + &Default::default(), + ); + + System::finalize(); + } + + // first 5 block hashes are pruned + for n in 0..5 { + assert_eq!( + System::block_hash(n), + H256::zero(), + ); + } + + // the remaining 10 are kept + for n in 5..15 { + assert_eq!( + System::block_hash(n), + [n as u8; 32].into(), + ); + } + }) + } } diff --git a/srml/timestamp/Cargo.toml b/srml/timestamp/Cargo.toml index 607a6d60d2860d70927394427bad523965dd144f..bb82d1a42b8ebac9af43d71c9ceb4e669afcd96e 100644 --- a/srml/timestamp/Cargo.toml +++ b/srml/timestamp/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] serde = { version = "1.0", optional = true } -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } runtime_primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } inherents = { package = "substrate-inherents", path = "../../core/inherents", default-features = false } diff --git a/srml/timestamp/src/lib.rs b/srml/timestamp/src/lib.rs index e9c0d85a20a0522205aa381916acfe899ea59080..48a0d04c32198275f2fa03f8d43e580344609be9 100644 --- a/srml/timestamp/src/lib.rs +++ b/srml/timestamp/src/lib.rs @@ -44,7 +44,10 @@ //! //! * `get` - Gets the current time for the current block. If this function is called prior to //! setting the timestamp, it will return the timestamp of the previous block. -//! * `minimum_period` - Gets the minimum (and advised) period between blocks for the chain. +//! +//! ### Trait Getters +//! +//! * `MinimumPeriod` - Gets the minimum (and advised) period between blocks for the chain. //! //! ## Usage //! @@ -93,8 +96,7 @@ use parity_codec::Encode; use parity_codec::Decode; #[cfg(feature = "std")] use inherents::ProvideInherentData; -use srml_support::{StorageValue, Parameter, decl_storage, decl_module}; -use srml_support::for_each_tuple; +use srml_support::{StorageValue, Parameter, decl_storage, decl_module, for_each_tuple, traits::Get}; use runtime_primitives::traits::{SimpleArithmetic, Zero, SaturatedConversion}; use system::ensure_none; use inherents::{RuntimeString, InherentIdentifier, ProvideInherent, IsFatalError, InherentData}; @@ -208,23 +210,36 @@ pub trait Trait: system::Trait { /// Something which can be notified when the timestamp is set. Set this to `()` if not needed. type OnTimestampSet: OnTimestampSet; + + /// The minimum period between blocks. Beware that this is different to the *expected* period + /// that the block production apparatus provides. Your chosen consensus system will generally + /// work with this to determine a sensible block time. e.g. For Aura, it will be double this + /// period on default settings. + type MinimumPeriod: Get; } decl_module! { pub struct Module for enum Call where origin: T::Origin { + /// The minimum period between blocks. Beware that this is different to the *expected* period + /// that the block production apparatus provides. Your chosen consensus system will generally + /// work with this to determine a sensible block time. e.g. For Aura, it will be double this + /// period on default settings. + const MinimumPeriod: T::Moment = T::MinimumPeriod::get(); + /// Set the current time. /// - /// This call should be invoked exactly once per block. It will panic at the finalization phase, - /// if this call hasn't been invoked by that time. + /// This call should be invoked exactly once per block. It will panic at the finalization + /// phase, if this call hasn't been invoked by that time. /// - /// The timestamp should be greater than the previous one by the amount specified by `minimum_period`. + /// The timestamp should be greater than the previous one by the amount specified by + /// `MinimumPeriod`. /// /// The dispatch origin for this call must be `Inherent`. fn set(origin, #[compact] now: T::Moment) { ensure_none(origin)?; assert!(!::DidUpdate::exists(), "Timestamp must be updated only once in the block"); assert!( - Self::now().is_zero() || now >= Self::now() + >::get(), + Self::now().is_zero() || now >= Self::now() + T::MinimumPeriod::get(), "Timestamp must increment by at least between sequential blocks" ); ::Now::put(now.clone()); @@ -233,16 +248,6 @@ decl_module! { >::on_timestamp_set(now); } - // Manage upgrade. Remove after all networks upgraded. - // TODO: #2133 - fn on_initialize() { - if let Some(period) = >::take() { - if !>::exists() { - >::put(period) - } - } - } - fn on_finalize() { assert!(::DidUpdate::take(), "Timestamp must be updated once in the block"); } @@ -254,16 +259,6 @@ decl_storage! { /// Current time for the current block. pub Now get(now) build(|_| 0.into()): T::Moment; - /// Old storage item provided for compatibility. Remove after all networks upgraded. - // TODO: #2133 - pub BlockPeriod: Option; - - /// The minimum period between blocks. Beware that this is different to the *expected* period - /// that the block production apparatus provides. Your chosen consensus system will generally - /// work with this to determine a sensible block time. e.g. For Aura, it will be double this - /// period on default settings. - pub MinimumPeriod get(minimum_period) config(): T::Moment = 3.into(); - /// Did the timestamp get updated in this block? DidUpdate: bool; } @@ -301,7 +296,7 @@ impl ProvideInherent for Module { .expect("Gets and decodes timestamp inherent data") .saturated_into(); - let next_time = cmp::max(data, Self::now() + >::get()); + let next_time = cmp::max(data, Self::now() + T::MinimumPeriod::get()); Some(Call::set(next_time.into())) } @@ -315,7 +310,7 @@ impl ProvideInherent for Module { let data = extract_inherent_data(data).map_err(|e| InherentError::Other(e))?; - let minimum = (Self::now() + >::get()).saturated_into::(); + let minimum = (Self::now() + T::MinimumPeriod::get()).saturated_into::(); if t > data + MAX_TIMESTAMP_DRIFT { Err(InherentError::Other("Timestamp too far in future to accept".into())) } else if t < minimum { @@ -330,12 +325,10 @@ impl ProvideInherent for Module { mod tests { use super::*; - use srml_support::{impl_outer_origin, assert_ok}; + use srml_support::{impl_outer_origin, assert_ok, parameter_types}; use runtime_io::{with_externalities, TestExternalities}; use substrate_primitives::H256; - use runtime_primitives::BuildStorage; - use runtime_primitives::traits::{BlakeTwo256, IdentityLookup}; - use runtime_primitives::testing::Header; + use runtime_primitives::{traits::{BlakeTwo256, IdentityLookup}, testing::Header}; impl_outer_origin! { pub enum Origin for Test {} @@ -343,6 +336,9 @@ mod tests { #[derive(Clone, Eq, PartialEq)] pub struct Test; + parameter_types! { + pub const BlockHashCount: u64 = 250; + } impl system::Trait for Test { type Origin = Origin; type Index = u64; @@ -353,21 +349,22 @@ mod tests { type Lookup = IdentityLookup; type Header = Header; type Event = (); + type BlockHashCount = BlockHashCount; + } + parameter_types! { + pub const MinimumPeriod: u64 = 5; } impl Trait for Test { type Moment = u64; type OnTimestampSet = (); + type MinimumPeriod = MinimumPeriod; } type Timestamp = Module; #[test] fn timestamp_works() { - let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; - t.extend(GenesisConfig:: { - minimum_period: 5, - }.build_storage().unwrap().0); - - with_externalities(&mut TestExternalities::new(t), || { + let t = system::GenesisConfig::default().build_storage::().unwrap(); + with_externalities(&mut TestExternalities::new_with_children(t), || { Timestamp::set_timestamp(42); assert_ok!(Timestamp::dispatch(Call::set(69), Origin::NONE)); assert_eq!(Timestamp::now(), 69); @@ -377,12 +374,8 @@ mod tests { #[test] #[should_panic(expected = "Timestamp must be updated only once in the block")] fn double_timestamp_should_fail() { - let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; - t.extend(GenesisConfig:: { - minimum_period: 5, - }.build_storage().unwrap().0); - - with_externalities(&mut TestExternalities::new(t), || { + let t = system::GenesisConfig::default().build_storage::().unwrap(); + with_externalities(&mut TestExternalities::new_with_children(t), || { Timestamp::set_timestamp(42); assert_ok!(Timestamp::dispatch(Call::set(69), Origin::NONE)); let _ = Timestamp::dispatch(Call::set(70), Origin::NONE); @@ -392,12 +385,8 @@ mod tests { #[test] #[should_panic(expected = "Timestamp must increment by at least between sequential blocks")] fn block_period_minimum_enforced() { - let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; - t.extend(GenesisConfig:: { - minimum_period: 5, - }.build_storage().unwrap().0); - - with_externalities(&mut TestExternalities::new(t), || { + let t = system::GenesisConfig::default().build_storage::().unwrap(); + with_externalities(&mut TestExternalities::new_with_children(t), || { Timestamp::set_timestamp(42); let _ = Timestamp::dispatch(Call::set(46), Origin::NONE); }); diff --git a/srml/treasury/Cargo.toml b/srml/treasury/Cargo.toml index 68b0451caf857e04105936d34264582d2bdcf226..64190f9c4fb8123560db3b0f4c138b91fab37a17 100644 --- a/srml/treasury/Cargo.toml +++ b/srml/treasury/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] serde = { version = "1.0", optional = true, features = ["derive"] } -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } runtime_primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } srml-support = { path = "../support", default-features = false } diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index 95fa90f88ff5f543daf03d8145b98a19f315249d..7c4d7b10f21cf4602f0e53057d0c53a69c7ecc61 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -70,10 +70,14 @@ #[cfg(feature = "std")] use serde::{Serialize, Deserialize}; use rstd::prelude::*; -use srml_support::{StorageValue, StorageMap, decl_module, decl_storage, decl_event, ensure}; -use srml_support::traits::{Currency, ReservableCurrency, OnDilution, OnUnbalanced, Imbalance}; -use runtime_primitives::{Permill, - traits::{Zero, EnsureOrigin, StaticLookup, Saturating, CheckedSub, CheckedMul} +use srml_support::{StorageValue, StorageMap, decl_module, decl_storage, decl_event, ensure, print}; +use srml_support::traits::{ + Currency, ExistenceRequirement, Get, Imbalance, OnDilution, OnUnbalanced, + ReservableCurrency, WithdrawReason +}; +use runtime_primitives::{Permill, ModuleId}; +use runtime_primitives::traits::{ + Zero, EnsureOrigin, StaticLookup, CheckedSub, CheckedMul, AccountIdConversion }; use parity_codec::{Encode, Decode}; use system::ensure_signed; @@ -82,6 +86,13 @@ type BalanceOf = <::Currency as Currency<::Ac type PositiveImbalanceOf = <::Currency as Currency<::AccountId>>::PositiveImbalance; type NegativeImbalanceOf = <::Currency as Currency<::AccountId>>::NegativeImbalance; +const MODULE_ID: ModuleId = ModuleId(*b"py/trsry"); + +pub const DEFAULT_PROPOSAL_BOND: u32 = 0; +pub const DEFAULT_PROPOSAL_BOND_MINIMUM: u32 = 0; +pub const DEFAULT_SPEND_PERIOD: u32 = 0; +pub const DEFAULT_BURN: u32 = 0; + pub trait Trait: system::Trait { /// The staking balance. type Currency: Currency + ReservableCurrency; @@ -100,12 +111,38 @@ pub trait Trait: system::Trait { /// Handler for the unbalanced decrease when slashing for a rejected proposal. type ProposalRejection: OnUnbalanced>; + + /// Fraction of a proposal's value that should be bonded in order to place the proposal. + /// An accepted proposal gets these back. A rejected proposal does not. + type ProposalBond: Get; + + /// Minimum amount of funds that should be placed in a deposit for making a proposal. + type ProposalBondMinimum: Get>; + + /// Period between successive spends. + type SpendPeriod: Get; + + /// Percentage of spare funds (if any) that are burnt per spend period. + type Burn: Get; } type ProposalIndex = u32; decl_module! { pub struct Module for enum Call where origin: T::Origin { + /// Fraction of a proposal's value that should be bonded in order to place the proposal. + /// An accepted proposal gets these back. A rejected proposal does not. + const ProposalBond: Permill = T::ProposalBond::get(); + + /// Minimum amount of funds that should be placed in a deposit for making a proposal. + const ProposalBondMinimum: BalanceOf = T::ProposalBondMinimum::get(); + + /// Period between successive spends. + const SpendPeriod: T::BlockNumber = T::SpendPeriod::get(); + + /// Percentage of spare funds (if any) that are burnt per spend period. + const Burn: Permill = T::Burn::get(); + fn deposit_event() = default; /// Put forward a suggestion for spending. A deposit proportional to the value /// is reserved and slashed if the proposal is rejected. It is returned once the @@ -129,31 +166,12 @@ decl_module! { .map_err(|_| "Proposer's balance too low")?; let c = Self::proposal_count(); - >::put(c + 1); + ProposalCount::put(c + 1); >::insert(c, Proposal { proposer, value, beneficiary, bond }); Self::deposit_event(RawEvent::Proposed(c)); } - /// Set the balance of funds available to spend. - fn set_pot(#[compact] new_pot: BalanceOf) { - // Put the new value into storage. - >::put(new_pot); - } - - /// (Re-)configure this module. - fn configure( - #[compact] proposal_bond: Permill, - #[compact] proposal_bond_minimum: BalanceOf, - #[compact] spend_period: T::BlockNumber, - #[compact] burn: Permill - ) { - >::put(proposal_bond); - >::put(proposal_bond_minimum); - >::put(spend_period); - >::put(burn); - } - /// Reject a proposed spend. The original deposit will be slashed. /// /// # @@ -183,12 +201,12 @@ decl_module! { ensure!(>::exists(proposal_id), "No proposal at that index"); - >::mutate(|v| v.push(proposal_id)); + Approvals::mutate(|v| v.push(proposal_id)); } fn on_finalize(n: T::BlockNumber) { // Check to see if we should spend some funds! - if (n % Self::spend_period()).is_zero() { + if (n % T::SpendPeriod::get()).is_zero() { Self::spend_funds(); } } @@ -207,26 +225,6 @@ pub struct Proposal { decl_storage! { trait Store for Module as Treasury { - // Config... - - /// Fraction of a proposal's value that should be bonded in order to place the proposal. - /// An accepted proposal gets these back. A rejected proposal does not. - ProposalBond get(proposal_bond) config(): Permill; - - /// Minimum amount of funds that should be placed in a deposit for making a proposal. - ProposalBondMinimum get(proposal_bond_minimum) config(): BalanceOf; - - /// Period between successive spends. - SpendPeriod get(spend_period) config(): T::BlockNumber = runtime_primitives::traits::One::one(); - - /// Percentage of spare funds (if any) that are burnt per spend period. - Burn get(burn) config(): Permill; - - // State... - - /// Total funds available to this module for spending. - Pot get(pot): BalanceOf; - /// Number of proposals that have been made. ProposalCount get(proposal_count): ProposalIndex; @@ -260,9 +258,17 @@ decl_event!( impl Module { // Add public immutables and private mutables. + /// The account ID of the treasury pot. + /// + /// This actually does computation. If you need to keep using it, then make sure you cache the + /// value and only call this once. + pub fn account_id() -> T::AccountId { + MODULE_ID.into_account() + } + /// The needed bond for a proposal whose spend is `value`. fn calculate_bond(value: BalanceOf) -> BalanceOf { - Self::proposal_bond_minimum().max(Self::proposal_bond() * value) + T::ProposalBondMinimum::get().max(T::ProposalBond::get() * value) } // Spend some money! @@ -272,7 +278,7 @@ impl Module { let mut missed_any = false; let mut imbalance = >::zero(); - >::mutate(|v| { + Approvals::mutate(|v| { v.retain(|&index| { // Should always be true, but shouldn't panic if false or we're screwed. if let Some(p) = Self::proposals(index) { @@ -298,18 +304,36 @@ impl Module { }); }); - T::MintedForSpending::on_unbalanced(imbalance); - if !missed_any { // burn some proportion of the remaining budget if we run a surplus. - let burn = (Self::burn() * budget_remaining).min(budget_remaining); + let burn = (T::Burn::get() * budget_remaining).min(budget_remaining); budget_remaining -= burn; + imbalance.subsume(T::Currency::burn(burn)); Self::deposit_event(RawEvent::Burnt(burn)) } + if let Err(problem) = T::Currency::settle( + &Self::account_id(), + imbalance, + WithdrawReason::Transfer, + ExistenceRequirement::KeepAlive + ) { + print("Inconsistent state - couldn't settle imbalance for funds spent by treasury"); + // Nothing else to do here. + drop(problem); + } + Self::deposit_event(RawEvent::Rollover(budget_remaining)); + } + + fn pot() -> BalanceOf { + T::Currency::free_balance(&Self::account_id()) + } +} - >::put(budget_remaining); +impl OnUnbalanced> for Module { + fn on_unbalanced(amount: NegativeImbalanceOf) { + T::Currency::resolve_creating(&Self::account_id(), amount); } } @@ -322,7 +346,7 @@ impl OnDilution> for Module { if let Some(funding) = total_issuance.checked_sub(&portion) { let funding = funding / portion; if let Some(funding) = funding.checked_mul(&minted) { - >::mutate(|x| *x = x.saturating_add(funding)); + Self::on_unbalanced(T::Currency::issue(funding)); } } } @@ -334,11 +358,9 @@ mod tests { use super::*; use runtime_io::with_externalities; - use srml_support::{impl_outer_origin, assert_ok, assert_noop}; + use srml_support::{assert_noop, assert_ok, impl_outer_origin, parameter_types}; use substrate_primitives::{H256, Blake2Hasher}; - use runtime_primitives::BuildStorage; - use runtime_primitives::traits::{BlakeTwo256, OnFinalize, IdentityLookup}; - use runtime_primitives::testing::Header; + use runtime_primitives::{traits::{BlakeTwo256, OnFinalize, IdentityLookup}, testing::Header}; impl_outer_origin! { pub enum Origin for Test {} @@ -346,6 +368,9 @@ mod tests { #[derive(Clone, Eq, PartialEq)] pub struct Test; + parameter_types! { + pub const BlockHashCount: u64 = 250; + } impl system::Trait for Test { type Origin = Origin; type Index = u64; @@ -356,6 +381,14 @@ mod tests { type Lookup = IdentityLookup; type Header = Header; type Event = (); + type BlockHashCount = BlockHashCount; + } + parameter_types! { + pub const ExistentialDeposit: u64 = 0; + pub const TransferFee: u64 = 0; + pub const CreationFee: u64 = 0; + pub const TransactionBaseFee: u64 = 0; + pub const TransactionByteFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; @@ -365,6 +398,17 @@ mod tests { type TransactionPayment = (); type TransferPayment = (); type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type TransferFee = TransferFee; + type CreationFee = CreationFee; + type TransactionBaseFee = TransactionBaseFee; + type TransactionByteFee = TransactionByteFee; + } + parameter_types! { + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const ProposalBondMinimum: u64 = 1; + pub const SpendPeriod: u64 = 2; + pub const Burn: Permill = Permill::from_percent(50); } impl Trait for Test { type Currency = balances::Module; @@ -373,37 +417,26 @@ mod tests { type Event = (); type MintedForSpending = (); type ProposalRejection = (); + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ProposalBondMinimum; + type SpendPeriod = SpendPeriod; + type Burn = Burn; } type Balances = balances::Module; type Treasury = Module; fn new_test_ext() -> runtime_io::TestExternalities { - let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; + let mut t = system::GenesisConfig::default().build_storage::().unwrap().0; t.extend(balances::GenesisConfig::{ balances: vec![(0, 100), (1, 99), (2, 1)], - transaction_base_fee: 0, - transaction_byte_fee: 0, - transfer_fee: 0, - creation_fee: 0, - existential_deposit: 0, vesting: vec![], }.build_storage().unwrap().0); - t.extend(GenesisConfig::{ - proposal_bond: Permill::from_percent(5), - proposal_bond_minimum: 1, - spend_period: 2, - burn: Permill::from_percent(50), - }.build_storage().unwrap().0); t.into() } #[test] fn genesis_config_works() { with_externalities(&mut new_test_ext(), || { - assert_eq!(Treasury::proposal_bond(), Permill::from_percent(5)); - assert_eq!(Treasury::proposal_bond_minimum(), 1); - assert_eq!(Treasury::spend_period(), 2); - assert_eq!(Treasury::burn(), Permill::from_percent(50)); assert_eq!(Treasury::pot(), 0); assert_eq!(Treasury::proposal_count(), 0); }); @@ -521,6 +554,7 @@ mod tests { fn accepted_spend_proposal_enacted_on_spend_period() { with_externalities(&mut new_test_ext(), || { Treasury::on_dilution(100, 100); + assert_eq!(Treasury::pot(), 100); assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); assert_ok!(Treasury::approve_proposal(Origin::ROOT, 0)); @@ -538,25 +572,27 @@ mod tests { fn on_dilution_quantization_effects() { with_externalities(&mut new_test_ext(), || { // minted = 1% of total issuance for all cases - let _ = Treasury::set_pot(0); assert_eq!(Balances::total_issuance(), 200); Treasury::on_dilution(2, 66); // portion = 33% of total issuance assert_eq!(Treasury::pot(), 4); // should increase by 4 (200 - 66) / 66 * 2 + Balances::make_free_balance_be(&Treasury::account_id(), 0); Treasury::on_dilution(2, 67); // portion = 33+eps% of total issuance - assert_eq!(Treasury::pot(), 6); // should increase by 2 (200 - 67) / 67 * 2 + assert_eq!(Treasury::pot(), 2); // should increase by 2 (200 - 67) / 67 * 2 + Balances::make_free_balance_be(&Treasury::account_id(), 0); Treasury::on_dilution(2, 100); // portion = 50% of total issuance - assert_eq!(Treasury::pot(), 8); // should increase by 2 (200 - 100) / 100 * 2 + assert_eq!(Treasury::pot(), 2); // should increase by 2 (200 - 100) / 100 * 2 + Balances::make_free_balance_be(&Treasury::account_id(), 0); // If any more than 50% of the network is staked (i.e. (2 * portion) > total_issuance) // then the pot will not increase. Treasury::on_dilution(2, 101); // portion = 50+eps% of total issuance - assert_eq!(Treasury::pot(), 8); // should increase by 0 (200 - 101) / 101 * 2 + assert_eq!(Treasury::pot(), 0); // should increase by 0 (200 - 101) / 101 * 2 Treasury::on_dilution(2, 134); // portion = 67% of total issuance - assert_eq!(Treasury::pot(), 8); // should increase by 0 (200 - 134) / 134 * 2 + assert_eq!(Treasury::pot(), 0); // should increase by 0 (200 - 134) / 134 * 2 }); } @@ -574,7 +610,7 @@ mod tests { Treasury::on_dilution(100, 100); >::on_finalize(4); assert_eq!(Balances::free_balance(&3), 150); - assert_eq!(Treasury::pot(), 25); + assert_eq!(Treasury::pot(), 75); }); } } diff --git a/subkey/Cargo.toml b/subkey/Cargo.toml index 5f043e9486c5bc5d6231fca57808eb5dbfebb4e1..699448e17407c39dffc4fa0b48a098089b56fb70 100644 --- a/subkey/Cargo.toml +++ b/subkey/Cargo.toml @@ -13,11 +13,11 @@ rand = "0.6" clap = { version = "~2.32", features = ["yaml"] } tiny-bip39 = "0.6.0" rustc-hex = "2.0" -substrate-bip39 = { git = "https://github.com/paritytech/substrate-bip39" } -schnorrkel = "0.1" +substrate-bip39 = "0.2.2" +schnorrkel = "0.1.1" hex = "0.3" hex-literal = "0.2" -parity-codec = "3.2" +parity-codec = "4.1.1" [features] bench = [] diff --git a/subkey/src/main.rs b/subkey/src/main.rs index b38bffd772bbf375491f9060a1784d52b84af59e..7cff0d6414f262578acf645fbcc1a0f92a8bd840 100644 --- a/subkey/src/main.rs +++ b/subkey/src/main.rs @@ -22,7 +22,7 @@ use std::{str::FromStr, io::{stdin, Read}}; use hex_literal::hex; use clap::load_yaml; use bip39::{Mnemonic, Language, MnemonicType}; -use substrate_primitives::{ed25519, sr25519, hexdisplay::HexDisplay, Pair, crypto::Ss58Codec, blake2_256}; +use substrate_primitives::{ed25519, sr25519, hexdisplay::HexDisplay, Pair, Public, crypto::Ss58Codec, blake2_256}; use parity_codec::{Encode, Decode, Compact}; use sr_primitives::generic::Era; use node_primitives::{Balance, Index, Hash}; @@ -32,7 +32,7 @@ mod vanity; trait Crypto { type Pair: Pair; - type Public: Ss58Codec + AsRef<[u8]>; + type Public: Public + Ss58Codec + AsRef<[u8]> + std::hash::Hash; fn pair_from_suri(suri: &str, password: Option<&str>) -> Self::Pair { Self::Pair::from_string(suri, password).expect("Invalid phrase") } diff --git a/test-utils/chain-spec-builder/Cargo.lock b/test-utils/chain-spec-builder/Cargo.lock index 89c08fd77e7af9297381730b0c1141121f36c500..afa92a46f8f4dd70021d0b2e7a53fb81dff6a3fa 100644 --- a/test-utils/chain-spec-builder/Cargo.lock +++ b/test-utils/chain-spec-builder/Cargo.lock @@ -463,7 +463,7 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1370,7 +1370,7 @@ dependencies = [ "parity-multiaddr 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multihash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "stdweb 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1402,7 +1402,7 @@ dependencies = [ "rw-stream-sink 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "secp256k1 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1447,7 +1447,7 @@ dependencies = [ "libp2p-core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1466,7 +1466,7 @@ dependencies = [ "parity-multiaddr 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1493,7 +1493,7 @@ dependencies = [ "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1514,7 +1514,7 @@ dependencies = [ "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multiaddr 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1860,7 +1860,7 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2238,7 +2238,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2250,7 +2250,7 @@ dependencies = [ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2262,7 +2262,7 @@ dependencies = [ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2941,7 +2941,7 @@ dependencies = [ "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "static_slice 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3763,7 +3763,7 @@ dependencies = [ "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "slog_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-peerset 1.0.0", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4457,7 +4457,7 @@ name = "unicode-normalization" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -5091,7 +5091,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddc0d2aff1f8f325ef660d9a0eb6e6dcd20b30b3f581a5897f58bf42d061c37a" "checksum slog-scope 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "60c04b4726fa04595ccf2c2dad7bcd15474242c4c5e109a8a376e8a2c9b1539a" "checksum slog_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eff3b513cf2e0d1a60e1aba152dc72bedc5b05585722bb3cebd7bcb1e31b98f" -"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" +"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" "checksum snow 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5a64f02fd208ef15bd2d1a65861df4707e416151e1272d02c8faafad1c138100" "checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3" "checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" diff --git a/test-utils/transaction-factory/Cargo.toml b/test-utils/transaction-factory/Cargo.toml index 66faaf6b345820bff589b319255de8a177e89813..2868b4f5372eedf4dae28ad887a20ebb3b2844ef 100644 --- a/test-utils/transaction-factory/Cargo.toml +++ b/test-utils/transaction-factory/Cargo.toml @@ -9,7 +9,7 @@ cli = { package = "substrate-cli", path = "../../core/cli" } client = { package = "substrate-client", path = "../../core/client" } consensus_common = { package = "substrate-consensus-common", path = "../../core/consensus/common" } log = "0.4" -parity-codec = { version = "3.3", default-features = false, features = ["derive"] } +parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } primitives = { package = "substrate-primitives", path = "../../core/primitives", default-features = false } sr_primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } substrate-service = { path = "../../core/service" } diff --git a/test-utils/transaction-factory/src/lib.rs b/test-utils/transaction-factory/src/lib.rs index 5bc3e561b6878d636547bed5a21bc8f3d88980e0..d4a9799c35c71749b70b6384f14caec3528034fe 100644 --- a/test-utils/transaction-factory/src/lib.rs +++ b/test-utils/transaction-factory/src/lib.rs @@ -176,5 +176,5 @@ fn import_block( auxiliary: Vec::new(), fork_choice: ForkChoiceStrategy::LongestChain, }; - client.import_block(import, HashMap::new()).expect("Failed to import block"); + (&**client).import_block(import, HashMap::new()).expect("Failed to import block"); }