diff --git a/.gitignore b/.gitignore index 4caeb6cc533a35a4f14e5b4ca8e038fe6f60b61b..21dee82d81463e8c0b197aa633697fdbfc143cdc 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,5 @@ node/runtime/wasm/target/ polkadot.* .DS_Store .idea/ +nohup.out +rls*.log diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bda6a6e5e8fd5c3a07b227f387c46d458607e829..f4f42ef49ae1dda63a300a450f80ea5cc220bbc3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,9 @@ # .gitlab-ci.yml - +# +# substrate +# +# pipelines can be triggered manually in the web +# setting DEPLOY_TAG will only deploy the tagged image stages: @@ -7,7 +11,7 @@ stages: - test - build - publish - - label + - deploy image: parity/rust:nightly @@ -20,13 +24,9 @@ variables: -cache: - key: "${CI_JOB_NAME}" - paths: - - ${CARGO_HOME} - - ./target +cache: {} -.collect_artifacts: &collect_artifacts +.collect-artifacts: &collect-artifacts artifacts: name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" when: on_success @@ -36,14 +36,21 @@ cache: +.kubernetes-build: &kubernetes-build + tags: + - kubernetes-parity-build + environment: + name: parity-build + + + #### stage: merge-test -check:merge:conflict: +check-merge-conflict: stage: merge-test image: parity/tools:latest cache: {} - tags: - - linux-docker + <<: *kubernetes-build only: - /^[0-9]+$/ variables: @@ -58,12 +65,11 @@ check:merge:conflict: #### stage: test -check:runtime: +check-runtime: stage: test image: parity/tools:latest cache: {} - tags: - - linux-docker + <<: *kubernetes-build only: - /^[0-9]+$/ variables: @@ -75,27 +81,34 @@ check:runtime: -test:rust:stable: &test +test-linux-stable: &test stage: test + cache: + key: "${CI_JOB_NAME}" + paths: + - ${CARGO_HOME} + - ./target variables: RUST_TOOLCHAIN: stable # Enable debug assertions since we are running optimized builds for testing # but still want to have debug assertions. RUSTFLAGS: -Cdebug-assertions=y TARGET: native + tags: + - linux-docker only: - tags - master - schedules - web - - /^pr-[0-9]+$/ - /^[0-9]+$/ - tags: - - linux-docker + except: + variables: + - $DEPLOY_TAG before_script: - - test -d ${CARGO_HOME} -a -d ./target && + - test -d ${CARGO_HOME} -a -d ./target && echo "build cache size:" && - du -hs ${CARGO_HOME} ./target + du -h --max-depth=2 ${CARGO_HOME} ./target - ./scripts/build.sh script: - time cargo test --all --release --verbose --locked @@ -104,7 +117,7 @@ test:rust:stable: &test -.build_only: &build_only +.build-only: &build-only only: - master - tags @@ -113,10 +126,18 @@ test:rust:stable: &test #### stage: build -build:rust:linux:release: &build +build-linux-release: &build stage: build - <<: *collect_artifacts - <<: *build_only + cache: + key: "${CI_JOB_NAME}" + paths: + - ${CARGO_HOME} + - ./target + <<: *collect-artifacts + <<: *build-only + except: + variables: + - $DEPLOY_TAG tags: - linux-docker before_script: @@ -126,19 +147,21 @@ build:rust:linux:release: &build - mkdir -p ./artifacts - mv ./target/release/substrate ./artifacts/. - echo -n "Substrate version = " - - if [ "${CI_COMMIT_TAG}" ]; then + - if [ "${CI_COMMIT_TAG}" ]; then echo "${CI_COMMIT_TAG}" | tee ./artifacts/VERSION; - else + else ./artifacts/substrate --version | sed -n -r 's/^substrate ([0-9.]+.*-[0-9a-f]{7,13})-.*$/\1/p' | tee ./artifacts/VERSION; fi - sha256sum ./artifacts/substrate | tee ./artifacts/substrate.sha256 + - echo "\n# building node-template\n" - ./scripts/node-template-release.sh ./artifacts/substrate-node-template.tar.gz + - cp -r scripts/docker/* ./artifacts -build:rust:doc:release: &build +build-rust-doc-release: &build stage: build allow_failure: true artifacts: @@ -147,12 +170,12 @@ build:rust:doc:release: &build expire_in: 7 days paths: - ./crate-docs - <<: *build_only + <<: *build-only tags: - linux-docker script: - rm -f ./crate-docs/index.html # use it as an indicator if the job succeeds - - time cargo doc --release --verbose + - time cargo +nightly doc --release --verbose - cp -R ./target/doc ./crate-docs - echo "" > ./crate-docs/index.html @@ -161,41 +184,52 @@ build:rust:doc:release: &build #### stage: publish -.publish_build: &publish_build +.publish-build: &publish-build stage: publish dependencies: - - build:rust:linux:release + - build-linux-release cache: {} - <<: *build_only + <<: *build-only + <<: *kubernetes-build -publish:docker:release: - <<: *publish_build - tags: - - shell +publish-docker-release: + <<: *publish-build + image: docker:stable + services: + - docker:dind + # collect VERSION artifact here to pass it on to kubernetes + <<: *collect-artifacts variables: + DOCKER_HOST: tcp://localhost:2375 + DOCKER_DRIVER: overlay2 GIT_STRATEGY: none - DOCKERFILE: scripts/docker/Dockerfile + # DOCKERFILE: scripts/docker/Dockerfile CONTAINER_IMAGE: parity/substrate - script: - - VERSION="$(cat ./artifacts/VERSION)" + before_script: - test "$Docker_Hub_User_Parity" -a "$Docker_Hub_Pass_Parity" || ( echo "no docker credentials provided"; exit 1 ) - docker login -u "$Docker_Hub_User_Parity" -p "$Docker_Hub_Pass_Parity" - docker info - - docker build --tag $CONTAINER_IMAGE:$VERSION --tag $CONTAINER_IMAGE:latest -f $DOCKERFILE ./artifacts/ + script: + - VERSION="$(cat ./artifacts/VERSION)" + - echo "Substrate version = ${VERSION}" + - test -z "${VERSION}" && exit 1 + - cd ./artifacts + - docker build --tag $CONTAINER_IMAGE:$VERSION --tag $CONTAINER_IMAGE:latest . - docker push $CONTAINER_IMAGE:$VERSION - docker push $CONTAINER_IMAGE:latest after_script: - docker logout + # only VERSION information is needed for the deployment + - find ./artifacts/ -depth -not -name VERSION -not -name artifacts -delete - -publish:s3:release: - <<: *publish_build +publish-s3-release: + <<: *publish-build image: parity/awscli:latest variables: GIT_STRATEGY: none @@ -213,21 +247,17 @@ publish:s3:release: after_script: - aws s3 ls s3://${BUCKET}/${PREFIX}/latest/ --recursive --human-readable --summarize - tags: - - linux-docker -publish:s3:doc: +publish-s3-doc: stage: publish + allow_failure: true dependencies: - - build:rust:doc:release + - build-rust-doc-release cache: {} - only: - - master - - tags - - web - - publish-rustdoc + <<: *build-only + <<: *kubernetes-build variables: GIT_STRATEGY: none BUCKET: "releases.parity.io" @@ -242,9 +272,83 @@ publish:s3:doc: after_script: - aws s3 ls s3://${BUCKET}/${PREFIX}/ --human-readable --summarize + + + + + +.deploy-template: &deploy + stage: deploy + when: manual + cache: {} + retry: 1 + image: parity/kubectl-helm:$HELM_VERSION + <<: *build-only tags: - - linux-docker + # this is the runner that is used to deploy it + - kubernetes-parity-build + before_script: + - test -z "${DEPLOY_TAG}" && + test -f ./artifacts/VERSION && + DEPLOY_TAG="$(cat ./artifacts/VERSION)" + - test "${DEPLOY_TAG}" || ( echo "Neither DEPLOY_TAG nor VERSION information available"; exit 1 ) + script: + - echo "Substrate version = ${DEPLOY_TAG}" + # or use helm to render the template + - helm template + --values ./scripts/kubernetes/values.yaml + --set image.tag=${DEPLOY_TAG} + --set validator.keys=${VALIDATOR_KEYS} + ./scripts/kubernetes | kubectl apply -f - --dry-run=false + - echo "# substrate namespace ${KUBE_NAMESPACE}" + - kubectl -n ${KUBE_NAMESPACE} get all + - echo "# substrate's nodes' external ip addresses:" + - kubectl get nodes -l node=substrate + -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{range @.status.addresses[?(@.type=="ExternalIP")]}{.address}{"\n"}{end}' + - echo "# substrate' nodes" + - kubectl -n ${KUBE_NAMESPACE} get pods + -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.nodeName}{"\n"}{end}' + - echo "# wait for the rollout to complete" + - kubectl -n ${KUBE_NAMESPACE} rollout status statefulset/substrate + + + +# have environment:url eventually point to the logs + + +.deploy-cibuild: &deploy-cibuild + <<: *deploy + dependencies: + - publish-docker-release + +.deploy-tag: &deploy-tag + <<: *deploy + only: + variables: + - $DEPLOY_TAG + + + +# have environment:url eventually point to the logs +deploy-ew3: + <<: *deploy-cibuild + environment: + name: parity-prod-ew3 + +deploy-ue1: + <<: *deploy-cibuild + environment: + name: parity-prod-ue1 + +deploy-ew3-tag: + <<: *deploy-tag + environment: + name: parity-prod-ew3 +deploy-ue1-tag: + <<: *deploy-tag + environment: + name: parity-prod-ue1 diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index 30bf3a1bb2cb63e2988d041f3304677d6b563a27..7098869dcc4a0e157945042812fd72826f0bc94f 100644 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -47,7 +47,7 @@ When reviewing a pull request, the end-goal is to suggest useful changes to the == Helping out -We use https://github.com/paritytech/substrate/labels[labels] to manage PRs and issues and communicate state of a PR. Please familiarize yourself with them. Further more we are organising issues in https://github.com/paritytech/substrate/milestones[milestones]. Best way to get started is to a pick a ticket from the current milestone tagged https://github.com/paritytech/substrate/issues?q=is%3Aissue+is%3Aopen+label%3AQ2-easy[`easy`] or https://github.com/paritytech/substrate/issues?q=is%3Aissue+is%3Aopen+label%3AQ3-medium[`medium`] and get going or https://github.com/paritytech/substrate/issues?q=is%3Aissue+is%3Aopen+label%3AX1-mentor[`mentor`] and get in contact with the mentor offering their support on that larger task. +We use https://github.com/paritytech/substrate/labels[labels] to manage PRs and issues and communicate state of a PR. Please familiarize yourself with them. Furthermore we are organising issues in https://github.com/paritytech/substrate/milestones[milestones]. Best way to get started is to a pick a ticket from the current milestone tagged https://github.com/paritytech/substrate/issues?q=is%3Aissue+is%3Aopen+label%3AQ2-easy[`easy`] or https://github.com/paritytech/substrate/issues?q=is%3Aissue+is%3Aopen+label%3AQ3-medium[`medium`] and get going or https://github.com/paritytech/substrate/issues?q=is%3Aissue+is%3Aopen+label%3AX1-mentor[`mentor`] and get in contact with the mentor offering their support on that larger task. == Releases diff --git a/Cargo.lock b/Cargo.lock index af1da8afc0769c4605239583e6b28f11eae87a54..b5882769dbc87c0b3af07dd7f4a51ed0f6899afa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -136,7 +136,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.2 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -194,11 +194,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "cexpr 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (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.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.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)", "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.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -212,6 +212,11 @@ name = "bitflags" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitmask" +version = "0.5.0" +source = "git+https://github.com/paritytech/bitmask#c2d8d196e30b018d1385be8357fdca61b978facf" + [[package]] name = "blake2" version = "0.8.0" @@ -283,11 +288,6 @@ name = "byte-tools" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "byteorder" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "byteorder" version = "0.5.3" @@ -330,7 +330,7 @@ dependencies = [ [[package]] name = "cfg-if" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -425,7 +425,7 @@ dependencies = [ "criterion-plot 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "csv 1.0.5 (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.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)", "num-traits 0.2.6 (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.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -453,12 +453,12 @@ name = "crossbeam" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (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.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)", "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -496,9 +496,9 @@ 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.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (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.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)", "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)", @@ -510,9 +510,9 @@ 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.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (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.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)", "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)", ] @@ -522,7 +522,7 @@ name = "crossbeam-utils" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -530,8 +530,8 @@ name = "crossbeam-utils" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -697,7 +697,7 @@ dependencies = [ [[package]] name = "environmental" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -758,8 +758,8 @@ dependencies = [ "futures 0.1.25 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -798,8 +798,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "fork-tree" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -807,7 +806,7 @@ name = "fs-swap" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.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.48 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -904,16 +903,32 @@ dependencies = [ [[package]] name = "hash-db" -version = "0.11.0" +version = "0.12.2" [[package]] name = "hash256-std-hasher" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crunchy 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hash256-std-hasher" +version = "0.12.2" +dependencies = [ + "crunchy 0.2.1 (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" @@ -1068,7 +1083,7 @@ name = "impl-codec" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1171,7 +1186,7 @@ dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.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)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1200,11 +1215,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "keccak-hasher" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hash-db 0.11.0", - "hash256-std-hasher 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", + "hash256-std-hasher 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "keccak-hasher" +version = "0.12.2" +dependencies = [ + "hash-db 0.12.2", + "hash256-std-hasher 0.12.2", "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1258,7 +1282,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1282,31 +1306,31 @@ dependencies = [ [[package]] name = "libp2p" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-dns 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-floodsub 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-identify 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-kad 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-mdns 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-mplex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-noise 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-ping 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-plaintext 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-ratelimit 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-secio 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-tcp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-uds 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-websocket 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-yamux 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multihash 0.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)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-core-derive 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-dns 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-floodsub 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-identify 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-kad 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-mdns 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-mplex 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-noise 0.3.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-ping 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-plaintext 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-ratelimit 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-secio 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-tcp 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-uds 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-websocket 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-yamux 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "stdweb 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1317,60 +1341,43 @@ dependencies = [ [[package]] name = "libp2p-core" -version = "0.3.4" -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.11 (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.25 (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.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multihash 0.1.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.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rw-stream-sink 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.10 (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)", -] - -[[package]] -name = "libp2p-core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" 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.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)", + "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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.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)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "multistream-select 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multihash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "multistream-select 0.3.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf 2.3.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)", - "rw-stream-sink 0.1.0 (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.1 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.10 (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)", + "zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-core-derive" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" dependencies = [ "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1378,28 +1385,28 @@ dependencies = [ [[package]] name = "libp2p-dns" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "tokio-dns-unofficial 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-floodsub" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" dependencies = [ "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.11 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "protobuf 2.3.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.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1410,15 +1417,15 @@ dependencies = [ [[package]] name = "libp2p-identify" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" dependencies = [ "bytes 0.4.11 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1431,8 +1438,8 @@ dependencies = [ [[package]] name = "libp2p-kad" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" dependencies = [ "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)", @@ -1440,12 +1447,12 @@ dependencies = [ "bytes 0.4.11 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-identify 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-ping 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-identify 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-ping 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multihash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1459,16 +1466,16 @@ dependencies = [ [[package]] name = "libp2p-mdns" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" 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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "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.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1480,13 +1487,13 @@ dependencies = [ [[package]] name = "libp2p-mplex" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" dependencies = [ "bytes 0.4.11 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1496,30 +1503,33 @@ dependencies = [ [[package]] name = "libp2p-noise" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.3.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" dependencies = [ "curve25519-dalek 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.3.4 (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.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "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)", + "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", "snow 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "x25519-dalek 0.5.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-ping" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" dependencies = [ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "parking_lot 0.7.1 (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)", @@ -1530,22 +1540,22 @@ dependencies = [ [[package]] name = "libp2p-plaintext" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-ratelimit" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" dependencies = [ "aio-limited 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1553,23 +1563,22 @@ dependencies = [ [[package]] name = "libp2p-secio" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" 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.11 (registry+https://github.com/rust-lang/crates.io-index)", "ctr 0.3.0 (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)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (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.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf 2.3.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.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rw-stream-sink 0.1.1 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "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)", "stdweb 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1580,13 +1589,13 @@ dependencies = [ [[package]] name = "libp2p-tcp" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "tk-listen 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1594,26 +1603,26 @@ dependencies = [ [[package]] name = "libp2p-uds" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-websocket" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rw-stream-sink 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "rw-stream-sink 0.1.1 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "stdweb 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "websocket 0.22.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1621,14 +1630,14 @@ dependencies = [ [[package]] name = "libp2p-yamux" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "yamux 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "yamux 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1696,7 +1705,7 @@ name = "log" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1722,7 +1731,7 @@ name = "memchr" version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1733,9 +1742,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memory-db" -version = "0.11.0" +version = "0.12.2" dependencies = [ - "hash-db 0.11.0", + "hash-db 0.12.2", "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)", ] @@ -1818,7 +1827,7 @@ dependencies = [ [[package]] name = "multistream-select" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1842,7 +1851,7 @@ name = "native-tls" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.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.48 (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.16 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1859,7 +1868,7 @@ name = "net2" version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1871,7 +1880,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1887,8 +1896,7 @@ dependencies = [ "node-executor 0.1.0", "node-primitives 0.1.0", "node-runtime 0.1.0", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1903,6 +1911,7 @@ dependencies = [ "substrate-primitives 0.1.0", "substrate-service 0.3.0", "substrate-service-test 0.3.0", + "substrate-telemetry 0.3.1", "substrate-transaction-pool 0.1.0", "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1913,13 +1922,12 @@ version = "0.1.0" dependencies = [ "node-primitives 0.1.0", "node-runtime 0.1.0", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "srml-balances 0.1.0", "srml-consensus 0.1.0", "srml-contract 0.1.0", - "srml-fees 0.1.0", "srml-grandpa 0.1.0", "srml-indices 0.1.0", "srml-session 0.1.0", @@ -1933,7 +1941,7 @@ dependencies = [ "substrate-primitives 0.1.0", "substrate-state-machine 0.1.0", "substrate-trie 0.4.0", - "trie-root 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-root 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1941,8 +1949,8 @@ dependencies = [ name = "node-primitives" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (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.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1959,8 +1967,7 @@ dependencies = [ "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "node-primitives 0.1.0", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (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.87 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1974,7 +1981,7 @@ dependencies = [ "srml-council 0.1.0", "srml-democracy 0.1.0", "srml-executive 0.1.0", - "srml-fees 0.1.0", + "srml-finality-tracker 0.1.0", "srml-grandpa 0.1.0", "srml-indices 0.1.0", "srml-session 0.1.0", @@ -1984,10 +1991,10 @@ dependencies = [ "srml-system 0.1.0", "srml-timestamp 0.1.0", "srml-treasury 0.1.0", - "srml-upgrade-key 0.1.0", "substrate-client 0.1.0", "substrate-consensus-aura-primitives 0.1.0", "substrate-keyring 0.1.0", + "substrate-offchain-primitives 0.1.0", "substrate-primitives 0.1.0", ] @@ -2001,11 +2008,9 @@ dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 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)", - "node-executor 0.1.0", "node-template-runtime 0.9.0", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "substrate-basic-authorship 0.1.0", "substrate-cli 0.3.0", @@ -2018,7 +2023,7 @@ dependencies = [ "substrate-service 0.3.0", "substrate-transaction-pool 0.1.0", "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-root 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-root 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2026,8 +2031,7 @@ dependencies = [ name = "node-template-runtime" version = "0.9.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.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.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2039,7 +2043,6 @@ dependencies = [ "srml-balances 0.1.0", "srml-consensus 0.1.0", "srml-executive 0.1.0", - "srml-fees 0.1.0", "srml-indices 0.1.0", "srml-sudo 0.1.0", "srml-support 0.1.0", @@ -2047,6 +2050,7 @@ dependencies = [ "srml-timestamp 0.1.0", "substrate-client 0.1.0", "substrate-consensus-aura-primitives 0.1.0", + "substrate-offchain-primitives 0.1.0", "substrate-primitives 0.1.0", ] @@ -2103,6 +2107,9 @@ dependencies = [ 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" @@ -2115,9 +2122,9 @@ version = "0.10.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (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.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.48 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2161,18 +2168,20 @@ source = "git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7 [[package]] name = "parity-codec" -version = "3.0.0" +version = "3.2.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)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "parity-codec-derive" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "proc-macro-crate 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2189,30 +2198,16 @@ dependencies = [ "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "parity-multiaddr" -version = "0.1.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 0.4.2 (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.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.87 (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-multiaddr" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" 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)", "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multihash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2220,7 +2215,7 @@ dependencies = [ [[package]] name = "parity-multihash" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" 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)", @@ -2337,6 +2332,16 @@ dependencies = [ "syn 0.15.26 (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 = "peeking_take_while" version = "0.1.2" @@ -2614,7 +2619,7 @@ 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.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.48 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2681,8 +2686,8 @@ dependencies = [ "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2691,7 +2696,7 @@ version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.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.48 (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)", @@ -2744,8 +2749,8 @@ dependencies = [ [[package]] name = "rw-stream-sink" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.1.1" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2783,13 +2788,13 @@ name = "schannel" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.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)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "schnorrkel" -version = "0.0.0" +version = "0.1.0" 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)", @@ -2799,6 +2804,7 @@ dependencies = [ "merlin 1.0.2 (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.1 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2962,7 +2968,7 @@ 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.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)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3017,10 +3023,10 @@ dependencies = [ name = "sr-io" version = "0.1.0" dependencies = [ - "environmental 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.11.0", + "environmental 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (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 0.1.0", "substrate-primitives 0.1.0", @@ -3036,8 +3042,7 @@ 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.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3051,7 +3056,7 @@ name = "sr-sandbox" version = "0.1.0" dependencies = [ "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (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 0.1.0", "substrate-primitives 0.1.0", @@ -3071,8 +3076,7 @@ name = "sr-version" version = "0.1.0" dependencies = [ "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", @@ -3084,7 +3088,7 @@ name = "srml-assets" version = "0.1.0" dependencies = [ "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", @@ -3099,15 +3103,16 @@ name = "srml-aura" version = "0.1.0" dependencies = [ "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (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.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", "srml-consensus 0.1.0", + "srml-session 0.1.0", "srml-staking 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", @@ -3121,8 +3126,7 @@ name = "srml-balances" version = "0.1.0" dependencies = [ "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.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.87 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -3139,8 +3143,7 @@ name = "srml-consensus" version = "0.1.0" dependencies = [ "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -3158,8 +3161,7 @@ version = "0.1.0" dependencies = [ "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (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.87 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3170,7 +3172,6 @@ dependencies = [ "sr-std 0.1.0", "srml-balances 0.1.0", "srml-consensus 0.1.0", - "srml-fees 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", "srml-timestamp 0.1.0", @@ -3183,8 +3184,8 @@ name = "srml-council" version = "0.1.0" dependencies = [ "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.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.87 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -3202,8 +3203,7 @@ name = "srml-democracy" version = "0.1.0" dependencies = [ "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.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.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3221,7 +3221,7 @@ name = "srml-example" version = "0.1.0" dependencies = [ "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", @@ -3236,14 +3236,13 @@ name = "srml-executive" version = "0.1.0" dependencies = [ "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", "srml-balances 0.1.0", - "srml-fees 0.1.0", "srml-indices 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", @@ -3251,18 +3250,21 @@ dependencies = [ ] [[package]] -name = "srml-fees" +name = "srml-finality-tracker" version = "0.1.0" dependencies = [ "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (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.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", + "substrate-inherents 0.1.0", "substrate-primitives 0.1.0", ] @@ -3270,13 +3272,14 @@ dependencies = [ name = "srml-grandpa" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", + "srml-consensus 0.1.0", + "srml-finality-tracker 0.1.0", "srml-session 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", @@ -3289,8 +3292,8 @@ name = "srml-indices" version = "0.1.0" dependencies = [ "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (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.87 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3307,8 +3310,7 @@ dependencies = [ name = "srml-metadata" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 0.1.0", @@ -3320,8 +3322,9 @@ name = "srml-session" version = "0.1.0" dependencies = [ "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (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.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.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.87 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -3339,8 +3342,7 @@ name = "srml-staking" version = "0.1.0" dependencies = [ "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.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.87 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -3361,8 +3363,8 @@ name = "srml-sudo" version = "0.1.0" dependencies = [ "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", @@ -3377,10 +3379,10 @@ dependencies = [ name = "srml-support" version = "0.1.0" dependencies = [ + "bitmask 0.5.0 (git+https://github.com/paritytech/bitmask)", "hex-literal 0.1.2 (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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "paste 0.1.4 (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.87 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3424,13 +3426,25 @@ dependencies = [ "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "srml-support-test" +version = "0.1.0" +dependencies = [ + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 0.1.0", + "srml-support 0.1.0", + "substrate-inherents 0.1.0", + "substrate-primitives 0.1.0", +] + [[package]] name = "srml-system" version = "0.1.0" dependencies = [ "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.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.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3446,13 +3460,11 @@ name = "srml-timestamp" version = "0.1.0" dependencies = [ "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", - "srml-consensus 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", "substrate-inherents 0.1.0", @@ -3464,8 +3476,7 @@ name = "srml-treasury" version = "0.1.0" dependencies = [ "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -3477,19 +3488,6 @@ dependencies = [ "substrate-primitives 0.1.0", ] -[[package]] -name = "srml-upgrade-key" -version = "0.1.0" -dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 0.1.0", - "sr-std 0.1.0", - "srml-consensus 0.1.0", - "srml-support 0.1.0", - "srml-system 0.1.0", -] - [[package]] name = "stable_deref_trait" version = "1.1.1" @@ -3587,18 +3585,39 @@ dependencies = [ "syn 0.15.26 (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.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "subkey" -version = "0.1.0" +version = "0.2.0" dependencies = [ "clap 2.32.0 (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)", + "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "schnorrkel 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "substrate-bip39 0.2.0 (git+https://github.com/paritytech/substrate-bip39)", "substrate-primitives 0.1.0", + "tiny-bip39 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "substrate" -version = "0.10.0" +version = "0.11.0" dependencies = [ "ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3612,17 +3631,29 @@ name = "substrate-basic-authorship" version = "0.1.0" dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "substrate-client 0.1.0", "substrate-consensus-aura-primitives 0.1.0", "substrate-consensus-common 0.1.0", "substrate-inherents 0.1.0", "substrate-primitives 0.1.0", + "substrate-telemetry 0.3.1", "substrate-test-client 0.1.0", "substrate-transaction-pool 0.1.0", ] +[[package]] +name = "substrate-bip39" +version = "0.2.0" +source = "git+https://github.com/paritytech/substrate-bip39#080da45923885cfec2379cef3dee4e7f43e6c260" +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.0 (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-cli" version = "0.3.0" @@ -3636,20 +3667,23 @@ dependencies = [ "exit-future 0.1.3 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.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)", "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.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-client 0.1.0", + "substrate-keyring 0.1.0", "substrate-network 0.1.0", "substrate-panic-handler 0.1.0", "substrate-primitives 0.1.0", "substrate-service 0.3.0", "substrate-state-machine 0.1.0", - "substrate-telemetry 0.3.0", + "substrate-telemetry 0.3.1", "sysinfo 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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.15 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3661,14 +3695,13 @@ dependencies = [ "error-chain 0.12.0 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.11.0", + "hash-db 0.12.2", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.1.2 (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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-api-macros 0.1.0", "sr-primitives 0.1.0", @@ -3680,7 +3713,7 @@ dependencies = [ "substrate-keyring 0.1.0", "substrate-primitives 0.1.0", "substrate-state-machine 0.1.0", - "substrate-telemetry 0.3.0", + "substrate-telemetry 0.3.1", "substrate-test-client 0.1.0", "substrate-trie 0.4.0", ] @@ -3690,14 +3723,13 @@ name = "substrate-client-db" version = "0.1.0" dependencies = [ "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.11.0", + "hash-db 0.12.2", "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)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "substrate-client 0.1.0", @@ -3718,7 +3750,7 @@ dependencies = [ "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", @@ -3736,6 +3768,7 @@ dependencies = [ "substrate-network 0.1.0", "substrate-primitives 0.1.0", "substrate-service 0.3.0", + "substrate-telemetry 0.3.1", "substrate-test-client 0.1.0", "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3754,7 +3787,7 @@ dependencies = [ "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "substrate-client 0.1.0", @@ -3772,9 +3805,10 @@ dependencies = [ "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-version 0.1.0", "substrate-inherents 0.1.0", @@ -3791,8 +3825,7 @@ dependencies = [ "exit-future 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "rhododendron 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -3817,10 +3850,10 @@ dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3845,18 +3878,20 @@ dependencies = [ "fork-tree 0.1.0", "futures 0.1.25 (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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", + "srml-finality-tracker 0.1.0", "substrate-client 0.1.0", "substrate-consensus-common 0.1.0", "substrate-finality-grandpa-primitives 0.1.0", + "substrate-inherents 0.1.0", "substrate-keyring 0.1.0", "substrate-network 0.1.0", "substrate-primitives 0.1.0", "substrate-service 0.3.0", + "substrate-telemetry 0.3.1", "substrate-test-client 0.1.0", "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3865,8 +3900,7 @@ dependencies = [ name = "substrate-finality-grandpa-primitives" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", "substrate-client 0.1.0", @@ -3877,8 +3911,7 @@ dependencies = [ name = "substrate-inherents" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", @@ -3889,7 +3922,9 @@ name = "substrate-keyring" version = "0.1.0" dependencies = [ "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.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)", + "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 0.1.0", ] @@ -3923,8 +3958,7 @@ dependencies = [ "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.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.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)", @@ -3933,6 +3967,7 @@ dependencies = [ "substrate-consensus-common 0.1.0", "substrate-keyring 0.1.0", "substrate-network-libp2p 0.1.0", + "substrate-peerset 0.1.0", "substrate-primitives 0.1.0", "substrate-test-client 0.1.0", "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3947,8 +3982,8 @@ dependencies = [ "error-chain 0.12.0 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3956,6 +3991,8 @@ dependencies = [ "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "substrate-peerset 0.1.0", + "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3963,6 +4000,33 @@ dependencies = [ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "substrate-offchain" +version = "0.1.0" +dependencies = [ + "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (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.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-primitives 0.1.0", + "substrate-client 0.1.0", + "substrate-consensus-common 0.1.0", + "substrate-inherents 0.1.0", + "substrate-offchain-primitives 0.1.0", + "substrate-primitives 0.1.0", + "substrate-test-client 0.1.0", + "substrate-transaction-pool 0.1.0", + "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "substrate-offchain-primitives" +version = "0.1.0" +dependencies = [ + "sr-primitives 0.1.0", + "substrate-client 0.1.0", +] + [[package]] name = "substrate-panic-handler" version = "0.1.0" @@ -3971,6 +4035,22 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "substrate-peerset" +version = "0.1.0" +dependencies = [ + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (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.87 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "substrate-primitives" version = "0.1.0" @@ -3978,24 +4058,27 @@ 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)", - "hash-db 0.11.0", - "hash256-std-hasher 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", + "hash256-std-hasher 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.2 (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.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "primitive-types 0.2.1 (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.0 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.14.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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "schnorrkel 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 0.1.0", + "substrate-bip39 0.2.0 (git+https://github.com/paritytech/substrate-bip39)", "substrate-serializer 0.1.0", + "tiny-bip39 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "twox-hash 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmi 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4007,17 +4090,19 @@ version = "0.1.0" dependencies = [ "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-derive 10.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-pubsub 10.0.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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (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.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-version 0.1.0", "substrate-client 0.1.0", @@ -4027,6 +4112,7 @@ dependencies = [ "substrate-primitives 0.1.0", "substrate-state-machine 0.1.0", "substrate-test-client 0.1.0", + "substrate-test-runtime 0.1.0", "substrate-transaction-pool 0.1.0", "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4059,9 +4145,9 @@ dependencies = [ "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "exit-future 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.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)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4073,11 +4159,13 @@ dependencies = [ "substrate-client-db 0.1.0", "substrate-consensus-common 0.1.0", "substrate-executor 0.1.0", + "substrate-inherents 0.1.0", "substrate-keystore 0.1.0", "substrate-network 0.1.0", + "substrate-offchain 0.1.0", "substrate-primitives 0.1.0", "substrate-rpc-servers 0.1.0", - "substrate-telemetry 0.3.0", + "substrate-telemetry 0.3.1", "substrate-test-client 0.1.0", "substrate-transaction-pool 0.1.0", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4108,8 +4196,7 @@ version = "0.1.0" dependencies = [ "env_logger 0.6.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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-primitives 0.1.0", ] @@ -4118,26 +4205,29 @@ dependencies = [ name = "substrate-state-machine" version = "0.1.0" dependencies = [ - "hash-db 0.11.0", + "hash-db 0.12.2", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 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)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-panic-handler 0.1.0", "substrate-primitives 0.1.0", "substrate-trie 0.4.0", - "trie-db 0.11.0", - "trie-root 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-db 0.12.2", + "trie-root 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "substrate-telemetry" -version = "0.3.0" +version = "0.3.1" dependencies = [ - "lazy_static 1.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)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (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.87 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4150,7 +4240,7 @@ name = "substrate-test-client" version = "0.1.0" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "substrate-client 0.1.0", "substrate-client-db 0.1.0", @@ -4166,27 +4256,29 @@ dependencies = [ name = "substrate-test-runtime" version = "0.1.0" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 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)", - "memory-db 0.11.0", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memory-db 0.12.2", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", "sr-version 0.1.0", + "srml-executive 0.1.0", "srml-support 0.1.0", "substrate-client 0.1.0", "substrate-consensus-aura-primitives 0.1.0", "substrate-executor 0.1.0", "substrate-inherents 0.1.0", "substrate-keyring 0.1.0", + "substrate-offchain-primitives 0.1.0", "substrate-primitives 0.1.0", + "substrate-test-client 0.1.0", "substrate-trie 0.4.0", - "trie-db 0.11.0", + "trie-db 0.12.2", ] [[package]] @@ -4194,14 +4286,16 @@ name = "substrate-transaction-graph" version = "0.1.0" dependencies = [ "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", + "substrate-primitives 0.1.0", "substrate-test-runtime 0.1.0", ] @@ -4212,7 +4306,7 @@ dependencies = [ "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "substrate-client 0.1.0", @@ -4227,17 +4321,17 @@ name = "substrate-trie" version = "0.4.0" dependencies = [ "criterion 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.11.0", + "hash-db 0.12.2", "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hasher 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memory-db 0.11.0", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "keccak-hasher 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memory-db 0.12.2", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 0.1.0", "substrate-primitives 0.1.0", - "trie-bench 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-db 0.11.0", - "trie-root 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-standardmap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-bench 0.12.2", + "trie-db 0.12.2", + "trie-root 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-standardmap 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4276,7 +4370,7 @@ name = "sysinfo" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4306,7 +4400,7 @@ name = "tempfile" version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.48 (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.51 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4345,7 +4439,7 @@ name = "thread_local" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.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)", ] [[package]] @@ -4358,6 +4452,20 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tiny-bip39" +version = "0.6.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)", + "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" @@ -4435,7 +4543,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (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.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)", "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4475,7 +4583,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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.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)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4590,25 +4698,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "trie-bench" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.12.2" dependencies = [ "criterion 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.11.0", - "keccak-hasher 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memory-db 0.11.0", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-db 0.11.0", - "trie-root 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-standardmap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", + "keccak-hasher 0.12.2", + "memory-db 0.12.2", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-db 0.12.2", + "trie-root 0.12.2", + "trie-standardmap 0.12.2", ] [[package]] name = "trie-db" -version = "0.11.0" +version = "0.12.2" dependencies = [ "elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.11.0", + "hash-db 0.12.2", "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)", @@ -4616,20 +4723,36 @@ dependencies = [ [[package]] name = "trie-root" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hash-db 0.11.0", + "hash-db 0.12.2", +] + +[[package]] +name = "trie-root" +version = "0.12.2" +dependencies = [ + "hash-db 0.12.2", ] [[package]] name = "trie-standardmap" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "criterion 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.11.0", - "keccak-hasher 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", + "keccak-hasher 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "trie-standardmap" +version = "0.12.2" +dependencies = [ + "criterion 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", + "keccak-hasher 0.12.2", ] [[package]] @@ -4652,7 +4775,7 @@ name = "twox-hash" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4947,6 +5070,16 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "x25519-dalek" +version = "0.5.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.0.3 (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 = "xdg" version = "2.2.0" @@ -4959,7 +5092,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "yamux" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4973,6 +5106,11 @@ dependencies = [ "tokio-io 0.1.11 (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" + [metadata] "checksum MacTypes-sys 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eaf9f0d0b1cc33a4d2aee14fb4b2eac03462ef4db29c8ac4057327d8a71ad86f" "checksum aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2e5b0458ea3beae0d1d8c0f3946564f8e10f90646cf78c06b4351052058d1ee" @@ -4998,6 +5136,7 @@ dependencies = [ "checksum bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebecac13b3c745150d7b6c3ea7572d372f09d627c2077e893bf26c5c7f70d282" "checksum bindgen 0.43.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d52d263eacd15d26cbcf215d254b410bd58212aaa2d3c453a04b2d3b3adcf41" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum bitmask 0.5.0 (git+https://github.com/paritytech/bitmask)" = "" "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" @@ -5007,14 +5146,13 @@ dependencies = [ "checksum bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0de79cfb98e7aa9988188784d8664b4b5dad6eaaa0863b91d9a4ed871d4f7a42" "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.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96c8b41881888cc08af32d47ac4edd52bc7fa27fef774be47a92443756451304" "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.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" "checksum cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "389803e36973d242e7fecb092b2de44a3d35ac62524b3b9339e51d577d668e02" "checksum cexpr 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "644d693ecfa91955ed32dcc7eda4914e1be97a641fb6f0645a37348e20b230da" -"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" +"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" "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" @@ -5054,7 +5192,7 @@ dependencies = [ "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" "checksum elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "073be79b6538296faf81c631872676600616073817dd9a440c477ad09b408983" "checksum env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afb070faf94c85d17d50ca44f6ad076bce18ae92f0037d350947240a36e9d42e" -"checksum environmental 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db746025e3ea695bfa0ae744dbacd5fcfc8db51b9760cf8bd0ab69708bb93c49" +"checksum environmental 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c7464757b80de8930c91c9afe77ddce501826bf9d134a87db2c67d9dc177e2c" "checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" "checksum exit-future 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "87559b08e99a81a92bbb867d237543e43495857749f688e0773390a20d56c61c" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" @@ -5078,7 +5216,8 @@ dependencies = [ "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4743617a7464bbda3c8aec8558ff2f9429047e025771037df561d383337ff865" "checksum h2 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ddb2b25a33e231484694267af28fec74ac63b5ccf51ee2065a5e313b834d836e" -"checksum hash256-std-hasher 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5c13dbac3cc50684760f54af18545c9e80fb75e93a3e586d71ebdc13138f6a4" +"checksum hash256-std-hasher 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1224388a21c88a80ae7087a2a245ca6d80acc97a9186b75789fb3eeefd0609af" +"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" @@ -5109,35 +5248,34 @@ dependencies = [ "checksum jsonrpc-server-utils 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5521613b31ea22d36d9f95ad642058dccec846a94ed8690957652d479f620707" "checksum jsonrpc-ws-server 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20b8333a5a6e6ccbcf5c90f90919de557cba4929efa164e9bd0e8e497eb20e46" "checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" -"checksum keccak-hasher 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb9d3670023f4c04153d90b8a557a822d1b27ed702bb015a87cf7bffead5b611" +"checksum keccak-hasher 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a02fb74dc1b613522069b5f2023c014756ce121c6c6fb39364c139b0efc39a2d" "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)" = "" "checksum kvdb-rocksdb 0.1.4 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" -"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" +"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.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" "checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2" -"checksum libp2p 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0ba8f6c176eca9f0e804d7ba1ead5e9730da40ccd30dce9ad24e7658e333a6b" -"checksum libp2p-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3bfdf7ab20e901f643cb0913e8e8feffd8439d3ee83d6cfea607f43fa3d14f6d" -"checksum libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c8dc95c7fda9de223bc195b637290918e8decb18e63fd3d03005f84b8ce380b" -"checksum libp2p-core-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e9ff3bb639d0be41e1aff9d0d28715e54474e4d15e43aa4865bdec44867d8d3" -"checksum libp2p-dns 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63d310aa56671539a2bce6124cf4326482278b0d0b841c3ba1514e44d8597096" -"checksum libp2p-floodsub 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8256d778f0dc087be409d8cbd081a11bc41ea27ddcd4862814e50e8cfa9c6df0" -"checksum libp2p-identify 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8883b6c80b113925360c2c7e1cb987fc14f5c01efc36db1f04d50cf569486be2" -"checksum libp2p-kad 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0691fcca7648369798c6466c61139d31dbb7e2afad311e44fcc4e220ce1e4d78" -"checksum libp2p-mdns 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63289f296e39752180d8a45e024cc38d1028a6db41deab3943ff2ccb9d1224cd" -"checksum libp2p-mplex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "791e375a6a230568f0d8f56f6236403de8e4bf4bd870c3c5f605fd1778da70b2" -"checksum libp2p-noise 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9beca4939eb183708b8f172170044d977f1264394998e183efbf4972e09c163f" -"checksum libp2p-ping 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81d40e54b11bfbdb7eb2b19a9c7bfe90af8abae0a2b0b3840b26b50151476f45" -"checksum libp2p-plaintext 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4383404cba7e4483e0b7d78b3ac5e66f8b024233a5095df9da65d5a1e975d692" -"checksum libp2p-ratelimit 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bad4fe925d50cc886608ab3b3a7a962b5064ecc49db8b66fd063a950d469c757" -"checksum libp2p-secio 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f9a7641a314d54ad7797f0445685818edb4d3c2f21690cea900f12ea73501b" -"checksum libp2p-tcp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4625bedbb083d676903a8ede4c5c42f9bf7bd5dee788f3cba29d8e01b785d253" -"checksum libp2p-uds 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac5f5d900e381b02ebea2f0621555a2f25a7735772355291aeb70fd9e0da3692" -"checksum libp2p-websocket 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96b6dfdd776a248d7494aeaf22f149b4d5f6784146546bc34f7b094c7162e141" -"checksum libp2p-yamux 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5a6197ae647c963f5a711c6fb00ba07b9a2812df26f6284870221f654fe9313" +"checksum libp2p 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-core-derive 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-dns 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-floodsub 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-identify 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-kad 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-mdns 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-mplex 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-noise 0.3.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-ping 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-plaintext 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-ratelimit 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-secio 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-tcp 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-uds 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-websocket 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-yamux 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" "checksum librocksdb-sys 5.14.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b9024327233e7fac7982440f73301c00046d438c5b1011e8f4e394226ce19007" "checksum libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "688e8d65e495567c2c35ea0001b26b9debf0b4ea11f8cccc954233b75fc3428a" "checksum linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7860ec297f7008ff7a1e3382d7f7e1dcd69efc94751a2284bafc3d013c2aa939" @@ -5158,7 +5296,7 @@ dependencies = [ "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" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum multistream-select 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ed84364f0e921a32204896952ee80c7befc14a7a39f2c56cd955d71e8dae6" +"checksum multistream-select 0.3.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" "checksum names 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef320dab323286b50fb5cdda23f61c796a72a89998ab565ca32525c5c556f2da" "checksum native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ff8e08de0070bbf4c31f452ea2a70db092f36f6f2e4d897adf5674477d488fb2" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" @@ -5178,12 +5316,11 @@ 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.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "88f69984317b736dceac3baa86600fc089856f69b44b07231f39b5648b02bcd4" -"checksum parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a58ba33211595f92cc2163ac583961d3dc767e656934146636b05256cc9acd7f" +"checksum parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "21c9c3a1623c71ed83964ff28cac6126e178920f7646d32c337eacb9152b2907" +"checksum parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "864e9f66b58c0b38f0d6b511b6576afa2b678ae801b64220553bced57ac12df9" "checksum parity-crypto 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b9db194dfbcfe3b398d63d765437a5c7232d59906e203055f0e993f6458ff1" -"checksum parity-multiaddr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9a8e5d637787fe097ec1bfca2aa3eb687396518003df991c6c7216d86682d5ff" -"checksum parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "61ae6944d4435d41f4d0f12108c5cbb9207cbb14bc8f2b4984c6e930dc9c8e41" -"checksum parity-multihash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e8eab0287ccde7821e337a124dc5a4f1d6e4c25d10cc91e3f9361615dd95076" +"checksum parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" "checksum parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)" = "511379a8194230c2395d2f5fa627a5a7e108a9f976656ce723ae68fca4097bfc" "checksum parity-ws 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2fec5048fba72a2e01baeb0d08089db79aead4b57e2443df172fb1840075a233" "checksum parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4d05f1349491390b1730afba60bb20d55761bef489a954546b58b4b34e1e2ac" @@ -5194,6 +5331,7 @@ dependencies = [ "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" "checksum paste 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f50392d1265092fbee9273414cc40eb6d47d307bd66222c477bb8450c8504f9d" "checksum paste-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a3cd512fe3a55e8933b2dcad913e365639db86d512e4004c3084b86864d9467a" +"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 pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" @@ -5242,13 +5380,13 @@ dependencies = [ "checksum rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "403bb3a286107a04825a5f82e1270acc1e14028d3d554d7a1e08914549575ab8" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rw-stream-sink 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "108ad7c3d65ba866ec50a224b7b3b0cb6c682c3d805015cea859d491232346a5" +"checksum rw-stream-sink 0.1.1 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" "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" "checksum schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "0e1a231dc10abf6749cfa5d7767f25888d484201accbd919b66ab5413c502d56" -"checksum schnorrkel 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe554f318830b48e5da8ab1ccb1ffd02b79228364dac7766b7cd1ec461ca5116" +"checksum schnorrkel 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a700659388785588c75b197cecda0f23c7112a9281ef703e8ffc651061ce014c" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum secp256k1 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfaccd3a23619349e0878d9a241f34b1982343cdf67367058cd7d078d326b63e" "checksum security-framework 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfab8dda0e7a327c696d893df9ffa19cadc4bd195797997f5223cf5831beaf05" @@ -5283,6 +5421,9 @@ dependencies = [ "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "670ad348dc73012fcf78c71f06f9d942232cdd4c859d4b6975e27836c3efc0c3" "checksum structopt-derive 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ef98172b1a00b0bec738508d3726540edcbd186d50dfd326f2b1febbb3559f04" +"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.0 (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.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "702662512f3ddeb74a64ce2fbbf3707ee1b6bb663d28bb054e0779bbc720d926" "checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" @@ -5297,6 +5438,7 @@ dependencies = [ "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.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a1415431cb2398d84da64173f8473c792808314427d4a6f2f3ea85ae67239fe3" "checksum tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e9175261fbdb60781fcd388a4d6cc7e14764a2b629a7ad94abb439aed223a44f" "checksum tinytemplate 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7655088894274afb52b807bd3c87072daa1fedd155068b8705cabfd628956115" "checksum tk-listen 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5462b0f968c0457efe38fcd2df7e487096b992419e4f5337b06775a614bbda4b" @@ -5317,9 +5459,8 @@ dependencies = [ "checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" -"checksum trie-bench 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77087d1bce467cf8371a5c0e10e4d925b065ec6cfad8b9cdff1fad4f218c6750" -"checksum trie-root 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3c6fef2705af3258ec46a7e22286090394a44216201a1cf7d04b78db825e543" -"checksum trie-standardmap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e4729504b8102acb1bef3f16e6b64d41aeb1ff0e329081451e8191df0f61ab2" +"checksum trie-root 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e45632ecaf2b8b4a40b5208383cd659b4e66f58ccd40086467a4614b45781430" +"checksum trie-standardmap 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006314f54f2ea7944a878e66fd93ad7978095bc355f30a2f26ec40f664d86c86" "checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" "checksum twofish 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d261e83e727c8e2dbb75dacac67c36e35db36a958ee504f2164fc052434e1" "checksum twox-hash 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "555cd4909480122bbbf21e34faac4cb08a171f324775670447ed116726c474af" @@ -5360,6 +5501,8 @@ dependencies = [ "checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" "checksum ws 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "329d3e6dd450a9c5c73024e1047f0be7e24121a68484eb0b5368977bee3cf8c3" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +"checksum x25519-dalek 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4aca1ba6bec2719576bd20dfe5b24d9359552e616d10bff257e50cd85f745d17" "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.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "56626765982b12c2f4b59529e1d2ce0a7c25499865e6edf8b502dceb51b65fe2" +"checksum yamux 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "302defd1bed8a9a6d43b82f0e5a50510dfdfbbd02c270c93ff9d6f3f5e2dea89" +"checksum zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8ddfeb6eee2fb3b262ef6e0898a52b7563bb8e0d5955a313b3cf2f808246ea14" diff --git a/Cargo.toml b/Cargo.toml index 68d3985384a23fc10be67c562c68fdea6126158f..a0c5dc4be190d94fe953159999e73e38cc8641e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ path = "node/src/main.rs" [package] name = "substrate" -version = "0.10.0" +version = "0.11.0" authors = ["Parity Technologies "] build = "build.rs" edition = "2018" @@ -57,6 +57,7 @@ members = [ "srml/support/procedural", "srml/support/procedural/tools", "srml/support/procedural/tools/derive", + "srml/support/test", "srml/assets", "srml/aura", "srml/balances", @@ -66,7 +67,7 @@ members = [ "srml/democracy", "srml/example", "srml/executive", - "srml/fees", + "srml/finality-tracker", "srml/grandpa", "srml/indices", "srml/metadata", @@ -76,7 +77,6 @@ members = [ "srml/system", "srml/timestamp", "srml/treasury", - "srml/upgrade-key", "node/cli", "node/executor", "node/primitives", @@ -103,5 +103,8 @@ panic = "unwind" [patch.crates-io] trie-db = { path = "../parity-trie/trie-db" } +trie-root = { path = "../parity-trie/trie-root" } hash-db = { path = "../parity-trie/hash-db" } memory-db = { path = "../parity-trie/memory-db" } +trie-bench = { path = "../parity-trie/test-support/trie-bench" } +hash256-std-hasher = { path = "../parity-trie/hash256-std-hasher" } diff --git a/README.adoc b/README.adoc index 4c3fdaf6cc63389052aa8862068426461c8baa82..90961cbb0f4958d302d35ce2917253cbcfaf9d77 100644 --- a/README.adoc +++ b/README.adoc @@ -237,11 +237,13 @@ Then build the code: cargo build # Builds all native code ---- -You can run the tests if you like: +You can run all the tests if you like: [source, shell] cargo test --all +Or just run the tests of a specific package (i.e. `cargo test -p srml-assets`) + You can start a development chain with: [source, shell] @@ -257,8 +259,7 @@ We'll start Alice's substrate node first on default TCP port 30333 with her chai cargo run --release \-- \ --base-path /tmp/alice \ --chain=local \ - --key Alice \ - --name "ALICE" \ + --alice \ --node-key 0000000000000000000000000000000000000000000000000000000000000001 \ --telemetry-url ws://telemetry.polkadot.io:1024 \ --validator @@ -270,8 +271,7 @@ cargo run --release \-- \ --base-path /tmp/bob \ --bootnodes /ip4/127.0.0.1/tcp/30333/p2p/QmQZ8TjTqeDj3ciwr93EJ95hxfDsb9pEYDizUAbWpigtQN \ --chain=local \ - --key Bob \ - --name "BOB" \ + --bob \ --port 30334 \ --telemetry-url ws://telemetry.polkadot.io:1024 \ --validator diff --git a/build.rs b/build.rs index 7dd666310f77449dcc2605bd58b50cef763722a4..273700c525c883579880be28b231a5f14e43c6d7 100644 --- a/build.rs +++ b/build.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// Copyright 2015-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ use vergen::{ConstantsFlags, generate_cargo_keys}; -const ERROR_MSG: &'static str = "Failed to generate metadata files"; +const ERROR_MSG: &str = "Failed to generate metadata files"; fn main() { generate_cargo_keys(ConstantsFlags::all()).expect(ERROR_MSG); diff --git a/core/basic-authorship/Cargo.toml b/core/basic-authorship/Cargo.toml index 82187db8031f853dd0518e2c2aaf3d9e185803e2..d173ac66ee2439da99f2257663c030bbe58c13e3 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.0" } +codec = { package = "parity-codec", version = "3.2" } 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" } @@ -14,6 +14,7 @@ consensus_common = { package = "substrate-consensus-common", path = "../../core/ primitives = { package = "substrate-primitives", path = "../../core/primitives" } inherents = { package = "substrate-inherents", path = "../inherents" } transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" } +substrate-telemetry = { path = "../telemetry" } [dev-dependencies] test-client = { package = "substrate-test-client", path = "../../core/test-client" } diff --git a/core/basic-authorship/src/basic_authorship.rs b/core/basic-authorship/src/basic_authorship.rs index 728ef3c0679952e263d451d13effd52474f125ac..55b45c1c4502d951c8bcf19ad2b9199037b28bdf 100644 --- a/core/basic-authorship/src/basic_authorship.rs +++ b/core/basic-authorship/src/basic_authorship.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -20,7 +20,7 @@ // use std::{self, time, sync::Arc}; -use log::{info, debug}; +use log::{info, debug, warn, trace}; use client::{ self, error, Client as SubstrateClient, CallExecutor, @@ -28,15 +28,15 @@ use client::{ }; use codec::Decode; use consensus_common::{self, evaluation}; -use primitives::{H256, Blake2Hasher}; +use primitives::{H256, Blake2Hasher, ExecutionContext}; use runtime_primitives::traits::{ Block as BlockT, Hash as HashT, Header as HeaderT, ProvideRuntimeApi, AuthorityIdFor }; -use runtime_primitives::ExecutionContext; use runtime_primitives::generic::BlockId; use runtime_primitives::ApplyError; use transaction_pool::txpool::{self, Pool as TransactionPool}; -use inherents::InherentData; +use inherents::{InherentData, pool::InherentsPool}; +use substrate_telemetry::{telemetry, CONSENSUS_INFO}; /// Build new blocks. pub trait BlockBuilder { @@ -114,6 +114,8 @@ pub struct ProposerFactory where A: txpool::ChainApi { pub client: Arc, /// The transaction pool. pub transaction_pool: Arc>, + /// The inherents pool + pub inherents_pool: Arc::Extrinsic>>, } impl consensus_common::Environment<::Block> for ProposerFactory where @@ -143,6 +145,7 @@ impl consensus_common::Environment<::Block> for Propose parent_id: id, parent_number: *parent_header.number(), transaction_pool: self.transaction_pool.clone(), + inherents_pool: self.inherents_pool.clone(), now: Box::new(time::Instant::now), }; @@ -157,6 +160,7 @@ pub struct Proposer { parent_id: BlockId, parent_number: <::Header as HeaderT>::Number, transaction_pool: Arc>, + inherents_pool: Arc::Extrinsic>>, now: Box time::Instant>, } @@ -200,17 +204,30 @@ impl Proposer where &self.parent_id, inherent_data, |block_builder| { + // Add inherents from the internal pool + + let inherents = self.inherents_pool.drain(); + debug!("Pushing {} queued inherents.", inherents.len()); + for i in inherents { + if let Err(e) = block_builder.push_extrinsic(i) { + warn!("Error while pushing inherent extrinsic from the pool: {:?}", e); + } + } + + // proceed with transactions let mut is_first = true; let mut skipped = 0; let mut unqueue_invalid = Vec::new(); let pending_iterator = self.transaction_pool.ready(); + debug!("Attempting to push transactions from the pool."); for pending in pending_iterator { if (self.now)() > deadline { debug!("Consensus deadline reached when pushing block transactions, proceeding with proposing."); break; } + trace!("[{:?}] Pushing to the block.", pending.hash); match block_builder.push_extrinsic(pending.data.clone()) { Ok(()) => { debug!("[{:?}] Pushed to the block.", pending.hash); @@ -252,6 +269,10 @@ impl Proposer where .collect::>() .join(", ") ); + telemetry!(CONSENSUS_INFO; "prepared_block_for_proposing"; + "number" => ?block.header().number(), + "hash" => ?<::Block as BlockT>::Hash::from(block.header().hash()), + ); let substrate_block = Decode::decode(&mut block.encode().as_slice()) .expect("blocks are defined to serialize to substrate blocks correctly; qed"); @@ -273,17 +294,16 @@ mod tests { use codec::Encode; use std::cell::RefCell; use consensus_common::{Environment, Proposer}; - use test_client::keyring::Keyring; - use test_client::{self, runtime::{Extrinsic, Transfer}}; + use test_client::{self, runtime::{Extrinsic, Transfer}, AccountKeyring}; fn extrinsic(nonce: u64) -> Extrinsic { let tx = Transfer { amount: Default::default(), nonce, - from: Keyring::Alice.to_raw_public().into(), + from: AccountKeyring::Alice.into(), to: Default::default(), }; - let signature = Keyring::from_raw_public(tx.from.to_fixed_bytes()).unwrap().sign(&tx.encode()).into(); + let signature = AccountKeyring::from_public(&tx.from).unwrap().sign(&tx.encode()).into(); Extrinsic::Transfer(tx, signature) } @@ -299,6 +319,7 @@ mod tests { let proposer_factory = ProposerFactory { client: client.clone(), transaction_pool: txpool.clone(), + inherents_pool: Default::default(), }; let mut proposer = proposer_factory.init( @@ -321,4 +342,32 @@ mod tests { assert_eq!(txpool.ready().count(), 2); } + #[test] + fn should_include_inherents_from_the_pool() { + // given + let client = Arc::new(test_client::new()); + let chain_api = transaction_pool::ChainApi::new(client.clone()); + let txpool = Arc::new(TransactionPool::new(Default::default(), chain_api)); + let inpool = Arc::new(InherentsPool::default()); + + let proposer_factory = ProposerFactory { + client: client.clone(), + transaction_pool: txpool.clone(), + inherents_pool: inpool.clone(), + }; + + inpool.add(extrinsic(0)); + + let proposer = proposer_factory.init( + &client.header(&BlockId::number(0)).unwrap().unwrap(), + &[] + ).unwrap(); + + // when + let deadline = time::Duration::from_secs(3); + let block = proposer.propose(Default::default(), deadline).unwrap(); + + // then + assert_eq!(block.extrinsics().len(), 1); + } } diff --git a/core/basic-authorship/src/lib.rs b/core/basic-authorship/src/lib.rs index a4f6afb8f86102ce137eb99cf5d85802c28d8e89..88a55c3bac4fa22bb21e42e9c66398a6e286b575 100644 --- a/core/basic-authorship/src/lib.rs +++ b/core/basic-authorship/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/cli/Cargo.toml b/core/cli/Cargo.toml index fa117969026a6c30cad62aa6859e2eb48393a9d1..c5bf34063d8066fff85fd6954b3d67c52399f9e8 100644 --- a/core/cli/Cargo.toml +++ b/core/cli/Cargo.toml @@ -14,12 +14,13 @@ atty = "0.2" regex = "1" time = "0.1" ansi_term = "0.11" -lazy_static = "1.0" +lazy_static = "1.3" app_dirs = "1.2" tokio = "0.1.7" futures = "0.1.17" fdlimit = "0.1" exit-future = "0.1" +serde_json = "1.0" sysinfo = "0.8.0" panic-handler = { package = "substrate-panic-handler", path = "../../core/panic-handler" } client = { package = "substrate-client", path = "../../core/client" } @@ -29,5 +30,9 @@ primitives = { package = "substrate-primitives", path = "../../core/primitives" service = { package = "substrate-service", path = "../../core/service" } state-machine = { package = "substrate-state-machine", path = "../../core/state-machine" } substrate-telemetry = { path = "../../core/telemetry" } +keyring = { package = "substrate-keyring", path = "../keyring" } names = "0.11.0" structopt = "0.2" + +[dev-dependencies] +tempdir = "0.3" diff --git a/core/cli/src/error.rs b/core/cli/src/error.rs index b9a036ce1c7a2e02550be81f16317c858f54e124..e368cc6d9670a59adaf2975de4f69421948fbb14 100644 --- a/core/cli/src/error.rs +++ b/core/cli/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/cli/src/informant.rs b/core/cli/src/informant.rs index e6de9d5b634cab4312698311c929ae5ec1709995..260615b2c1cb626429c14e95cc51baceda08d4b1 100644 --- a/core/cli/src/informant.rs +++ b/core/cli/src/informant.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -17,44 +17,41 @@ //! Console informant. Prints sync progress and block events. Runs on the calling thread. use ansi_term::Colour; -use std::{fmt, time::{Duration, Instant}}; +use std::fmt; +use std::time; use futures::{Future, Stream}; use service::{Service, Components}; use tokio::runtime::TaskExecutor; -use tokio::timer::Interval; use sysinfo::{get_current_pid, ProcessExt, System, SystemExt}; use network::{SyncState, SyncProvider}; use client::{backend::Backend, BlockchainEvents}; -use substrate_telemetry::telemetry; -use log::{debug, info, warn}; +use substrate_telemetry::{telemetry, SUBSTRATE_INFO}; +use log::{info, warn}; use runtime_primitives::generic::BlockId; use runtime_primitives::traits::{Header, As}; -const TIMER_INTERVAL_MS: u64 = 5000; - /// Spawn informant on the event loop pub fn start(service: &Service, exit: ::exit_future::Exit, handle: TaskExecutor) where C: Components, { - let interval = Interval::new(Instant::now(), Duration::from_millis(TIMER_INTERVAL_MS)); - let network = service.network(); let client = service.client(); let txpool = service.transaction_pool(); let mut last_number = None; + let mut last_update = time::Instant::now(); let mut sys = System::new(); let self_pid = get_current_pid(); - let display_notifications = interval.map_err(|e| debug!("Timer error: {:?}", e)).for_each(move |_| { - let sync_status = network.status(); + let display_notifications = network.status().for_each(move |sync_status| { if let Ok(info) = client.info() { let best_number: u64 = info.chain.best_number.as_(); let best_hash = info.chain.best_hash; let num_peers = sync_status.num_peers; - let speed = move || speed(best_number, last_number); + 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) { (SyncState::Idle, _) => ("Idle".into(), "".into()), (SyncState::Downloading, None) => (format!("Syncing{}", speed()), "".into()), @@ -85,8 +82,12 @@ pub fn start(service: &Service, exit: ::exit_future::Exit, handle: TaskExe (proc.cpu_usage(), proc.memory()) } else { (0.0, 0) }; + let network_state = serde_json::to_string(&network.network_state()).unwrap_or_default(); + telemetry!( + SUBSTRATE_INFO; "system.interval"; + "network_state" => network_state, "status" => format!("{}{}", status, target), "peers" => num_peers, "height" => best_number, @@ -144,7 +145,7 @@ pub fn start(service: &Service, exit: ::exit_future::Exit, handle: TaskExe let txpool = service.transaction_pool(); let display_txpool_import = txpool.import_notification_stream().for_each(move |_| { let status = txpool.status(); - telemetry!("txpool.import"; "ready" => status.ready, "future" => status.future); + telemetry!(SUBSTRATE_INFO; "txpool.import"; "ready" => status.ready, "future" => status.future); Ok(()) }); @@ -152,9 +153,11 @@ pub fn start(service: &Service, exit: ::exit_future::Exit, handle: TaskExe handle.spawn(exit.until(informant_work).map(|_| ())); } -fn speed(best_number: u64, last_number: Option) -> String { +fn speed(best_number: u64, last_number: Option, last_update: time::Instant) -> String { + let since_last_millis = last_update.elapsed().as_secs() * 1000; + let since_last_subsec_millis = last_update.elapsed().subsec_millis() as u64; let speed = match last_number { - Some(num) => (best_number.saturating_sub(num) * 10_000 / TIMER_INTERVAL_MS) as f64, + Some(num) => (best_number.saturating_sub(num) * 10_000 / (since_last_millis + since_last_subsec_millis)) as f64, None => 0.0 }; diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index 76fb7a31cdbbe53192e2cb365820e82eb869ebad..8fa133ea797f5afab1ed245493b4b9472084001f 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -32,7 +32,8 @@ use service::{ FactoryGenesis, PruningMode, ChainSpec, }; use network::{ - Protocol, config::{NetworkConfiguration, NonReservedPeerMode, Secret}, + self, multiaddr::Protocol, + config::{NetworkConfiguration, NonReservedPeerMode, NodeKeyConfig}, build_multiaddr, }; use primitives::H256; @@ -50,6 +51,7 @@ pub use structopt::clap::App; use params::{ RunCmd, PurgeChainCmd, RevertCmd, ImportBlocksCmd, ExportBlocksCmd, BuildSpecCmd, NetworkConfigurationParams, SharedParams, MergeParameters, TransactionPoolParams, + NodeKeyParams, NodeKeyType }; pub use params::{NoCustom, CoreParams}; pub use traits::{GetLogFilter, AugmentClap}; @@ -59,8 +61,20 @@ use log::info; use lazy_static::lazy_static; use futures::Future; +use substrate_telemetry::TelemetryEndpoints; -const MAX_NODE_NAME_LENGTH: usize = 32; +/// The maximum number of characters for a node name. +const NODE_NAME_MAX_LENGTH: usize = 32; + +/// The file name of the node's Secp256k1 secret key inside the chain-specific +/// network config directory, if neither `--node-key` nor `--node-key-file` +/// is specified in combination with `--node-key-type=secp256k1`. +const NODE_KEY_SECP256K1_FILE: &str = "secret"; + +/// The file name of the node's Ed25519 secret key inside the chain-specific +/// network config directory, if neither `--node-key` nor `--node-key-file` +/// is specified in combination with `--node-key-type=ed25519`. +const NODE_KEY_ED25519_FILE: &str = "secret_ed25519"; /// Executable version. Used to pass version information from the root crate. pub struct VersionInfo { @@ -100,7 +114,7 @@ fn generate_node_name() -> String { let node_name = Generator::with_naming(Name::Numbered).next().unwrap(); let count = node_name.chars().count(); - if count < MAX_NODE_NAME_LENGTH { + if count < NODE_NAME_MAX_LENGTH { break node_name } }; @@ -132,14 +146,14 @@ fn base_path(cli: &SharedParams, version: &VersionInfo) -> PathBuf { ) } -fn create_input_err>(msg: T) -> error::Error { +fn input_err>(msg: T) -> error::Error { error::ErrorKind::Input(msg.into()).into() } /// Check whether a node name is considered as valid fn is_node_name_valid(_name: &str) -> Result<(), &str> { let name = _name.to_string(); - if name.chars().count() >= MAX_NODE_NAME_LENGTH { + if name.chars().count() >= NODE_NAME_MAX_LENGTH { return Err("Node name too long"); } @@ -230,14 +244,60 @@ where } } -fn parse_node_key(key: Option) -> error::Result> { - match key.map(|k| H256::from_str(&k)) { - Some(Ok(secret)) => Ok(Some(secret.into())), - Some(Err(err)) => Err(create_input_err(format!("Error parsing node key: {}", err))), - None => Ok(None), +/// Create a `NodeKeyConfig` from the given `NodeKeyParams` in the context +/// of an optional network config storage directory. +fn node_key_config

(params: NodeKeyParams, net_config_dir: &Option

) + -> error::Result +where + P: AsRef +{ + match params.node_key_type { + NodeKeyType::Secp256k1 => + 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(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(NodeKeyConfig::Ed25519) } } +fn net_config_file

(net_config_dir: &Option

, name: &str) -> Option +where + P: AsRef +{ + net_config_dir.as_ref().map(|d| d.as_ref().join(name)) +} + +/// Create an error caused by an invalid node key argument. +fn invalid_node_key(e: impl std::fmt::Display) -> error::Error { + input_err(format!("Invalid node key: {}", e)) +} + +/// Parse a Secp256k1 secret key from a hex string into a `network::Secret`. +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) + .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 { + H256::from_str(&hex).map_err(invalid_node_key).and_then(|bytes| + network::identity::ed25519::SecretKey::from_bytes(bytes) + .map(network::Secret::Input) + .map_err(invalid_node_key)) +} + /// Fill the given `PoolConfiguration` by looking at the cli parameters. fn fill_transaction_pool_configuration( options: &mut FactoryFullConfiguration, @@ -294,7 +354,7 @@ fn fill_network_configuration( config.public_addresses = Vec::new(); config.client_version = client_id; - config.use_secret = parse_node_key(cli.node_key)?; + config.node_key = node_key_config(cli.node_key_params, &config.net_config_path)?; config.in_peers = cli.in_peers; config.out_peers = cli.out_peers; @@ -316,14 +376,14 @@ where config.impl_commit = version.commit; config.impl_version = version.version; - config.name = match cli.name { + config.name = match cli.name.or(cli.keyring.account.map(|a| a.to_string())) { None => generate_node_name(), Some(name) => name, }; match is_node_name_valid(&config.name) { Ok(_) => (), Err(msg) => bail!( - create_input_err( + input_err( format!("Invalid node name '{}'. Reason: {}. If unsure, use none.", config.name, msg @@ -346,7 +406,7 @@ where Some(ref s) if s == "archive" => PruningMode::ArchiveAll, None => PruningMode::default(), Some(s) => PruningMode::keep_blocks( - s.parse().map_err(|_| create_input_err("Invalid pruning mode specified"))? + s.parse().map_err(|_| input_err("Invalid pruning mode specified"))? ), }; @@ -359,14 +419,25 @@ where service::Roles::FULL }; + let exec = cli.execution_strategies; config.execution_strategies = ExecutionStrategies { - syncing: cli.syncing_execution.into(), - importing: cli.importing_execution.into(), - block_construction: cli.block_construction_execution.into(), - other: cli.other_execution.into(), + 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(), + }; + + config.offchain_worker = match (cli.offchain_worker, role) { + (params::OffchainWorkerEnabled::WhenValidating, service::Roles::AUTHORITY) => true, + (params::OffchainWorkerEnabled::Always, _) => true, + (params::OffchainWorkerEnabled::Never, _) => false, + (params::OffchainWorkerEnabled::WhenValidating, _) => false, }; config.roles = role; + config.disable_grandpa = cli.no_grandpa; + let client_id = config.client_id(); fill_network_configuration( cli.network_config, @@ -386,7 +457,11 @@ where } if cli.shared_params.dev { - config.keys.push("Alice".into()); + config.keys.push("//Alice".into()); + } + + if let Some(account) = cli.keyring.account { + config.keys.push(format!("//{}", account)); } let rpc_interface: &str = if cli.rpc_external { "0.0.0.0" } else { "127.0.0.1" }; @@ -401,11 +476,13 @@ where // Override telemetry if cli.no_telemetry { - config.telemetry_url = None; - } else if let Some(url) = cli.telemetry_url { - config.telemetry_url = Some(url); + config.telemetry_endpoints = None; + } else if !cli.telemetry_endpoints.is_empty() { + config.telemetry_endpoints = Some(TelemetryEndpoints::new(cli.telemetry_endpoints)); } + config.force_authoring = cli.force_authoring; + Ok(config) } @@ -438,23 +515,19 @@ where // 9926-9949 Unassigned fn with_default_boot_node( - mut spec: ChainSpec>, - cli: &BuildSpecCmd, + spec: &mut ChainSpec>, + cli: BuildSpecCmd, version: &VersionInfo, -) -> error::Result>> +) -> error::Result<()> where F: ServiceFactory { if spec.boot_nodes().is_empty() { - let network_path = - Some(network_path(&base_path(&cli.shared_params, version), spec.id()).to_string_lossy().into()); - let network_key = parse_node_key(cli.node_key.clone())?; - - let network_keys = - network::obtain_private_key(&network_key, &network_path) - .map_err(|err| format!("Error obtaining network key: {}", err))?; - - let peer_id = network_keys.to_peer_id(); + let base_path = base_path(&cli.shared_params, version); + let storage_path = network_path(&base_path, spec.id()); + let node_key = node_key_config(cli.node_key_params, &Some(storage_path))?; + let keys = node_key.into_keypair()?; + let peer_id = keys.public().into_peer_id(); let addr = build_multiaddr![ Ip4([127, 0, 0, 1]), Tcp(30333u16), @@ -462,7 +535,7 @@ where ]; spec.add_boot_node(addr) } - Ok(spec) + Ok(()) } fn build_spec( @@ -475,9 +548,10 @@ where S: FnOnce(&str) -> Result>>, String>, { info!("Building chain spec"); - let spec = load_spec(&cli.shared_params, spec_factory)?; - let spec = with_default_boot_node::(spec, &cli, version)?; - let json = service::chain_ops::build_spec::>(spec, cli.raw)?; + let raw_output = cli.raw; + let mut spec = load_spec(&cli.shared_params, spec_factory)?; + with_default_boot_node::(&mut spec, cli, version)?; + let json = service::chain_ops::build_spec::>(spec, raw_output)?; print!("{}", json); @@ -573,23 +647,28 @@ where S: FnOnce(&str) -> Result>>, String>, { let config = create_config_with_db_path::(spec_factory, &cli.shared_params, version)?; - let db_path = config.database_path; - print!("Are you sure to remove {:?}? (y/n)", &db_path); - stdout().flush().expect("failed to flush stdout"); - - let mut input = String::new(); - stdin().read_line(&mut input)?; - let input = input.trim(); - - match input.chars().nth(0) { - Some('y') | Some('Y') => { - fs::remove_dir_all(&db_path)?; - println!("{:?} removed.", &db_path); - }, - _ => println!("Aborted"), + + if cli.yes == false { + print!("Are you sure to remove {:?}? (y/n)", &db_path); + stdout().flush().expect("failed to flush stdout"); + + let mut input = String::new(); + stdin().read_line(&mut input)?; + let input = input.trim(); + + match input.chars().nth(0) { + Some('y') | Some('Y') => {}, + _ => { + println!("Aborted"); + return Ok(()); + }, + } } + fs::remove_dir_all(&db_path)?; + println!("{:?} removed.", &db_path); + Ok(()) } @@ -697,6 +776,8 @@ fn kill_color(s: &str) -> String { #[cfg(test)] mod tests { use super::*; + use tempdir::TempDir; + use network::identity::{secp256k1, ed25519}; #[test] fn tests_node_name_good() { @@ -712,4 +793,111 @@ mod tests { assert!(is_node_name_valid("www.visit.me").is_err()); assert!(is_node_name_valid("email@domain").is_err()); } + + #[test] + fn test_node_key_config_input() { + fn secret_input(net_config_dir: Option) -> error::Result<()> { + NodeKeyType::variants().into_iter().try_for_each(|t| { + let node_key_type = NodeKeyType::from_str(t).unwrap(); + let sk = match node_key_type { + NodeKeyType::Secp256k1 => secp256k1::SecretKey::generate().as_ref().to_vec(), + NodeKeyType::Ed25519 => ed25519::SecretKey::generate().as_ref().to_vec() + }; + let params = NodeKeyParams { + node_key_type, + node_key: Some(format!("{:x}", H256::from_slice(sk.as_ref()))), + node_key_file: None + }; + node_key_config(params, &net_config_dir).and_then(|c| match c { + NodeKeyConfig::Secp256k1(network::Secret::Input(ref ski)) + if node_key_type == NodeKeyType::Secp256k1 && + &sk[..] == ski.as_ref() => Ok(()), + NodeKeyConfig::Ed25519(network::Secret::Input(ref ski)) + if node_key_type == NodeKeyType::Ed25519 && + &sk[..] == ski.as_ref() => Ok(()), + _ => Err(input_err("Unexpected node key config")) + }) + }) + } + + assert!(secret_input(None).is_ok()); + assert!(secret_input(Some("x".to_string())).is_ok()); + } + + #[test] + fn test_node_key_config_file() { + fn secret_file(net_config_dir: Option) -> error::Result<()> { + NodeKeyType::variants().into_iter().try_for_each(|t| { + let node_key_type = NodeKeyType::from_str(t).unwrap(); + let tmp = TempDir::new("alice")?; + let file = tmp.path().join(format!("{}_mysecret", t)).to_path_buf(); + let params = NodeKeyParams { + node_key_type, + node_key: None, + 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)) + if node_key_type == NodeKeyType::Secp256k1 && f == &file => Ok(()), + NodeKeyConfig::Ed25519(network::Secret::File(ref f)) + if node_key_type == NodeKeyType::Ed25519 && f == &file => Ok(()), + _ => Err(input_err("Unexpected node key config")) + }) + }) + } + + assert!(secret_file(None).is_ok()); + assert!(secret_file(Some("x".to_string())).is_ok()); + } + + #[test] + fn test_node_key_config_default() { + fn with_def_params(f: F) -> error::Result<()> + where + F: Fn(NodeKeyParams) -> error::Result<()> + { + NodeKeyType::variants().into_iter().try_for_each(|t| { + let node_key_type = NodeKeyType::from_str(t).unwrap(); + f(NodeKeyParams { + node_key_type, + node_key: None, + node_key_file: None + }) + }) + } + + fn no_config_dir() -> error::Result<()> { + with_def_params(|params| { + let typ = params.node_key_type; + node_key_config::(params, &None) + .and_then(|c| match c { + NodeKeyConfig::Secp256k1(network::Secret::New) + if typ == NodeKeyType::Secp256k1 => Ok(()), + NodeKeyConfig::Ed25519(network::Secret::New) + if typ == NodeKeyType::Ed25519 => Ok(()), + _ => Err(input_err("Unexpected node key config")) + }) + }) + } + + fn some_config_dir(net_config_dir: String) -> error::Result<()> { + with_def_params(|params| { + let dir = PathBuf::from(net_config_dir.clone()); + 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)) + if typ == NodeKeyType::Secp256k1 && + f == &dir.join(NODE_KEY_SECP256K1_FILE) => Ok(()), + NodeKeyConfig::Ed25519(network::Secret::File(ref f)) + if typ == NodeKeyType::Ed25519 && + f == &dir.join(NODE_KEY_ED25519_FILE) => Ok(()), + _ => Err(input_err("Unexpected node key config")) + }) + }) + } + + assert!(no_config_dir().is_ok()); + assert!(some_config_dir("x".to_string()).is_ok()); + } } diff --git a/core/cli/src/params.rs b/core/cli/src/params.rs index bd33c7f1f16b7dd86cdc40c920e4fe03bff74bc8..4c2fb5350279a97320d476965f40fe3b29138104 100644 --- a/core/cli/src/params.rs +++ b/core/cli/src/params.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ use crate::traits::{AugmentClap, GetLogFilter}; use std::path::PathBuf; -use structopt::{StructOpt, clap::{arg_enum, _clap_count_exprs, App, AppSettings, SubCommand}}; +use structopt::{StructOpt, clap::{arg_enum, _clap_count_exprs, App, AppSettings, SubCommand, Arg}}; use client; /// Auxialary macro to implement `GetLogFilter` for all types that have the `shared_params` field. @@ -39,6 +39,7 @@ arg_enum! { Wasm, Both, NativeElseWasm, + NativeWhenPossible, } } @@ -49,10 +50,21 @@ impl Into for ExecutionStrategy { ExecutionStrategy::Wasm => client::ExecutionStrategy::AlwaysWasm, ExecutionStrategy::Both => client::ExecutionStrategy::Both, ExecutionStrategy::NativeElseWasm => client::ExecutionStrategy::NativeElseWasm, + ExecutionStrategy::NativeWhenPossible => client::ExecutionStrategy::NativeWhenPossible, } } } +arg_enum! { + /// How to execute blocks + #[derive(Debug, Clone)] + pub enum OffchainWorkerEnabled { + Always, + Never, + WhenValidating, + } +} + /// Shared parameters used by all `CoreParams`. #[derive(Debug, StructOpt, Clone)] pub struct SharedParams { @@ -68,7 +80,7 @@ pub struct SharedParams { #[structopt(long = "base-path", short = "d", value_name = "PATH", parse(from_os_str))] pub base_path: Option, - ///Sets a custom logging filter + /// Sets a custom logging filter #[structopt(short = "l", long = "log", value_name = "LOG_PATTERN")] pub log: Option, } @@ -98,10 +110,6 @@ pub struct NetworkConfigurationParams { #[structopt(long = "port", value_name = "PORT")] pub port: Option, - /// Specify node secret key (64-character hex string) - #[structopt(long = "node-key", value_name = "KEY")] - pub node_key: Option, - /// Specify the number of outgoing connections we're trying to maintain #[structopt(long = "out-peers", value_name = "OUT_PEERS", default_value = "25")] pub out_peers: u32, @@ -109,6 +117,93 @@ pub struct NetworkConfigurationParams { /// Specify the maximum number of incoming connections we're accepting #[structopt(long = "in-peers", value_name = "IN_PEERS", default_value = "25")] pub in_peers: u32, + + #[allow(missing_docs)] + #[structopt(flatten)] + pub node_key_params: NodeKeyParams +} + +arg_enum! { + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + pub enum NodeKeyType { + Secp256k1, + Ed25519 + } +} + +/// Parameters used to create the `NodeKeyConfig`, which determines the keypair +/// used for libp2p networking. +#[derive(Debug, StructOpt, Clone)] +pub struct NodeKeyParams { + /// The secret key to use for libp2p networking. + /// + /// The value is a string that is parsed according to the choice of + /// `--node-key-type` as follows: + /// + /// `secp256k1`: + /// The value is parsed as a hex-encoded Secp256k1 32 bytes secret key, + /// i.e. 64 hex characters. + /// + /// `ed25519`: + /// The value is parsed as a hex-encoded Ed25519 32 bytes secret key, + /// i.e. 64 hex characters. + /// + /// The value of this option takes precedence over `--node-key-file`. + /// + /// WARNING: Secrets provided as command-line arguments are easily exposed. + /// Use of this option should be limited to development and testing. To use + /// an externally managed secret key, use `--node-key-file` instead. + #[structopt(long = "node-key", value_name = "KEY")] + pub node_key: Option, + + /// The type of secret key to use for libp2p networking. + /// + /// The secret key of the node is obtained as follows: + /// + /// * If the `--node-key` option is given, the value is parsed as a secret key + /// according to the type. See the documentation for `--node-key`. + /// + /// * If the `--node-key-file` option is given, the secret key is read from the + /// specified file. See the documentation for `--node-key-file`. + /// + /// * Otherwise, the secret key is read from a file with a predetermined, + /// type-specific name from the chain-specific network config directory + /// inside the base directory specified by `--base-dir`. If this file does + /// not exist, it is created with a newly generated secret key of the + /// chosen type. + /// + /// The node's secret key determines the corresponding public key and hence the + /// node's peer ID in the context of libp2p. + /// + /// NOTE: The current default key type is `secp256k1` for a transition period only + /// but will eventually change to `ed25519` in a future release. To continue using + /// `secp256k1` keys, use `--node-key-type=secp256k1`. + #[structopt( + long = "node-key-type", + value_name = "TYPE", + raw( + possible_values = "&NodeKeyType::variants()", + case_insensitive = "true", + default_value = r#""Secp256k1""# + ) + )] + pub node_key_type: NodeKeyType, + + /// The file from which to read the node's secret key to use for libp2p networking. + /// + /// The contents of the file are parsed according to the choice of `--node-key-type` + /// as follows: + /// + /// `secp256k1`: + /// The file must contain an unencoded 32 bytes Secp256k1 secret key. + /// + /// `ed25519`: + /// The file must contain an unencoded 32 bytes Ed25519 secret key. + /// + /// If the file does not exist, it is created with a newly generated secret key of + /// the chosen type. + #[structopt(long = "node-key-file", value_name = "FILE")] + pub node_key_file: Option } /// Parameters used to create the pool configuration. @@ -122,6 +217,70 @@ pub struct TransactionPoolParams { pub pool_kbytes: usize, } +/// Execution strategies parameters. +#[derive(Debug, StructOpt, Clone)] +pub struct ExecutionStrategies { + /// The means of execution used when calling into the runtime while syncing blocks. + #[structopt( + long = "syncing-execution", + value_name = "STRATEGY", + raw( + possible_values = "&ExecutionStrategy::variants()", + case_insensitive = "true", + default_value = r#""NativeElseWasm""# + ) + )] + pub syncing_execution: ExecutionStrategy, + + /// The means of execution used when calling into the runtime while importing blocks. + #[structopt( + long = "importing-execution", + value_name = "STRATEGY", + raw( + possible_values = "&ExecutionStrategy::variants()", + case_insensitive = "true", + default_value = r#""NativeElseWasm""# + ) + )] + pub importing_execution: ExecutionStrategy, + + /// The means of execution used when calling into the runtime while constructing blocks. + #[structopt( + long = "block-construction-execution", + value_name = "STRATEGY", + raw( + possible_values = "&ExecutionStrategy::variants()", + case_insensitive = "true", + default_value = r#""Wasm""# + ) + )] + pub block_construction_execution: ExecutionStrategy, + + /// The means of execution used when calling into the runtime while constructing blocks. + #[structopt( + long = "offchain-worker-execution", + value_name = "STRATEGY", + raw( + possible_values = "&ExecutionStrategy::variants()", + case_insensitive = "true", + default_value = r#""NativeWhenPossible""# + ) + )] + pub offchain_worker_execution: ExecutionStrategy, + + /// The means of execution used when calling into the runtime while not syncing, importing or constructing blocks. + #[structopt( + long = "other-execution", + value_name = "STRATEGY", + raw( + possible_values = "&ExecutionStrategy::variants()", + case_insensitive = "true", + default_value = r#""Wasm""# + ) + )] + pub other_execution: ExecutionStrategy, +} + /// The `run` command used to run a node. #[derive(Debug, StructOpt, Clone)] pub struct RunCmd { @@ -137,6 +296,10 @@ pub struct RunCmd { #[structopt(long = "validator")] pub validator: bool, + /// Disable GRANDPA when running in validator mode + #[structopt(long = "no-grandpa")] + pub no_grandpa: bool, + /// Run in light client mode #[structopt(long = "light")] pub light: bool, @@ -169,63 +332,33 @@ pub struct RunCmd { #[structopt(long = "name", value_name = "NAME")] pub name: Option, - /// Should not connect to the Substrate telemetry server (telemetry is on by default on global chains) + /// Disable connecting to the Substrate telemetry server (telemetry is on by default on global chains). #[structopt(long = "no-telemetry")] pub no_telemetry: bool, - /// The URL of the telemetry server to connect to - #[structopt(long = "telemetry-url", value_name = "TELEMETRY_URL")] - pub telemetry_url: Option, - - /// The means of execution used when calling into the runtime while syncing blocks. - #[structopt( - long = "syncing-execution", - value_name = "STRATEGY", - raw( - possible_values = "&ExecutionStrategy::variants()", - case_insensitive = "true", - default_value = r#""NativeElseWasm""# - ) - )] - pub syncing_execution: ExecutionStrategy, - - /// The means of execution used when calling into the runtime while importing blocks. - #[structopt( - long = "importing-execution", - value_name = "STRATEGY", - raw( - possible_values = "&ExecutionStrategy::variants()", - case_insensitive = "true", - default_value = r#""NativeElseWasm""# - ) - )] - pub importing_execution: ExecutionStrategy, + /// The URL of the telemetry server to connect to. This flag can be passed multiple times + /// as a mean to specify multiple telemetry endpoints. Verbosity levels range from 0-9, with + /// 0 denoting the least verbosity. If no verbosity level is specified the default is 0. + #[structopt(long = "telemetry-url", value_name = "URL VERBOSITY", parse(try_from_str = "parse_telemetry_endpoints"))] + pub telemetry_endpoints: Vec<(String, u8)>, - /// The means of execution used when calling into the runtime while constructing blocks. + /// Should execute offchain workers on every block. By default it's only enabled for nodes that are authoring new + /// blocks. #[structopt( - long = "block-construction-execution", - value_name = "STRATEGY", + long = "offchain-worker", + value_name = "ENABLED", raw( - possible_values = "&ExecutionStrategy::variants()", + possible_values = "&OffchainWorkerEnabled::variants()", case_insensitive = "true", - default_value = r#""Wasm""# + default_value = r#""WhenValidating""# ) )] - pub block_construction_execution: ExecutionStrategy, + pub offchain_worker: OffchainWorkerEnabled, - /// The means of execution used when calling into the runtime while not syncing, importing or constructing blocks. - #[structopt( - long = "other-execution", - value_name = "STRATEGY", - raw( - possible_values = "&ExecutionStrategy::variants()", - case_insensitive = "true", - default_value = r#""Wasm""# - ) - )] - pub other_execution: ExecutionStrategy, + #[allow(missing_docs)] + #[structopt(flatten)] + pub execution_strategies: ExecutionStrategies, - #[allow(missing_docs)] #[structopt(flatten)] pub shared_params: SharedParams, @@ -237,6 +370,99 @@ pub struct RunCmd { #[allow(missing_docs)] #[structopt(flatten)] pub pool_config: TransactionPoolParams, + + #[allow(missing_docs)] + #[structopt(flatten)] + pub keyring: Keyring, + + /// Enable authoring even when offline. + #[structopt(long = "force-authoring")] + pub force_authoring: bool, +} + +/// Stores all required Cli values for a keyring test account. +struct KeyringTestAccountCliValues { + help: String, + conflicts_with: Vec, + name: String, + variant: keyring::AuthorityKeyring, +} + +lazy_static::lazy_static! { + /// The Cli values for all test accounts. + static ref TEST_ACCOUNTS_CLI_VALUES: Vec = { + keyring::AuthorityKeyring::iter().map(|a| { + let help = format!("Shortcut for `--key //{} --name {}`.", a, a); + 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())) + .collect::>(); + let name = a.to_string().to_lowercase(); + + KeyringTestAccountCliValues { + help, + conflicts_with, + name, + variant: a, + } + }).collect() + }; +} + +/// Wrapper for exposing the keyring test accounts into the Cli. +#[derive(Debug, Clone)] +pub struct Keyring { + pub account: Option, +} + +impl StructOpt for Keyring { + fn clap<'a, 'b>() -> App<'a, 'b> { + unimplemented!("Should not be called for `TestAccounts`.") + } + + fn from_clap(m: &::structopt::clap::ArgMatches) -> Self { + Keyring { + account: TEST_ACCOUNTS_CLI_VALUES.iter().find(|a| m.is_present(&a.name)).map(|a| a.variant), + } + } +} + +impl AugmentClap for Keyring { + fn augment_clap<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + TEST_ACCOUNTS_CLI_VALUES.iter().fold(app, |app, a| { + let conflicts_with_strs = a.conflicts_with.iter().map(|s| s.as_str()).collect::>(); + + app.arg( + Arg::with_name(&a.name) + .long(&a.name) + .help(&a.help) + .conflicts_with_all(&conflicts_with_strs) + .takes_value(false) + ) + }) + } +} + +impl Keyring { + fn is_subcommand() -> bool { + false + } +} + +/// Default to verbosity level 0, if none is provided. +fn parse_telemetry_endpoints(s: &str) -> Result<(String, u8), Box> { + let pos = s.find(' '); + match pos { + None => { + Ok((s.to_owned(), 0)) + }, + Some(pos_) => { + let verbosity = s[pos_ + 1..].parse()?; + let url = s[..pos_].parse()?; + Ok((url, verbosity)) + } + } } impl_augment_clap!(RunCmd); @@ -253,9 +479,9 @@ pub struct BuildSpecCmd { #[structopt(flatten)] pub shared_params: SharedParams, - /// Specify node secret key (64-character hex string) - #[structopt(long = "node-key", value_name = "KEY")] - pub node_key: Option, + #[allow(missing_docs)] + #[structopt(flatten)] + pub node_key_params: NodeKeyParams, } impl_get_log_filter!(BuildSpecCmd); @@ -321,6 +547,10 @@ impl_get_log_filter!(RevertCmd); /// The `purge-chain` command used to remove the whole chain. #[derive(Debug, StructOpt, Clone)] pub struct PurgeChainCmd { + /// Skip interactive prompt by answering yes automatically. + #[structopt(short = "y")] + pub yes: bool, + #[allow(missing_docs)] #[structopt(flatten)] pub shared_params: SharedParams, diff --git a/core/client/Cargo.toml b/core/client/Cargo.toml index bc2911a0ae29579a296149f1dab6e9171ae3abaf..0f0eca441ad1b816fcc45bf0228edd031bc2094b 100644 --- a/core/client/Cargo.toml +++ b/core/client/Cargo.toml @@ -18,10 +18,9 @@ state-machine = { package = "substrate-state-machine", path = "../state-machine" 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.11", optional = true } +hash-db = { version = "0.12", default-features = false } kvdb = { git = "https://github.com/paritytech/parity-common", optional = true, rev="b0317f649ab2c665b7987b8475878fc4d2e1f81d" } -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", 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 } @@ -36,11 +35,14 @@ kvdb-memorydb = { git = "https://github.com/paritytech/parity-common", rev="b031 [features] default = ["std"] std = [ + "rstd/std", "parity-codec/std", - "parity-codec-derive/std", - "consensus", "primitives/std", "inherents/std", + "runtime-primitives/std", + "runtime-version/std", + "hash-db/std", + "consensus", "parking_lot", "error-chain", "fnv", @@ -49,13 +51,9 @@ std = [ "futures", "heapsize", "executor", - "runtime-primitives/std", - "runtime-version/std", - "rstd/std", "state-machine", "keyring", "trie", "substrate-telemetry", - "hash-db", "kvdb" ] diff --git a/core/client/db/Cargo.toml b/core/client/db/Cargo.toml index 6408fa0dc80b3716ffd8d50b02c834a3b6d95aa0..7fc1cc5d9575018a462dd731277600de8cf442b5 100644 --- a/core/client/db/Cargo.toml +++ b/core/client/db/Cargo.toml @@ -12,13 +12,12 @@ kvdb = { git = "https://github.com/paritytech/parity-common", rev="b0317f649ab2c kvdb-rocksdb = { git = "https://github.com/paritytech/parity-common", rev="b0317f649ab2c665b7987b8475878fc4d2e1f81d" } kvdb-memorydb = { git = "https://github.com/paritytech/parity-common", rev="b0317f649ab2c665b7987b8475878fc4d2e1f81d", optional = true } lru-cache = "0.1.1" -hash-db = { version = "0.11" } +hash-db = { version = "0.12" } 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 = "3.0" -parity-codec-derive = "3.0" +parity-codec = { version = "3.2", 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 f8e52e14c630f07b421eaff4b69ca1bd0071c4fc..1e641534f969c0d63eefe387e98c9ded8bb3c81a 100644 --- a/core/client/db/src/cache/list_cache.rs +++ b/core/client/db/src/cache/list_cache.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/client/db/src/cache/list_entry.rs b/core/client/db/src/cache/list_entry.rs index b54094fa00deb3b6a5a8e1a8b02297de2b42a7f2..237ae9a268026744b87f6d85b7c6301cb82ee204 100644 --- a/core/client/db/src/cache/list_entry.rs +++ b/core/client/db/src/cache/list_entry.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -18,7 +18,7 @@ use client::error::Result as ClientResult; use runtime_primitives::traits::{Block as BlockT, NumberFor}; -use parity_codec_derive::{Encode, Decode}; +use parity_codec::{Encode, Decode}; use crate::cache::{CacheItemT, ComplexBlockId}; use crate::cache::list_storage::{Storage}; diff --git a/core/client/db/src/cache/list_storage.rs b/core/client/db/src/cache/list_storage.rs index b9bf99f67b884fba4ae85f358cb9c0b731cb834b..659a30507e136576a844624fa167eb1cfb08ddb9 100644 --- a/core/client/db/src/cache/list_storage.rs +++ b/core/client/db/src/cache/list_storage.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/client/db/src/cache/mod.rs b/core/client/db/src/cache/mod.rs index 8df8e42518347e05019b2571febb78b58b536ce2..3d669e392d01c86fc4c6666aec40728c950862ef 100644 --- a/core/client/db/src/cache/mod.rs +++ b/core/client/db/src/cache/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -24,7 +24,6 @@ use kvdb::{KeyValueDB, DBTransaction}; use client::blockchain::Cache as BlockchainCache; use client::error::Result as ClientResult; use parity_codec::{Encode, Decode}; -use parity_codec_derive::{Encode, Decode}; use runtime_primitives::generic::BlockId; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, NumberFor, As, AuthorityIdFor}; use crate::utils::{self, COLUMN_META}; diff --git a/core/client/db/src/lib.rs b/core/client/db/src/lib.rs index 99483b428882c5617746c8864944f6e8468bb4c8..93adb990240a629550ab73c4e0caa19a0185f38a 100644 --- a/core/client/db/src/lib.rs +++ b/core/client/db/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -40,7 +40,7 @@ use client::ExecutionStrategies; use parity_codec::{Decode, Encode}; use hash_db::Hasher; use kvdb::{KeyValueDB, DBTransaction}; -use trie::MemoryDB; +use trie::{MemoryDB, PrefixedMemoryDB, prefixed_key}; use parking_lot::RwLock; use primitives::{H256, Blake2Hasher, ChangesTrieConfiguration, convert_hash}; use primitives::storage::well_known_keys; @@ -51,7 +51,7 @@ use state_machine::backend::Backend as StateBackend; use executor::RuntimeInfo; use state_machine::{CodeExecutor, DBValue}; use crate::utils::{Meta, db_err, meta_keys, open_database, read_db, block_id_to_lookup_key, read_meta}; -use client::LeafSet; +use client::leaves::{LeafSet, FinalizationDisplaced}; use client::children; use state_db::StateDb; use crate::storage_cache::{CachingState, SharedCache, new_shared_cache}; @@ -259,7 +259,7 @@ impl client::blockchain::Backend for BlockchainDb { /// Database transaction pub struct BlockImportOperation { old_state: CachingState, - db_updates: MemoryDB, + db_updates: PrefixedMemoryDB, storage_updates: Vec<(Vec, Option>)>, changes_trie_updates: MemoryDB, pending_block: Option>, @@ -310,7 +310,7 @@ where Block: BlockT, // currently authorities are not cached on full nodes } - fn update_db_storage(&mut self, update: MemoryDB) -> Result<(), client::error::Error> { + fn update_db_storage(&mut self, update: PrefixedMemoryDB) -> Result<(), client::error::Error> { self.db_updates = update; Ok(()) } @@ -321,7 +321,7 @@ where Block: BlockT, return Err(client::error::ErrorKind::GenesisInvalid.into()); } - let mut transaction: MemoryDB = Default::default(); + let mut transaction: PrefixedMemoryDB = Default::default(); for (child_key, child_map) in children { if !well_known_keys::is_child_storage_key(&child_key) { @@ -374,22 +374,23 @@ where Block: BlockT, struct StorageDb { pub db: Arc, - pub state_db: StateDb, + pub state_db: StateDb>, } impl state_machine::Storage for StorageDb { - fn get(&self, key: &H256) -> Result, String> { - self.state_db.get(key, self).map(|r| r.map(|v| DBValue::from_slice(&v))) + fn get(&self, key: &H256, prefix: &[u8]) -> Result, String> { + let key = prefixed_key::(key, prefix); + self.state_db.get(&key, self).map(|r| r.map(|v| DBValue::from_slice(&v))) .map_err(|e| format!("Database backend error: {:?}", e)) } } -impl state_db::HashDb for StorageDb { +impl state_db::NodeDb for StorageDb { type Error = io::Error; - type Hash = H256; + type Key = [u8]; - fn get(&self, key: &H256) -> Result>, Self::Error> { - self.db.get(columns::STATE, key.as_bytes()).map(|r| r.map(|v| v.to_vec())) + fn get(&self, key: &[u8]) -> Result>, Self::Error> { + self.db.get(columns::STATE, key).map(|r| r.map(|v| v.to_vec())) } } @@ -405,7 +406,7 @@ impl DbGenesisStorage { } impl state_machine::Storage for DbGenesisStorage { - fn get(&self, _key: &H256) -> Result, String> { + fn get(&self, _key: &H256, _prefix: &[u8]) -> Result, String> { Ok(None) } } @@ -515,7 +516,7 @@ impl state_machine::ChangesTrieRootsStorage for DbC } impl state_machine::ChangesTrieStorage for DbChangesTrieStorage { - fn get(&self, key: &H256) -> Result, String> { + fn get(&self, key: &H256, _prefix: &[u8]) -> Result, String> { self.db.get(columns::CHANGES_TRIE, &key[..]) .map_err(|err| format!("{}", err)) } @@ -559,7 +560,7 @@ impl> Backend { let blockchain = BlockchainDb::new(db.clone())?; let meta = blockchain.meta.clone(); let map_e = |e: state_db::Error| ::client::error::Error::from(format!("State database error: {:?}", e)); - let state_db: StateDb = StateDb::new(pruning, &StateMetaDb(&*db)).map_err(map_e)?; + let state_db: StateDb<_, _> = StateDb::new(pruning, &StateMetaDb(&*db)).map_err(map_e)?; let storage_db = StorageDb { db: db.clone(), state_db, @@ -714,11 +715,18 @@ impl> Backend { header: &Block::Header, last_finalized: Option, justification: Option, + finalization_displaced: &mut Option>>, ) -> Result<(Block::Hash, ::Number, bool, bool), client::error::Error> { // TODO: ensure best chain contains this block. let number = *header.number(); self.ensure_sequential_finalization(header, last_finalized)?; - self.note_finalized(transaction, header, *hash)?; + self.note_finalized( + transaction, + header, + *hash, + finalization_displaced, + )?; + if let Some(justification) = justification { transaction.put( columns::JUSTIFICATION, @@ -767,10 +775,13 @@ impl> Backend { -> Result<(), client::error::Error> { let mut transaction = DBTransaction::new(); + let mut finalization_displaced_leaves = None; + operation.apply_aux(&mut transaction); let mut meta_updates = Vec::new(); let mut last_finalized_hash = self.blockchain.meta.read().finalized_hash; + if !operation.finalized_blocks.is_empty() { for (block, justification) in operation.finalized_blocks { let block_hash = self.blockchain.expect_block_hash_from_id(&block)?; @@ -782,6 +793,7 @@ impl> Backend { &block_header, Some(last_finalized_hash), justification, + &mut finalization_displaced_leaves, )?); last_finalized_hash = block_hash; } @@ -821,7 +833,7 @@ impl> Backend { transaction.put(columns::META, meta_keys::GENESIS_HASH, hash.as_ref()); } - let mut changeset: state_db::ChangeSet = state_db::ChangeSet::default(); + let mut changeset: state_db::ChangeSet> = state_db::ChangeSet::default(); for (key, (val, rc)) in operation.db_updates.drain() { if rc > 0 { changeset.inserted.push((key, val.to_vec())); @@ -846,7 +858,12 @@ impl> Backend { if finalized { // TODO: ensure best chain contains this block. self.ensure_sequential_finalization(header, Some(last_finalized_hash))?; - self.note_finalized(&mut transaction, header, hash)?; + self.note_finalized( + &mut transaction, + header, + hash, + &mut finalization_displaced_leaves, + )?; } else { // canonicalize blocks which are old enough, regardless of finality. self.force_delayed_canonicalize(&mut transaction, hash, *header.number())? @@ -892,9 +909,16 @@ impl> Backend { if let Some((number, hash, enacted, retracted, displaced_leaf, is_best)) = imported { if let Err(e) = write_result { + let mut leaves = self.blockchain.leaves.write(); + let mut undo = leaves.undo(); if let Some(displaced_leaf) = displaced_leaf { - self.blockchain.leaves.write().undo(displaced_leaf); + undo.undo_import(displaced_leaf); + } + + if let Some(finalization_displaced) = finalization_displaced_leaves { + undo.undo_finalization(finalization_displaced); } + return Err(e) } @@ -924,6 +948,7 @@ impl> Backend { transaction: &mut DBTransaction, f_header: &Block::Header, f_hash: Block::Hash, + displaced: &mut Option>> ) -> Result<(), client::error::Error> where Block: BlockT, { @@ -947,11 +972,17 @@ impl> Backend { self.changes_tries_storage.prune(changes_trie_config, transaction, f_hash, f_num); } + let new_displaced = self.blockchain.leaves.write().finalize_height(f_num); + match displaced { + x @ &mut None => *x = Some(new_displaced), + &mut Some(ref mut displaced) => displaced.merge(new_displaced), + } + Ok(()) } } -fn apply_state_commit(transaction: &mut DBTransaction, commit: state_db::CommitSet) { +fn apply_state_commit(transaction: &mut DBTransaction, commit: state_db::CommitSet>) { for (key, val) in commit.data.inserted.into_iter() { transaction.put(columns::STATE, &key[..], &val); } @@ -1001,7 +1032,7 @@ impl client::backend::Backend for Backend whe Ok(BlockImportOperation { pending_block: None, old_state, - db_updates: MemoryDB::default(), + db_updates: PrefixedMemoryDB::default(), storage_updates: Default::default(), changes_trie_updates: MemoryDB::default(), aux_ops: Vec::new(), @@ -1036,22 +1067,27 @@ impl client::backend::Backend for Backend whe let mut transaction = DBTransaction::new(); let hash = self.blockchain.expect_block_hash_from_id(&block)?; let header = self.blockchain.expect_header(block)?; - let commit = || { + let mut displaced = None; + let commit = |displaced| { let (hash, number, is_best, is_finalized) = self.finalize_block_with_transaction( &mut transaction, &hash, &header, None, justification, + displaced, )?; self.storage.db.write(transaction).map_err(db_err)?; self.blockchain.update_meta(hash, number, is_best, is_finalized); Ok(()) }; - match commit() { + match commit(&mut displaced) { Ok(()) => self.storage.state_db.apply_pending(), e @ Err(_) => { self.storage.state_db.revert_pending(); + if let Some(displaced) = displaced { + self.blockchain.leaves.write().undo().undo_finalization(displaced); + } return e; } } @@ -1134,6 +1170,10 @@ impl client::backend::Backend for Backend whe } } + fn have_state_at(&self, hash: &Block::Hash, number: NumberFor) -> bool { + !self.storage.state_db.is_pruned(hash, number.as_()) + } + fn destroy_state(&self, mut state: Self::State) -> Result<(), client::error::Error> { if let Some(hash) = state.parent_hash.clone() { let is_best = || self.blockchain.meta.read().best_hash == hash; @@ -1152,6 +1192,7 @@ mod tests { use super::*; use crate::columns; use client::backend::Backend as BTrait; + use client::blockchain::Backend as BLBTrait; use client::backend::BlockImportOperation as Op; use runtime_primitives::testing::{Header, Block as RawBlock, ExtrinsicWrapper}; use runtime_primitives::traits::{Hash, BlakeTwo256}; @@ -1374,7 +1415,7 @@ mod tests { op.reset_storage(storage.iter().cloned().collect(), Default::default()).unwrap(); - key = op.db_updates.insert(b"hello"); + key = op.db_updates.insert(&[], b"hello"); op.set_block_data( header, Some(vec![]), @@ -1408,8 +1449,8 @@ mod tests { ).0.into(); let hash = header.hash(); - op.db_updates.insert(b"hello"); - op.db_updates.remove(&key); + op.db_updates.insert(&[], b"hello"); + op.db_updates.remove(&key, &[]); op.set_block_data( header, Some(vec![]), @@ -1443,7 +1484,7 @@ mod tests { ).0.into(); let hash = header.hash(); - op.db_updates.remove(&key); + op.db_updates.remove(&key, &[]); op.set_block_data( header, Some(vec![]), @@ -1509,7 +1550,7 @@ mod tests { assert_eq!(backend.changes_tries_storage.root(&anchor, block), Ok(Some(changes_root))); for (key, (val, _)) in changes_trie_update.drain() { - assert_eq!(backend.changes_trie_storage().unwrap().get(&key), Ok(Some(val))); + assert_eq!(backend.changes_trie_storage().unwrap().get(&key, &[]), Ok(Some(val))); } }; @@ -1635,23 +1676,23 @@ mod tests { let mut tx = DBTransaction::new(); backend.changes_tries_storage.prune(Some(config.clone()), &mut tx, Default::default(), 12); backend.storage.db.write(tx).unwrap(); - assert!(backend.changes_tries_storage.get(&root1).unwrap().is_none()); - assert!(backend.changes_tries_storage.get(&root2).unwrap().is_none()); - assert!(backend.changes_tries_storage.get(&root3).unwrap().is_none()); - assert!(backend.changes_tries_storage.get(&root4).unwrap().is_none()); - assert!(backend.changes_tries_storage.get(&root5).unwrap().is_some()); - assert!(backend.changes_tries_storage.get(&root6).unwrap().is_some()); - assert!(backend.changes_tries_storage.get(&root7).unwrap().is_some()); - assert!(backend.changes_tries_storage.get(&root8).unwrap().is_some()); + assert!(backend.changes_tries_storage.get(&root1, &[]).unwrap().is_none()); + assert!(backend.changes_tries_storage.get(&root2, &[]).unwrap().is_none()); + assert!(backend.changes_tries_storage.get(&root3, &[]).unwrap().is_none()); + assert!(backend.changes_tries_storage.get(&root4, &[]).unwrap().is_none()); + assert!(backend.changes_tries_storage.get(&root5, &[]).unwrap().is_some()); + assert!(backend.changes_tries_storage.get(&root6, &[]).unwrap().is_some()); + assert!(backend.changes_tries_storage.get(&root7, &[]).unwrap().is_some()); + assert!(backend.changes_tries_storage.get(&root8, &[]).unwrap().is_some()); // now simulate finalization of block#16, causing prune of tries at #5..#8 let mut tx = DBTransaction::new(); backend.changes_tries_storage.prune(Some(config.clone()), &mut tx, Default::default(), 16); backend.storage.db.write(tx).unwrap(); - assert!(backend.changes_tries_storage.get(&root5).unwrap().is_none()); - assert!(backend.changes_tries_storage.get(&root6).unwrap().is_none()); - assert!(backend.changes_tries_storage.get(&root7).unwrap().is_none()); - assert!(backend.changes_tries_storage.get(&root8).unwrap().is_none()); + assert!(backend.changes_tries_storage.get(&root5, &[]).unwrap().is_none()); + assert!(backend.changes_tries_storage.get(&root6, &[]).unwrap().is_none()); + assert!(backend.changes_tries_storage.get(&root7, &[]).unwrap().is_none()); + assert!(backend.changes_tries_storage.get(&root8, &[]).unwrap().is_none()); // now "change" pruning mode to archive && simulate finalization of block#20 // => no changes tries are pruned, because we never prune in archive mode @@ -1659,10 +1700,10 @@ mod tests { let mut tx = DBTransaction::new(); backend.changes_tries_storage.prune(Some(config), &mut tx, Default::default(), 20); backend.storage.db.write(tx).unwrap(); - assert!(backend.changes_tries_storage.get(&root9).unwrap().is_some()); - assert!(backend.changes_tries_storage.get(&root10).unwrap().is_some()); - assert!(backend.changes_tries_storage.get(&root11).unwrap().is_some()); - assert!(backend.changes_tries_storage.get(&root12).unwrap().is_some()); + assert!(backend.changes_tries_storage.get(&root9, &[]).unwrap().is_some()); + assert!(backend.changes_tries_storage.get(&root10, &[]).unwrap().is_some()); + assert!(backend.changes_tries_storage.get(&root11, &[]).unwrap().is_some()); + assert!(backend.changes_tries_storage.get(&root12, &[]).unwrap().is_some()); } #[test] @@ -1701,15 +1742,15 @@ mod tests { let mut tx = DBTransaction::new(); backend.changes_tries_storage.prune(Some(config.clone()), &mut tx, block5, 5); backend.storage.db.write(tx).unwrap(); - assert!(backend.changes_tries_storage.get(&root1).unwrap().is_none()); - assert!(backend.changes_tries_storage.get(&root2).unwrap().is_some()); + assert!(backend.changes_tries_storage.get(&root1, &[]).unwrap().is_none()); + assert!(backend.changes_tries_storage.get(&root2, &[]).unwrap().is_some()); // now simulate finalization of block#6, causing prune of tries at #2 let mut tx = DBTransaction::new(); backend.changes_tries_storage.prune(Some(config.clone()), &mut tx, block6, 6); backend.storage.db.write(tx).unwrap(); - assert!(backend.changes_tries_storage.get(&root2).unwrap().is_none()); - assert!(backend.changes_tries_storage.get(&root3).unwrap().is_some()); + assert!(backend.changes_tries_storage.get(&root2, &[]).unwrap().is_none()); + assert!(backend.changes_tries_storage.get(&root3, &[]).unwrap().is_some()); } #[test] @@ -1789,8 +1830,6 @@ mod tests { BlockId::Hash(block1), ).unwrap(); - println!("{:?}", tree_route); - assert_eq!(tree_route.common_block().hash, block0); assert!(tree_route.retracted().is_empty()); assert_eq!(tree_route.enacted().iter().map(|r| r.hash).collect::>(), vec![block1]); @@ -1815,6 +1854,30 @@ mod tests { test_client::trait_tests::test_blockchain_query_by_number_gets_canonical(backend); } + #[test] + fn test_leaves_pruned_on_finality() { + let backend: Backend = Backend::new_test(10, 10); + let block0 = insert_header(&backend, 0, Default::default(), Default::default(), Default::default()); + + let block1_a = insert_header(&backend, 1, block0, Default::default(), Default::default()); + let block1_b = insert_header(&backend, 1, block0, Default::default(), [1; 32].into()); + let block1_c = insert_header(&backend, 1, block0, Default::default(), [2; 32].into()); + + assert_eq!(backend.blockchain().leaves().unwrap(), vec![block1_a, block1_b, block1_c]); + + let block2_a = insert_header(&backend, 2, block1_a, Default::default(), Default::default()); + let block2_b = insert_header(&backend, 2, block1_b, Default::default(), Default::default()); + let block2_c = insert_header(&backend, 2, block1_b, Default::default(), [1; 32].into()); + + assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2_a, block2_b, block2_c, block1_c]); + + backend.finalize_block(BlockId::hash(block1_a), None).unwrap(); + backend.finalize_block(BlockId::hash(block2_a), None).unwrap(); + + // leaves at same height stay. Leaves at lower heights pruned. + assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2_a, block2_b, block2_c]); + } + #[test] fn test_aux() { let backend: Backend = Backend::new_test(0, 0); diff --git a/core/client/db/src/light.rs b/core/client/db/src/light.rs index b86ebb93ef70de950548befa01a65421e94d12f7..d99ef503b2f81047d341140233b51d17160d0bdb 100644 --- a/core/client/db/src/light.rs +++ b/core/client/db/src/light.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -24,7 +24,8 @@ use kvdb::{KeyValueDB, DBTransaction}; use client::backend::{AuxStore, NewBlockState}; use client::blockchain::{BlockStatus, Cache as BlockchainCache, HeaderBackend as BlockchainHeaderBackend, Info as BlockchainInfo}; -use client::{cht, LeafSet}; +use client::cht; +use client::leaves::{LeafSet, FinalizationDisplaced}; use client::error::{ErrorKind as ClientErrorKind, Result as ClientResult}; use client::light::blockchain::Storage as LightBlockchainStorage; use parity_codec::{Decode, Encode}; @@ -250,6 +251,7 @@ impl LightStorage { transaction: &mut DBTransaction, header: &Block::Header, hash: Block::Hash, + displaced: &mut Option>>, ) -> ClientResult<()> { let meta = self.meta.read(); if &meta.finalized_hash != header.parent_hash() { @@ -311,6 +313,12 @@ impl LightStorage { } } + let new_displaced = self.leaves.write().finalize_height(header.number().clone()); + match displaced { + x @ &mut None => *x = Some(new_displaced), + &mut Some(ref mut displaced) => displaced.merge(new_displaced), + } + Ok(()) } @@ -366,6 +374,7 @@ impl LightBlockchainStorage for LightStorage leaf_state: NewBlockState, aux_ops: Vec<(Vec, Option>)>, ) -> ClientResult<()> { + let mut finalization_displaced_leaves = None; let mut transaction = DBTransaction::new(); let hash = header.hash(); @@ -394,18 +403,24 @@ impl LightBlockchainStorage for LightStorage ); transaction.put(columns::HEADER, &lookup_key, &header.encode()); - if number.is_zero() { - transaction.put(columns::META, meta_keys::FINALIZED_BLOCK, &lookup_key); + let is_genesis = number.is_zero(); + if is_genesis { transaction.put(columns::META, meta_keys::GENESIS_HASH, hash.as_ref()); } let finalized = match leaf_state { + _ if is_genesis => true, NewBlockState::Final => true, _ => false, }; if finalized { - self.note_finalized(&mut transaction, &header, hash)?; + self.note_finalized( + &mut transaction, + &header, + hash, + &mut finalization_displaced_leaves, + )?; } { @@ -425,10 +440,18 @@ impl LightBlockchainStorage for LightStorage debug!("Light DB Commit {:?} ({})", hash, number); let write_result = self.db.write(transaction).map_err(db_err); if let Err(e) = write_result { + let mut leaves = self.leaves.write(); + let mut undo = leaves.undo(); + // revert leaves set update if there was one. if let Some(displaced_leaf) = displaced_leaf { - leaves.undo(displaced_leaf); + undo.undo_import(displaced_leaf); } + + if let Some(finalization_displaced) = finalization_displaced_leaves { + undo.undo_finalization(finalization_displaced); + } + return Err(e); } @@ -464,10 +487,11 @@ impl LightBlockchainStorage for LightStorage fn finalize_header(&self, id: BlockId) -> ClientResult<()> { if let Some(header) = self.header(id)? { + let mut displaced = None; let mut transaction = DBTransaction::new(); let hash = header.hash(); let number = *header.number(); - self.note_finalized(&mut transaction, &header, hash.clone())?; + self.note_finalized(&mut transaction, &header, hash.clone(), &mut displaced)?; { let mut cache = self.cache.0.write(); let cache_ops = cache.transaction(&mut transaction) @@ -477,7 +501,12 @@ impl LightBlockchainStorage for LightStorage )? .into_ops(); - self.db.write(transaction).map_err(db_err)?; + if let Err(e) = self.db.write(transaction).map_err(db_err) { + if let Some(displaced) = displaced { + self.leaves.write().undo().undo_finalization(displaced); + } + return Err(e); + } cache.commit(cache_ops); } self.update_meta(hash, header.number().clone(), false, true); @@ -512,6 +541,7 @@ pub(crate) mod tests { use super::*; type Block = RawBlock>; + type AuthorityId = AuthorityIdFor; pub fn default_header(parent: &Hash, number: u64) -> Header { Header { @@ -802,10 +832,10 @@ pub(crate) mod tests { let checks = vec![ (0, None), (1, None), - (2, Some(vec![[1u8; 32].into()])), - (3, Some(vec![[1u8; 32].into()])), - (4, Some(vec![[1u8; 32].into(), [2u8; 32].into()])), - (5, Some(vec![[1u8; 32].into(), [2u8; 32].into()])), + (2, Some(vec![AuthorityId::from_raw([1u8; 32])])), + (3, Some(vec![AuthorityId::from_raw([1u8; 32])])), + (4, Some(vec![AuthorityId::from_raw([1u8; 32]), AuthorityId::from_raw([2u8; 32])])), + (5, Some(vec![AuthorityId::from_raw([1u8; 32]), AuthorityId::from_raw([2u8; 32])])), (6, None), (7, None), // block will work for 'future' block too ]; @@ -814,13 +844,13 @@ pub(crate) mod tests { run_checks(&db, 0, &checks); let hash1 = insert_final_block(&db, None, || default_header(&hash0, 1)); run_checks(&db, 1, &checks); - let hash2 = insert_final_block(&db, Some(vec![[1u8; 32].into()]), || default_header(&hash1, 2)); + let hash2 = insert_final_block(&db, Some(vec![AuthorityId::from_raw([1u8; 32])]), || default_header(&hash1, 2)); run_checks(&db, 2, &checks); - let hash3 = insert_final_block(&db, Some(vec![[1u8; 32].into()]), || default_header(&hash2, 3)); + let hash3 = insert_final_block(&db, Some(vec![AuthorityId::from_raw([1u8; 32])]), || default_header(&hash2, 3)); run_checks(&db, 3, &checks); - let hash4 = insert_final_block(&db, Some(vec![[1u8; 32].into(), [2u8; 32].into()]), || default_header(&hash3, 4)); + let hash4 = insert_final_block(&db, Some(vec![AuthorityId::from_raw([1u8; 32]), AuthorityId::from_raw([2u8; 32])]), || default_header(&hash3, 4)); run_checks(&db, 4, &checks); - let hash5 = insert_final_block(&db, Some(vec![[1u8; 32].into(), [2u8; 32].into()]), || default_header(&hash4, 5)); + let hash5 = insert_final_block(&db, Some(vec![AuthorityId::from_raw([1u8; 32]), AuthorityId::from_raw([2u8; 32])]), || default_header(&hash4, 5)); run_checks(&db, 5, &checks); let hash6 = insert_final_block(&db, None, || default_header(&hash5, 6)); run_checks(&db, 7, &checks); @@ -832,9 +862,9 @@ pub(crate) mod tests { // some older non-best blocks are inserted // ... -> B2(1) -> B2_1(1) -> B2_2(2) // => the cache ignores all writes before best finalized block - let hash2_1 = insert_non_best_block(&db, Some(vec![[1u8; 32].into()]), || default_header(&hash2, 3)); + let hash2_1 = insert_non_best_block(&db, Some(vec![AuthorityId::from_raw([1u8; 32])]), || default_header(&hash2, 3)); assert_eq!(None, db.cache().authorities_at(BlockId::Hash(hash2_1))); - let hash2_2 = insert_non_best_block(&db, Some(vec![[1u8; 32].into(), [2u8; 32].into()]), || default_header(&hash2_1, 4)); + let hash2_2 = insert_non_best_block(&db, Some(vec![AuthorityId::from_raw([1u8; 32]), AuthorityId::from_raw([2u8; 32])]), || default_header(&hash2_1, 4)); assert_eq!(None, db.cache().authorities_at(BlockId::Hash(hash2_2))); } @@ -845,39 +875,39 @@ pub(crate) mod tests { // \> B6_1_1(5) // \> B6_1_2(6) -> B6_1_3(7) - let hash7 = insert_block(&db, Some(vec![[3u8; 32].into()]), || default_header(&hash6, 7)); + let hash7 = insert_block(&db, Some(vec![AuthorityId::from_raw([3u8; 32])]), || default_header(&hash6, 7)); assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![[3u8; 32].into()])); - let hash8 = insert_block(&db, Some(vec![[3u8; 32].into()]), || default_header(&hash7, 8)); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])])); + let hash8 = insert_block(&db, Some(vec![AuthorityId::from_raw([3u8; 32])]), || default_header(&hash7, 8)); assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![[3u8; 32].into()])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![[3u8; 32].into()])); - let hash6_1 = insert_block(&db, Some(vec![[4u8; 32].into()]), || default_header(&hash6, 7)); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![AuthorityId::from_raw([3u8; 32])])); + let hash6_1 = insert_block(&db, Some(vec![AuthorityId::from_raw([4u8; 32])]), || default_header(&hash6, 7)); assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![[3u8; 32].into()])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![[3u8; 32].into()])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![[4u8; 32].into()])); - let hash6_1_1 = insert_non_best_block(&db, Some(vec![[5u8; 32].into()]), || default_header(&hash6_1, 8)); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![AuthorityId::from_raw([3u8; 32])])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])])); + let hash6_1_1 = insert_non_best_block(&db, Some(vec![AuthorityId::from_raw([5u8; 32])]), || default_header(&hash6_1, 8)); assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![[3u8; 32].into()])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![[3u8; 32].into()])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![[4u8; 32].into()])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![[5u8; 32].into()])); - let hash6_1_2 = insert_non_best_block(&db, Some(vec![[6u8; 32].into()]), || default_header(&hash6_1, 8)); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![AuthorityId::from_raw([3u8; 32])])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![AuthorityId::from_raw([5u8; 32])])); + let hash6_1_2 = insert_non_best_block(&db, Some(vec![AuthorityId::from_raw([6u8; 32])]), || default_header(&hash6_1, 8)); assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![[3u8; 32].into()])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![[3u8; 32].into()])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![[4u8; 32].into()])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![[5u8; 32].into()])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), Some(vec![[6u8; 32].into()])); - let hash6_2 = insert_block(&db, Some(vec![[4u8; 32].into()]), || default_header(&hash6_1, 8)); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![AuthorityId::from_raw([3u8; 32])])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![AuthorityId::from_raw([5u8; 32])])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), Some(vec![AuthorityId::from_raw([6u8; 32])])); + let hash6_2 = insert_block(&db, Some(vec![AuthorityId::from_raw([4u8; 32])]), || default_header(&hash6_1, 8)); assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![[3u8; 32].into()])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![[3u8; 32].into()])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![[4u8; 32].into()])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![[5u8; 32].into()])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), Some(vec![[6u8; 32].into()])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_2)), Some(vec![[4u8; 32].into()])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![AuthorityId::from_raw([3u8; 32])])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![AuthorityId::from_raw([5u8; 32])])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), Some(vec![AuthorityId::from_raw([6u8; 32])])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_2)), Some(vec![AuthorityId::from_raw([4u8; 32])])); (hash7, hash8, hash6_1, hash6_2, hash6_1_1, hash6_1_2) }; @@ -888,19 +918,19 @@ pub(crate) mod tests { assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), None); assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![[4u8; 32].into()])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![[5u8; 32].into()])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), Some(vec![[6u8; 32].into()])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_2)), Some(vec![[4u8; 32].into()])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![AuthorityId::from_raw([5u8; 32])])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), Some(vec![AuthorityId::from_raw([6u8; 32])])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_2)), Some(vec![AuthorityId::from_raw([4u8; 32])])); // finalize block hash6_2 db.finalize_header(BlockId::Hash(hash6_2)).unwrap(); assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), None); assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![[4u8; 32].into()])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])])); assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), None); assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_2)), Some(vec![[4u8; 32].into()])); + assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_2)), Some(vec![AuthorityId::from_raw([4u8; 32])])); } } @@ -940,4 +970,28 @@ pub(crate) mod tests { assert_eq!(db.get_aux(&[2]).unwrap(), Some(vec![102])); assert_eq!(db.get_aux(&[3]).unwrap(), Some(vec![103])); } + + #[test] + fn test_leaves_pruned_on_finality() { + let db = LightStorage::::new_test(); + let block0 = insert_block(&db, None, || default_header(&Default::default(), 0)); + + let block1_a = insert_block(&db, None, || default_header(&block0, 1)); + let block1_b = insert_block(&db, None, || header_with_extrinsics_root(&block0, 1, [1; 32].into())); + let block1_c = insert_block(&db, None, || header_with_extrinsics_root(&block0, 1, [2; 32].into())); + + assert_eq!(db.leaves.read().hashes(), vec![block1_a, block1_b, block1_c]); + + let block2_a = insert_block(&db, None, || default_header(&block1_a, 2)); + let block2_b = insert_block(&db, None, || header_with_extrinsics_root(&block1_b, 2, [1; 32].into())); + let block2_c = insert_block(&db, None, || header_with_extrinsics_root(&block1_b, 2, [2; 32].into())); + + assert_eq!(db.leaves.read().hashes(), vec![block2_a, block2_b, block2_c, block1_c]); + + db.finalize_header(BlockId::hash(block1_a)).unwrap(); + db.finalize_header(BlockId::hash(block2_a)).unwrap(); + + // leaves at same height stay. Leaves at lower heights pruned. + assert_eq!(db.leaves.read().hashes(), vec![block2_a, block2_b, block2_c]); + } } diff --git a/core/client/db/src/storage_cache.rs b/core/client/db/src/storage_cache.rs index da07aa4d5a923ebffd5c745438f75e1e399862e8..6cfdbdd09b53db4ea986965550d076831cd07eae 100644 --- a/core/client/db/src/storage_cache.rs +++ b/core/client/db/src/storage_cache.rs @@ -109,7 +109,7 @@ impl, B: Block> CachingState { } } - /// Propagate local cache into the shared cache and synchonize + /// Propagate local cache into the shared cache and synchronize /// the shared cache with the best block state. /// This function updates the shared cache by removing entries /// that are invalidated by chain reorganization. `sync_cache` diff --git a/core/client/db/src/utils.rs b/core/client/db/src/utils.rs index 150c1fdd98ccdef5b596735f2e523bd179a3a35f..ce843a93a2fa4531761d1f94925bb14a23d9f72a 100644 --- a/core/client/db/src/utils.rs +++ b/core/client/db/src/utils.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/client/src/backend.rs b/core/client/src/backend.rs index 7b1136c92951bec62dffa9ada5047db2653d703b..9b063177ff14bd4b66f0fcb55c8ae562a2a18b23 100644 --- a/core/client/src/backend.rs +++ b/core/client/src/backend.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -142,6 +142,10 @@ pub trait Backend: AuxStore + Send + Sync where fn blockchain(&self) -> &Self::Blockchain; /// Returns reference to changes trie storage. fn changes_trie_storage(&self) -> Option<&Self::ChangesTrieStorage>; + /// 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() + } /// Returns state backend with post-state of given block. fn state_at(&self, block: BlockId) -> error::Result; /// Destroy state and save any useful data, such as cache. diff --git a/core/client/src/block_builder/api.rs b/core/client/src/block_builder/api.rs index f0f9a231229b04b831ad26e62e937aee8090d111..8aad26277738152d940810518d3523de71de77cc 100644 --- a/core/client/src/block_builder/api.rs +++ b/core/client/src/block_builder/api.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -16,46 +16,10 @@ //! The runtime api for building blocks. -use runtime_primitives::{traits::Block as BlockT, ApplyResult, RuntimeString}; +use runtime_primitives::{traits::Block as BlockT, ApplyResult}; use rstd::vec::Vec; use sr_api_macros::decl_runtime_apis; pub use inherents::{InherentData, CheckInherentsResult}; -use parity_codec_derive::{Encode, Decode}; - -/// The old representation of the inherent data. -#[doc(hide)] -#[derive(Encode, Decode)] -pub struct OldInherentData { - /// Current timestamp. - pub timestamp: u64, - /// Blank report. - pub consensus: (), - /// Aura expected slot. Can take any value during block construction. - pub aura_expected_slot: u64, -} - -impl OldInherentData { - /// Create a new `BasicInherentData` instance. - pub fn new(timestamp: u64, expected_slot: u64) -> Self { - Self { - timestamp, - consensus: (), - aura_expected_slot: expected_slot, - } - } -} - -/// Error type used while checking inherents. -#[doc(hide)] -#[derive(Encode, PartialEq)] -#[cfg_attr(feature = "std", derive(Decode))] -pub enum OldCheckInherentError { - /// The inherents are generally valid but a delay until the given timestamp - /// is required. - ValidAtTimestamp(u64), - /// Some other error has occurred. - Other(RuntimeString), -} decl_runtime_apis! { /// The `BlockBuilder` api trait that provides required functions for building a block for a runtime. @@ -69,11 +33,6 @@ decl_runtime_apis! { fn inherent_extrinsics(inherent: InherentData) -> Vec<::Extrinsic>; /// Check that the inherents are valid. The inherent data will vary from chain to chain. fn check_inherents(block: Block, data: InherentData) -> CheckInherentsResult; - /// Check that the inherents are valid. The inherent data will vary from chain to chain. - /// - /// Old version that is used by the CC network. - #[changed_in(2)] - fn check_inherents(block: Block, data: OldInherentData) -> ::std::result::Result<(), OldCheckInherentError>; /// Generate a random seed. fn random_seed() -> ::Hash; } diff --git a/core/client/src/block_builder/block_builder.rs b/core/client/src/block_builder/block_builder.rs index 1cc3e4c1a9ee171848328d702ccba9eb403d2de0..63e18e827984e2e07adc2273770cea7d227a7c44 100644 --- a/core/client/src/block_builder/block_builder.rs +++ b/core/client/src/block_builder/block_builder.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -17,15 +17,15 @@ use super::api::BlockBuilder as BlockBuilderApi; use std::vec::Vec; use parity_codec::Encode; -use crate::blockchain::HeaderBackend; +use runtime_primitives::ApplyOutcome; +use runtime_primitives::generic::BlockId; use runtime_primitives::traits::{ Header as HeaderT, Hash, Block as BlockT, One, HashFor, ProvideRuntimeApi, ApiRef }; -use primitives::H256; -use runtime_primitives::generic::BlockId; +use primitives::{H256, ExecutionContext}; +use crate::blockchain::HeaderBackend; use crate::runtime_api::Core; use crate::error; -use runtime_primitives::{ApplyOutcome, ExecutionContext}; /// Utility for building new (valid) blocks from a stream of extrinsics. diff --git a/core/client/src/block_builder/mod.rs b/core/client/src/block_builder/mod.rs index f22f599ffdd9a2ae356bef3006aff19a4225bd2d..7f617044a42cf7cbb734f516a702591f60742c10 100644 --- a/core/client/src/block_builder/mod.rs +++ b/core/client/src/block_builder/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/client/src/blockchain.rs b/core/client/src/blockchain.rs index eb9ce1342eade2c58ef154d583a302f4ddb54987..a18c6e5d577a8bef1dbbacf53614869373f148e4 100644 --- a/core/client/src/blockchain.rs +++ b/core/client/src/blockchain.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/client/src/call_executor.rs b/core/client/src/call_executor.rs index 13ff478f3becb1ef271596256eb6659e1e47e1fd..0dad56be0740371ad01e74d6253adec89127346a 100644 --- a/core/client/src/call_executor.rs +++ b/core/client/src/call_executor.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -19,12 +19,12 @@ use parity_codec::{Encode, Decode}; use runtime_primitives::generic::BlockId; use runtime_primitives::traits::Block as BlockT; use state_machine::{ - self, OverlayedChanges, Ext, CodeExecutor, ExecutionManager, ExecutionStrategy + self, OverlayedChanges, Ext, CodeExecutor, ExecutionManager, ExecutionStrategy, NeverOffchainExt, }; use executor::{RuntimeVersion, RuntimeInfo, NativeVersion}; use hash_db::Hasher; use trie::MemoryDB; -use primitives::{H256, Blake2Hasher, NativeOrEncoded, NeverNativeValue}; +use primitives::{H256, Blake2Hasher, NativeOrEncoded, NeverNativeValue, OffchainExt}; use crate::backend; use crate::error; @@ -42,12 +42,15 @@ where /// Execute a call to a contract on top of state in a block of given hash. /// /// No changes are made. - fn call( + fn call< + O: OffchainExt, + >( &self, id: &BlockId, method: &str, call_data: &[u8], strategy: ExecutionStrategy, + side_effects_handler: Option<&mut O>, ) -> Result, error::Error>; /// Execute a contextual call on top of state in a block of a given hash. @@ -56,6 +59,7 @@ where /// Before executing the method, passed header is installed as the current header /// of the execution context. fn contextual_call< + O: OffchainExt, PB: Fn() -> error::Result, EM: Fn( Result, Self::Error>, @@ -73,6 +77,7 @@ where prepare_environment_block: PB, execution_manager: ExecutionManager, native_call: Option, + side_effects_handler: Option<&mut O>, ) -> error::Result> where ExecutionManager: Clone; /// Extract RuntimeVersion of given block @@ -84,6 +89,7 @@ where /// /// No changes are made. fn call_at_state< + O: OffchainExt, S: state_machine::Backend, F: FnOnce( Result, Self::Error>, @@ -98,6 +104,7 @@ where call_data: &[u8], manager: ExecutionManager, native_call: Option, + side_effects_handler: Option<&mut O>, ) -> Result<(NativeOrEncoded, S::Transaction, Option>), error::Error>; /// Execute a call to a contract on top of given state, gathering execution proof. @@ -140,7 +147,10 @@ pub struct LocalCallExecutor { impl LocalCallExecutor { /// Creates new instance of local call executor. pub fn new(backend: Arc, executor: E) -> Self { - LocalCallExecutor { backend, executor } + LocalCallExecutor { + backend, + executor, + } } } @@ -161,17 +171,19 @@ where { type Error = E::Error; - fn call(&self, + fn call(&self, id: &BlockId, method: &str, call_data: &[u8], - strategy: ExecutionStrategy + strategy: ExecutionStrategy, + side_effects_handler: Option<&mut O>, ) -> error::Result> { let mut changes = OverlayedChanges::default(); let state = self.backend.state_at(*id)?; let return_data = state_machine::new( &state, self.backend.changes_trie_storage(), + side_effects_handler, &mut changes, &self.executor, method, @@ -187,6 +199,7 @@ where } fn contextual_call< + O: OffchainExt, PB: Fn() -> error::Result, EM: Fn( Result, Self::Error>, @@ -204,6 +217,7 @@ where prepare_environment_block: PB, execution_manager: ExecutionManager, native_call: Option, + mut side_effects_handler: Option<&mut O>, ) -> Result, error::Error> where ExecutionManager: Clone { let state = self.backend.state_at(*at)?; if method != "Core_initialise_block" && initialised_block.map(|id| id != *at).unwrap_or(true) { @@ -211,6 +225,7 @@ where state_machine::new( &state, self.backend.changes_trie_storage(), + side_effects_handler.as_mut().map(|x| &mut **x), changes, &self.executor, "Core_initialise_block", @@ -226,6 +241,7 @@ where let result = state_machine::new( &state, self.backend.changes_trie_storage(), + side_effects_handler, changes, &self.executor, method, @@ -248,12 +264,13 @@ where fn runtime_version(&self, id: &BlockId) -> error::Result { let mut overlay = OverlayedChanges::default(); let state = self.backend.state_at(*id)?; - let mut ext = Ext::new(&mut overlay, &state, self.backend.changes_trie_storage()); + let mut ext = Ext::new(&mut overlay, &state, self.backend.changes_trie_storage(), NeverOffchainExt::new()); self.executor.runtime_version(&mut ext) .ok_or(error::ErrorKind::VersionInvalid.into()) } fn call_at_state< + O: OffchainExt, S: state_machine::Backend, F: FnOnce( Result, Self::Error>, @@ -268,10 +285,12 @@ where call_data: &[u8], manager: ExecutionManager, native_call: Option, + side_effects_handler: Option<&mut O>, ) -> error::Result<(NativeOrEncoded, S::Transaction, Option>)> { state_machine::new( state, self.backend.changes_trie_storage(), + side_effects_handler, changes, &self.executor, method, diff --git a/core/client/src/cht.rs b/core/client/src/cht.rs index 59377b532588ad2bce133c7aac526be6d207305a..d8e7ffbff33a74ab65539913fa9f23839422660f 100644 --- a/core/client/src/cht.rs +++ b/core/client/src/cht.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/client/src/client.rs b/core/client/src/client.rs index 99f276ea2bbaf59015c8b8f242cd6b6507324386..699bbcad8dfe1c9397c0a8a53da43f43066d6480 100644 --- a/core/client/src/client.rs +++ b/core/client/src/client.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -27,15 +27,15 @@ use runtime_primitives::{ }; use consensus::{ Error as ConsensusError, ErrorKind as ConsensusErrorKind, ImportBlock, ImportResult, - BlockOrigin, ForkChoiceStrategy + BlockOrigin, ForkChoiceStrategy, }; use runtime_primitives::traits::{ Block as BlockT, Header as HeaderT, Zero, As, NumberFor, CurrentHeight, BlockNumberToHash, ApiRef, ProvideRuntimeApi, Digest, DigestItem, AuthorityIdFor }; -use runtime_primitives::{BuildStorage, ExecutionContext}; +use runtime_primitives::BuildStorage; use crate::runtime_api::{CallRuntimeAt, ConstructRuntimeApi}; -use primitives::{Blake2Hasher, H256, ChangesTrieConfiguration, convert_hash, NeverNativeValue}; +use primitives::{Blake2Hasher, H256, ChangesTrieConfiguration, convert_hash, NeverNativeValue, ExecutionContext}; use primitives::storage::{StorageKey, StorageData}; use primitives::storage::well_known_keys; use parity_codec::{Encode, Decode}; @@ -43,7 +43,7 @@ use state_machine::{ DBValue, Backend as StateBackend, CodeExecutor, ChangesTrieAnchorBlockId, ExecutionStrategy, ExecutionManager, prove_read, ChangesTrieRootsStorage, ChangesTrieStorage, - key_changes, key_changes_proof, OverlayedChanges, + key_changes, key_changes_proof, OverlayedChanges, NeverOffchainExt, }; use hash_db::Hasher; @@ -61,7 +61,7 @@ use crate::in_mem; use crate::block_builder::{self, api::BlockBuilder as BlockBuilderAPI}; use crate::genesis; use consensus; -use substrate_telemetry::telemetry; +use substrate_telemetry::{telemetry, SUBSTRATE_INFO}; use log::{info, trace, warn}; use error_chain::bail; @@ -84,6 +84,8 @@ pub struct ExecutionStrategies { pub importing: ExecutionStrategy, /// Execution strategy used when constructing blocks. pub block_construction: ExecutionStrategy, + /// Execution strategy used for offchain workers. + pub offchain_worker: ExecutionStrategy, /// Execution strategy used in other cases. pub other: ExecutionStrategy, } @@ -94,6 +96,7 @@ impl Default for ExecutionStrategies { syncing: ExecutionStrategy::NativeElseWasm, importing: ExecutionStrategy::NativeElseWasm, block_construction: ExecutionStrategy::AlwaysWasm, + offchain_worker: ExecutionStrategy::NativeWhenPossible, other: ExecutionStrategy::NativeElseWasm, } } @@ -167,8 +170,10 @@ pub struct ClientInfo { pub enum BlockStatus { /// Added to the import queue. Queued, - /// Already in the blockchain. - InChain, + /// Already in the blockchain and the state is available. + InChainWithState, + /// In the blockchain, but the state is not available. + InChainPruned, /// Block or parent is known to be bad. KnownBad, /// Not in the queue or the blockchain. @@ -341,7 +346,7 @@ impl Client where pub fn authorities_at(&self, id: &BlockId) -> error::Result>> { match self.backend.blockchain().cache().and_then(|cache| cache.authorities_at(*id)) { Some(cached_value) => Ok(cached_value), - None => self.executor.call(id, "Core_authorities", &[], ExecutionStrategy::NativeElseWasm) + None => self.executor.call(id, "Core_authorities", &[], ExecutionStrategy::NativeElseWasm, NeverOffchainExt::new()) .and_then(|r| Vec::>::decode(&mut &r[..]) .ok_or_else(|| error::ErrorKind::InvalidAuthoritiesSet.into())) } @@ -503,8 +508,8 @@ impl Client where } impl<'a, Block: BlockT> ChangesTrieStorage for AccessedRootsRecorder<'a, Block> { - fn get(&self, key: &H256) -> Result, String> { - self.storage.get(key) + fn get(&self, key: &H256, prefix: &[u8]) -> Result, String> { + self.storage.get(key, prefix) } } @@ -619,9 +624,10 @@ impl Client where } /// Lock the import lock, and run operations inside. - pub fn lock_import_and_run) -> error::Result>( - &self, f: F - ) -> error::Result { + pub fn lock_import_and_run(&self, f: F) -> Result where + F: FnOnce(&mut ClientImportOperation) -> Result, + Err: From, + { let inner = || { let _import_lock = self.import_lock.lock(); @@ -729,7 +735,7 @@ impl Client where fork_choice, ); - telemetry!("block.import"; + telemetry!(SUBSTRATE_INFO; "block.import"; "height" => height, "best" => ?hash, "origin" => ?origin @@ -827,7 +833,7 @@ impl Client where operation.notify_imported = Some((hash, origin, import_headers.into_post(), is_new_best, storage_changes)); } - Ok(ImportResult::Queued) + Ok(ImportResult::imported()) } fn block_execution( @@ -859,7 +865,7 @@ impl Client where warn!(" Header {:?}", header); warn!(" Native result {:?}", native_result); warn!(" Wasm result {:?}", wasm_result); - telemetry!("block.execute.consensus_failure"; + telemetry!(SUBSTRATE_INFO; "block.execute.consensus_failure"; "hash" => ?hash, "origin" => ?origin, "header" => ?header @@ -868,7 +874,7 @@ impl Client where }), } }; - let (_, storage_update, changes_update) = self.executor.call_at_state::<_, _, NeverNativeValue, fn() -> _>( + let (_, storage_update, changes_update) = self.executor.call_at_state::<_, _, _, NeverNativeValue, fn() -> _>( transaction_state, &mut overlay, "Core_execute_block", @@ -878,6 +884,7 @@ impl Client where _ => get_execution_manager(self.execution_strategies().importing), }, None, + NeverOffchainExt::new(), )?; overlay.commit_prospective(); @@ -1072,9 +1079,19 @@ impl Client where return Ok(BlockStatus::Queued); } } - match self.backend.blockchain().header(*id).map_err(|e| error::Error::from_blockchain(Box::new(e)))?.is_some() { - true => Ok(BlockStatus::InChain), - false => Ok(BlockStatus::Unknown), + let hash_and_number = match id.clone() { + BlockId::Hash(hash) => self.backend.blockchain().number(hash)?.map(|n| (hash, n)), + BlockId::Number(n) => self.backend.blockchain().hash(n)?.map(|hash| (hash, n)), + }; + match hash_and_number { + Some((hash, number)) => { + if self.backend().have_state_at(&hash, number) { + Ok(BlockStatus::InChainWithState) + } else { + Ok(BlockStatus::InChainPruned) + } + } + None => Ok(BlockStatus::Unknown), } } @@ -1326,7 +1343,8 @@ impl CallRuntimeAt for Client where Block: BlockT { fn call_api_at< - R: Encode + Decode + PartialEq, NC: FnOnce() -> result::Result + UnwindSafe + R: Encode + Decode + PartialEq, + NC: FnOnce() -> result::Result + UnwindSafe, >( &self, at: &BlockId, @@ -1335,15 +1353,22 @@ impl CallRuntimeAt for Client where changes: &mut OverlayedChanges, initialised_block: &mut Option>, native_call: Option, - context: ExecutionContext + context: ExecutionContext, ) -> error::Result> { let manager = match context { ExecutionContext::BlockConstruction => self.execution_strategies.block_construction.get_manager(), ExecutionContext::Syncing => self.execution_strategies.syncing.get_manager(), ExecutionContext::Importing => self.execution_strategies.importing.get_manager(), + ExecutionContext::OffchainWorker(_) => self.execution_strategies.offchain_worker.get_manager(), ExecutionContext::Other => self.execution_strategies.other.get_manager(), }; - self.executor.contextual_call::<_, fn(_,_) -> _,_,_>( + + let mut offchain_extensions = match context { + ExecutionContext::OffchainWorker(ext) => Some(ext), + _ => None, + }; + + self.executor.contextual_call::<_, _, fn(_,_) -> _,_,_>( at, function, &args, @@ -1352,6 +1377,7 @@ impl CallRuntimeAt for Client where || self.prepare_environment_block(at), manager, native_call, + offchain_extensions.as_mut(), ) } @@ -1385,19 +1411,23 @@ impl consensus::BlockImport for Client hash: Block::Hash, parent_hash: Block::Hash, ) -> Result { - match self.backend.blockchain().status(BlockId::Hash(parent_hash)) + match self.block_status(&BlockId::Hash(parent_hash)) .map_err(|e| ConsensusError::from(ConsensusErrorKind::ClientImport(e.to_string())))? { - blockchain::BlockStatus::InChain => {}, - blockchain::BlockStatus::Unknown => return Ok(ImportResult::UnknownParent), + BlockStatus::InChainWithState | BlockStatus::Queued => {}, + BlockStatus::Unknown | BlockStatus::InChainPruned => return Ok(ImportResult::UnknownParent), + BlockStatus::KnownBad => return Ok(ImportResult::KnownBad), } - match self.backend.blockchain().status(BlockId::Hash(hash)) + + match self.block_status(&BlockId::Hash(hash)) .map_err(|e| ConsensusError::from(ConsensusErrorKind::ClientImport(e.to_string())))? { - blockchain::BlockStatus::InChain => return Ok(ImportResult::AlreadyInChain), - blockchain::BlockStatus::Unknown => {}, + BlockStatus::InChainWithState | BlockStatus::Queued => return Ok(ImportResult::AlreadyInChain), + BlockStatus::Unknown | BlockStatus::InChainPruned => {}, + BlockStatus::KnownBad => return Ok(ImportResult::KnownBad), } - Ok(ImportResult::Queued) + + Ok(ImportResult::imported()) } } @@ -1414,7 +1444,7 @@ impl consensus::Authorities for Client impl CurrentHeight for Client where B: backend::Backend, - E: CallExecutor + Clone, + E: CallExecutor, Block: BlockT, { type BlockNumber = ::Number; @@ -1425,7 +1455,7 @@ impl CurrentHeight for Client where impl BlockNumberToHash for Client where B: backend::Backend, - E: CallExecutor + Clone, + E: CallExecutor, Block: BlockT, { type BlockNumber = ::Number; @@ -1517,11 +1547,10 @@ impl backend::AuxStore for Client pub(crate) mod tests { use std::collections::HashMap; use super::*; - use keyring::Keyring; use primitives::twox_128; use runtime_primitives::traits::DigestItem as DigestItemT; use runtime_primitives::generic::DigestItem; - use test_client::{self, TestClient}; + use test_client::{self, TestClient, AccountKeyring, AuthorityKeyring}; use consensus::BlockOrigin; use test_client::client::backend::Backend as TestBackend; use test_client::BlockBuilderExt; @@ -1538,10 +1567,10 @@ pub(crate) mod tests { ) { // prepare block structure let blocks_transfers = vec![ - vec![(Keyring::Alice, Keyring::Dave), (Keyring::Bob, Keyring::Dave)], - vec![(Keyring::Charlie, Keyring::Eve)], + vec![(AccountKeyring::Alice, AccountKeyring::Dave), (AccountKeyring::Bob, AccountKeyring::Dave)], + vec![(AccountKeyring::Charlie, AccountKeyring::Eve)], vec![], - vec![(Keyring::Alice, Keyring::Dave)], + vec![(AccountKeyring::Alice, AccountKeyring::Dave)], ]; // prepare client ang import blocks @@ -1552,8 +1581,8 @@ pub(crate) mod tests { let mut builder = remote_client.new_block().unwrap(); for (from, to) in block_transfers { builder.push_transfer(Transfer { - from: from.to_raw_public().into(), - to: to.to_raw_public().into(), + from: from.into(), + to: to.into(), amount: 1, nonce: *nonces.entry(from).and_modify(|n| { *n = *n + 1 }).or_default(), }).unwrap(); @@ -1568,12 +1597,12 @@ pub(crate) mod tests { } // prepare test cases - let alice = twox_128(&runtime::system::balance_of_key(Keyring::Alice.to_raw_public().into())).to_vec(); - let bob = twox_128(&runtime::system::balance_of_key(Keyring::Bob.to_raw_public().into())).to_vec(); - let charlie = twox_128(&runtime::system::balance_of_key(Keyring::Charlie.to_raw_public().into())).to_vec(); - let dave = twox_128(&runtime::system::balance_of_key(Keyring::Dave.to_raw_public().into())).to_vec(); - let eve = twox_128(&runtime::system::balance_of_key(Keyring::Eve.to_raw_public().into())).to_vec(); - let ferdie = twox_128(&runtime::system::balance_of_key(Keyring::Ferdie.to_raw_public().into())).to_vec(); + let alice = twox_128(&runtime::system::balance_of_key(AccountKeyring::Alice.into())).to_vec(); + let bob = twox_128(&runtime::system::balance_of_key(AccountKeyring::Bob.into())).to_vec(); + let charlie = twox_128(&runtime::system::balance_of_key(AccountKeyring::Charlie.into())).to_vec(); + let dave = twox_128(&runtime::system::balance_of_key(AccountKeyring::Dave.into())).to_vec(); + let eve = twox_128(&runtime::system::balance_of_key(AccountKeyring::Eve.into())).to_vec(); + let ferdie = twox_128(&runtime::system::balance_of_key(AccountKeyring::Ferdie.into())).to_vec(); let test_cases = vec![ (1, 4, alice.clone(), vec![(4, 0), (1, 0)]), (1, 3, alice.clone(), vec![(1, 0)]), @@ -1607,14 +1636,14 @@ pub(crate) mod tests { assert_eq!( client.runtime_api().balance_of( &BlockId::Number(client.info().unwrap().chain.best_number), - Keyring::Alice.to_raw_public().into() + AccountKeyring::Alice.into() ).unwrap(), 1000 ); assert_eq!( client.runtime_api().balance_of( &BlockId::Number(client.info().unwrap().chain.best_number), - Keyring::Ferdie.to_raw_public().into() + AccountKeyring::Ferdie.into() ).unwrap(), 0 ); @@ -1626,9 +1655,9 @@ pub(crate) mod tests { assert_eq!(client.info().unwrap().chain.best_number, 0); assert_eq!(client.authorities_at(&BlockId::Number(0)).unwrap(), vec![ - Keyring::Alice.to_raw_public().into(), - Keyring::Bob.to_raw_public().into(), - Keyring::Charlie.to_raw_public().into() + AuthorityKeyring::Alice.into(), + AuthorityKeyring::Bob.into(), + AuthorityKeyring::Charlie.into() ]); } @@ -1650,8 +1679,8 @@ pub(crate) mod tests { let mut builder = client.new_block().unwrap(); builder.push_transfer(Transfer { - from: Keyring::Alice.to_raw_public().into(), - to: Keyring::Ferdie.to_raw_public().into(), + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), amount: 42, nonce: 0, }).unwrap(); @@ -1663,14 +1692,14 @@ pub(crate) mod tests { assert_eq!( client.runtime_api().balance_of( &BlockId::Number(client.info().unwrap().chain.best_number), - Keyring::Alice.to_raw_public().into() + AccountKeyring::Alice.into() ).unwrap(), 958 ); assert_eq!( client.runtime_api().balance_of( &BlockId::Number(client.info().unwrap().chain.best_number), - Keyring::Ferdie.to_raw_public().into() + AccountKeyring::Ferdie.into() ).unwrap(), 42 ); @@ -1692,15 +1721,15 @@ pub(crate) mod tests { let mut builder = client.new_block().unwrap(); builder.push_transfer(Transfer { - from: Keyring::Alice.to_raw_public().into(), - to: Keyring::Ferdie.to_raw_public().into(), + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), amount: 42, nonce: 0, }).unwrap(); assert!(builder.push_transfer(Transfer { - from: Keyring::Eve.to_raw_public().into(), - to: Keyring::Alice.to_raw_public().into(), + from: AccountKeyring::Eve.into(), + to: AccountKeyring::Alice.into(), amount: 42, nonce: 0, }).is_err()); @@ -1786,8 +1815,8 @@ pub(crate) mod tests { let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap(); // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder.push_transfer(Transfer { - from: Keyring::Alice.to_raw_public().into(), - to: Keyring::Ferdie.to_raw_public().into(), + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), amount: 41, nonce: 0, }).unwrap(); @@ -1806,8 +1835,8 @@ pub(crate) mod tests { let mut builder = client.new_block_at(&BlockId::Hash(b2.hash())).unwrap(); // this push is required as otherwise C3 has the same hash as B3 and won't get imported builder.push_transfer(Transfer { - from: Keyring::Alice.to_raw_public().into(), - to: Keyring::Ferdie.to_raw_public().into(), + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), amount: 1, nonce: 1, }).unwrap(); @@ -1818,8 +1847,8 @@ pub(crate) mod tests { let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap(); // this push is required as otherwise D2 has the same hash as B2 and won't get imported builder.push_transfer(Transfer { - from: Keyring::Alice.to_raw_public().into(), - to: Keyring::Ferdie.to_raw_public().into(), + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), amount: 1, nonce: 0, }).unwrap(); @@ -1907,8 +1936,8 @@ pub(crate) mod tests { let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap(); // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder.push_transfer(Transfer { - from: Keyring::Alice.to_raw_public().into(), - to: Keyring::Ferdie.to_raw_public().into(), + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), amount: 41, nonce: 0, }).unwrap(); @@ -1927,8 +1956,8 @@ pub(crate) mod tests { let mut builder = client.new_block_at(&BlockId::Hash(b2.hash())).unwrap(); // this push is required as otherwise C3 has the same hash as B3 and won't get imported builder.push_transfer(Transfer { - from: Keyring::Alice.to_raw_public().into(), - to: Keyring::Ferdie.to_raw_public().into(), + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), amount: 1, nonce: 1, }).unwrap(); @@ -1939,8 +1968,8 @@ pub(crate) mod tests { let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap(); // this push is required as otherwise D2 has the same hash as B2 and won't get imported builder.push_transfer(Transfer { - from: Keyring::Alice.to_raw_public().into(), - to: Keyring::Ferdie.to_raw_public().into(), + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), amount: 1, nonce: 0, }).unwrap(); diff --git a/core/client/src/error.rs b/core/client/src/error.rs index bfc073f634c1bb0a0e681c96c983de42722c5f3c..edc179ec6a701b6a3db48d44463c05f487f09601 100644 --- a/core/client/src/error.rs +++ b/core/client/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/client/src/genesis.rs b/core/client/src/genesis.rs index a048433d39b561a1e535b6067ee9e3a043a83b46..7ebae4c558895cd7d7309f5f1eff420680691b7e 100644 --- a/core/client/src/genesis.rs +++ b/core/client/src/genesis.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -41,14 +41,16 @@ pub fn construct_genesis_block< mod tests { use super::*; use parity_codec::{Encode, Decode, Joiner}; - use keyring::Keyring; use executor::{NativeExecutionDispatch, native_executor_instance}; use state_machine::{self, OverlayedChanges, ExecutionStrategy, InMemoryChangesTrieStorage}; use state_machine::backend::InMemory; - use test_client::runtime::genesismap::{GenesisConfig, additional_storage_with_genesis}; - use test_client::runtime::{Hash, Transfer, Block, BlockNumber, Header, Digest, Extrinsic}; + use test_client::{ + runtime::genesismap::{GenesisConfig, additional_storage_with_genesis}, + runtime::{Hash, Transfer, Block, BlockNumber, Header, Digest, Extrinsic}, + AccountKeyring, AuthorityKeyring + }; use runtime_primitives::traits::BlakeTwo256; - use primitives::{Blake2Hasher, ed25519::{Public, Pair}}; + 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")); @@ -67,7 +69,7 @@ mod tests { use trie::ordered_trie_root; let transactions = txs.into_iter().map(|tx| { - let signature = Pair::from(Keyring::from_public(Public::from_raw(tx.from.to_fixed_bytes())).unwrap()) + let signature = AccountKeyring::from_public(&tx.from).unwrap() .sign(&tx.encode()).into(); Extrinsic::Transfer(tx, signature) @@ -75,7 +77,6 @@ mod tests { let extrinsics_root = ordered_trie_root::(transactions.iter().map(Encode::encode)).into(); - println!("root before: {:?}", extrinsics_root); let mut header = Header { parent_hash, number, @@ -89,6 +90,7 @@ mod tests { state_machine::new( backend, Some(&InMemoryChangesTrieStorage::new()), + state_machine::NeverOffchainExt::new(), &mut overlay, &executor(), "Core_initialise_block", @@ -101,6 +103,7 @@ mod tests { state_machine::new( backend, Some(&InMemoryChangesTrieStorage::new()), + state_machine::NeverOffchainExt::new(), &mut overlay, &executor(), "BlockBuilder_apply_extrinsic", @@ -113,6 +116,7 @@ mod tests { let (ret_data, _, _) = state_machine::new( backend, Some(&InMemoryChangesTrieStorage::new()), + state_machine::NeverOffchainExt::new(), &mut overlay, &executor(), "BlockBuilder_finalise_block", @@ -121,7 +125,6 @@ mod tests { ExecutionStrategy::NativeElseWasm, ).unwrap(); header = Header::decode(&mut &ret_data[..]).unwrap(); - println!("root after: {:?}", header.extrinsics_root); (vec![].and(&Block { header, extrinsics: transactions }), hash) } @@ -133,8 +136,8 @@ mod tests { genesis_hash, hex!("25e5b37074063ab75c889326246640729b40d0c86932edc527bc80db0e04fe5c").into(), vec![Transfer { - from: Keyring::One.to_raw_public().into(), - to: Keyring::Two.to_raw_public().into(), + from: AccountKeyring::One.into(), + to: AccountKeyring::Two.into(), amount: 69, nonce: 0, }] @@ -143,8 +146,10 @@ mod tests { #[test] fn construct_genesis_should_work_with_native() { - let mut storage = GenesisConfig::new_simple( - vec![Keyring::One.to_raw_public().into(), Keyring::Two.to_raw_public().into()], 1000 + let mut storage = GenesisConfig::new(false, + vec![AuthorityKeyring::One.into(), AuthorityKeyring::Two.into()], + vec![AccountKeyring::One.into(), AccountKeyring::Two.into()], + 1000 ).genesis_map(); let state_root = BlakeTwo256::trie_root(storage.clone().into_iter()); let block = construct_genesis_block::(state_root); @@ -158,6 +163,7 @@ mod tests { let _ = state_machine::new( &backend, Some(&InMemoryChangesTrieStorage::new()), + state_machine::NeverOffchainExt::new(), &mut overlay, &executor(), "Core_execute_block", @@ -169,8 +175,10 @@ mod tests { #[test] fn construct_genesis_should_work_with_wasm() { - let mut storage = GenesisConfig::new_simple( - vec![Keyring::One.to_raw_public().into(), Keyring::Two.to_raw_public().into()], 1000 + let mut storage = GenesisConfig::new(false, + vec![AuthorityKeyring::One.into(), AuthorityKeyring::Two.into()], + vec![AccountKeyring::One.into(), AccountKeyring::Two.into()], + 1000 ).genesis_map(); let state_root = BlakeTwo256::trie_root(storage.clone().into_iter()); let block = construct_genesis_block::(state_root); @@ -184,6 +192,7 @@ mod tests { let _ = state_machine::new( &backend, Some(&InMemoryChangesTrieStorage::new()), + state_machine::NeverOffchainExt::new(), &mut overlay, &executor(), "Core_execute_block", @@ -194,10 +203,11 @@ mod tests { } #[test] - #[should_panic] fn construct_genesis_with_bad_transaction_should_panic() { - let mut storage = GenesisConfig::new_simple( - vec![Keyring::One.to_raw_public().into(), Keyring::Two.to_raw_public().into()], 68 + let mut storage = GenesisConfig::new(false, + vec![AuthorityKeyring::One.into(), AuthorityKeyring::Two.into()], + vec![AccountKeyring::One.into(), AccountKeyring::Two.into()], + 68 ).genesis_map(); let state_root = BlakeTwo256::trie_root(storage.clone().into_iter()); let block = construct_genesis_block::(state_root); @@ -208,15 +218,17 @@ mod tests { let (b1data, _b1hash) = block1(genesis_hash, &backend); let mut overlay = OverlayedChanges::default(); - let _ = state_machine::new( + let r = state_machine::new( &backend, Some(&InMemoryChangesTrieStorage::new()), + state_machine::NeverOffchainExt::new(), &mut overlay, &Executor::new(None), "Core_execute_block", &b1data, ).execute( ExecutionStrategy::NativeElseWasm, - ).unwrap(); + ); + assert!(r.is_err()); } } diff --git a/core/client/src/in_mem.rs b/core/client/src/in_mem.rs index 6c90d9ae3e84fb5d3947d9b7bc03dbf02059db6c..7f3cdfd8dde62448e1c5078a3a59e96de1326224 100644 --- a/core/client/src/in_mem.rs +++ b/core/client/src/in_mem.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -742,8 +742,8 @@ impl state_machine::ChangesTrieRootsStorage for ChangesTrieStorage } impl state_machine::ChangesTrieStorage for ChangesTrieStorage where H::Out: HeapSizeOf { - fn get(&self, key: &H::Out) -> Result, String> { - self.0.get(key) + fn get(&self, key: &H::Out, prefix: &[u8]) -> Result, String> { + self.0.get(key, prefix) } } diff --git a/core/client/src/leaves.rs b/core/client/src/leaves.rs index 92bdfa64ec64096bb1b6cb22e0ed7e0fac12e517..cc906d59a4bb1882211df3de855afe3d683aad7c 100644 --- a/core/client/src/leaves.rs +++ b/core/client/src/leaves.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -14,68 +14,63 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use std::collections::BTreeSet; -use std::cmp::{Ord, Ordering}; +//! Helper for managing the set of available leaves in the chain for DB implementations. + +use std::collections::BTreeMap; +use std::cmp::Reverse; use kvdb::{KeyValueDB, DBTransaction}; use runtime_primitives::traits::SimpleArithmetic; use parity_codec::{Encode, Decode}; use crate::error; -/// helper wrapper type to keep a list of block hashes ordered -/// by `number` descending in a `BTreeSet` which allows faster and simpler -/// insertion and removal than keeping them in a list. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] struct LeafSetItem { hash: H, - number: N, + number: Reverse, } -impl Ord for LeafSetItem where N: Ord { - fn cmp(&self, other: &Self) -> Ordering { - // reverse (descending) order - other.number.cmp(&self.number) - } +/// A displaced leaf after import. +#[must_use = "Displaced items from the leaf set must be handled."] +pub struct ImportDisplaced { + new_hash: H, + displaced: LeafSetItem, } -impl PartialOrd for LeafSetItem where N: PartialOrd { - fn partial_cmp(&self, other: &Self) -> Option { - // reverse (descending) order - other.number.partial_cmp(&self.number) - } +/// Displaced leaves after finalization. +#[must_use = "Displaced items from the leaf set must be handled."] +pub struct FinalizationDisplaced { + leaves: BTreeMap, Vec>, } -impl PartialEq for LeafSetItem where N: PartialEq { - fn eq(&self, other: &LeafSetItem) -> bool { - self.number == other.number +impl FinalizationDisplaced { + /// Merge with another. This should only be used for displaced items that + /// are produced within one transaction of each other. + pub fn merge(&mut self, mut other: Self) { + // this will ignore keys that are in duplicate, however + // if these are actually produced correctly via the leaf-set within + // one transaction, then there will be no overlap in the keys. + self.leaves.append(&mut other.leaves); } } -impl Eq for LeafSetItem where N: PartialEq {} - -/// A displaced leaf after import. -pub struct DisplacedLeaf { - new_hash: H, - displaced: LeafSetItem, -} - /// list of leaf hashes ordered by number (descending). /// stored in memory for fast access. /// this allows very fast checking and modification of active leaves. #[derive(Debug, Clone, PartialEq, Eq)] pub struct LeafSet { - storage: BTreeSet>, + storage: BTreeMap, Vec>, pending_added: Vec>, pending_removed: Vec, } impl LeafSet where - H: Clone + Decode + Encode, - N: Clone + SimpleArithmetic + Decode + Encode, + H: Clone + PartialEq + Decode + Encode, + N: std::fmt::Debug + Clone + SimpleArithmetic + Decode + Encode, { /// Construct a new, blank leaf set. pub fn new() -> Self { Self { - storage: BTreeSet::new(), + storage: BTreeMap::new(), pending_added: Vec::new(), pending_removed: Vec::new(), } @@ -83,7 +78,8 @@ impl LeafSet where /// Read the leaf list from the DB, using given prefix for keys. pub fn read_from_db(db: &KeyValueDB, column: Option, prefix: &[u8]) -> error::Result { - let mut storage = BTreeSet::new(); + let mut storage = BTreeMap::new(); + for (key, value) in db.iter_from_prefix(column, prefix) { if !key.starts_with(prefix) { break } let raw_hash = &mut &key[prefix.len()..]; @@ -95,7 +91,7 @@ impl LeafSet where Some(number) => number, None => return Err(error::ErrorKind::Backend("Error decoding number".into()).into()), }; - storage.insert(LeafSetItem { hash, number }); + storage.entry(Reverse(number)).or_insert_with(Vec::new).push(hash); } Ok(Self { storage, @@ -105,20 +101,20 @@ impl LeafSet where } /// update the leaf list on import. returns a displaced leaf if there was one. - pub fn import(&mut self, hash: H, number: N, parent_hash: H) -> Option> { + pub fn import(&mut self, hash: H, number: N, parent_hash: H) -> Option> { // avoid underflow for genesis. let displaced = if number != N::zero() { - let displaced = LeafSetItem { - hash: parent_hash.clone(), - number: number.clone() - N::one(), - }; - let was_displaced = self.storage.remove(&displaced); + let new_number = Reverse(number.clone() - N::one()); + let was_displaced = self.remove_leaf(&new_number, &parent_hash); if was_displaced { - self.pending_removed.push(parent_hash); - Some(DisplacedLeaf { + self.pending_removed.push(parent_hash.clone()); + Some(ImportDisplaced { new_hash: hash.clone(), - displaced, + displaced: LeafSetItem { + hash: parent_hash, + number: new_number, + }, }) } else { None @@ -127,36 +123,53 @@ impl LeafSet where None }; - let item = LeafSetItem { hash, number }; - self.storage.insert(item.clone()); - self.pending_added.push(item); + self.insert_leaf(Reverse(number.clone()), hash.clone()); + self.pending_added.push(LeafSetItem { hash, number: Reverse(number) }); displaced } - /// Undo an import operation, with a displaced leaf. - pub fn undo(&mut self, displaced: DisplacedLeaf) { - let new_number = displaced.displaced.number.clone() + N::one(); - self.storage.remove(&LeafSetItem { hash: displaced.new_hash, number: new_number }); - self.storage.insert(displaced.displaced); - self.pending_added.clear(); - self.pending_removed.clear(); + /// Note a block height finalized, displacing all leaves with number less than the finalized block's. + /// + /// Although it would be more technically correct to also prune out leaves at the + /// same number as the finalized block, but with different hashes, the current behavior + /// is simpler and our assumptions about how finalization works means that those leaves + /// will be pruned soon afterwards anyway. + pub fn finalize_height(&mut self, number: N) -> FinalizationDisplaced { + let boundary = if number == N::zero() { + return FinalizationDisplaced { leaves: BTreeMap::new() }; + } else { + number - N::one() + }; + + let below_boundary = self.storage.split_off(&Reverse(boundary)); + self.pending_removed.extend(below_boundary.values().flat_map(|h| h.iter()).cloned()); + FinalizationDisplaced { + leaves: below_boundary, + } + } + + /// Undo all pending operations. + /// + /// This returns an `Undo` struct, where any + /// `Displaced` objects that have returned by previous method calls + /// should be passed to via the appropriate methods. Otherwise, + /// the on-disk state may get out of sync with in-memory state. + pub fn undo(&mut self) -> Undo { + Undo { inner: self } } /// currently since revert only affects the canonical chain /// we assume that parent has no further children /// and we add it as leaf again pub fn revert(&mut self, hash: H, number: N, parent_hash: H) { - self.storage.insert(LeafSetItem { - hash: parent_hash, - number: number.clone() - N::one(), - }); - self.storage.remove(&LeafSetItem { hash, number }); + self.insert_leaf(Reverse(number.clone() - N::one()), parent_hash); + self.remove_leaf(&Reverse(number), &hash); } /// returns an iterator over all hashes in the leaf set /// ordered by their block number descending. pub fn hashes(&self) -> Vec { - self.storage.iter().map(|item| item.hash.clone()).collect() + self.storage.iter().flat_map(|(_, hashes)| hashes.iter()).cloned().collect() } /// Write the leaf list to the database transaction. @@ -164,7 +177,7 @@ impl LeafSet where let mut buf = prefix.to_vec(); for LeafSetItem { hash, number } in self.pending_added.drain(..) { hash.using_encoded(|s| buf.extend(s)); - tx.put_vec(column, &buf[..], number.encode()); + tx.put_vec(column, &buf[..], number.0.encode()); buf.truncate(prefix.len()); // reuse allocation. } for hash in self.pending_removed.drain(..) { @@ -173,6 +186,68 @@ impl LeafSet where buf.truncate(prefix.len()); // reuse allocation. } } + + #[cfg(test)] + fn contains(&self, number: N, hash: H) -> bool { + self.storage.get(&Reverse(number)).map_or(false, |hashes| hashes.contains(&hash)) + } + + fn insert_leaf(&mut self, number: Reverse, hash: H) { + self.storage.entry(number).or_insert_with(Vec::new).push(hash); + } + + // returns true if this leaf was contained, false otherwise. + fn remove_leaf(&mut self, number: &Reverse, hash: &H) -> bool { + let mut empty = false; + let removed = self.storage.get_mut(number).map_or(false, |leaves| { + let mut found = false; + leaves.retain(|h| if h == hash { + found = true; + false + } else { + true + }); + + if leaves.is_empty() { empty = true } + + found + }); + + if removed && empty { + self.storage.remove(number); + } + + removed + } +} + +/// Helper for undoing operations. +pub struct Undo<'a, H: 'a, N: 'a> { + inner: &'a mut LeafSet, +} + +impl<'a, H: 'a, N: 'a> Undo<'a, H, N> where + H: Clone + PartialEq + Decode + Encode, + N: std::fmt::Debug + Clone + SimpleArithmetic + Decode + Encode, +{ + /// Undo an imported block by providing the displaced leaf. + pub fn undo_import(&mut self, displaced: ImportDisplaced) { + let new_number = Reverse(displaced.displaced.number.0.clone() + N::one()); + self.inner.remove_leaf(&new_number, &displaced.new_hash); + self.inner.insert_leaf(new_number, displaced.displaced.hash); + } + + /// Undo a finalization operation by providing the displaced leaves. + pub fn undo_finalization(&mut self, mut displaced: FinalizationDisplaced) { + self.inner.storage.append(&mut displaced.leaves); + } +} + +impl<'a, H: 'a, N: 'a> Drop for Undo<'a, H, N> { + fn drop(&mut self) { + self.inner.pending_added.clear(); + self.inner.pending_removed.clear(); + } } #[cfg(test)] @@ -188,15 +263,15 @@ mod tests { set.import(2_1, 2, 1_1); set.import(3_1, 3, 2_1); - assert!(set.storage.contains(&LeafSetItem { hash: 3_1, number: 3 })); - assert!(!set.storage.contains(&LeafSetItem { hash: 2_1, number: 2 })); - assert!(!set.storage.contains(&LeafSetItem { hash: 1_1, number: 1 })); - assert!(!set.storage.contains(&LeafSetItem { hash: 0, number: 0 })); + assert!(set.contains(3, 3_1)); + assert!(!set.contains(2, 2_1)); + assert!(!set.contains(1, 1_1)); + assert!(!set.contains(0, 0)); set.import(2_2, 2, 1_1); - assert!(set.storage.contains(&LeafSetItem { hash: 3_1, number: 3 })); - assert!(set.storage.contains(&LeafSetItem { hash: 2_2, number: 2 })); + assert!(set.contains(3, 3_1)); + assert!(set.contains(2, 2_2)); } #[test] @@ -219,4 +294,63 @@ mod tests { let set2 = LeafSet::read_from_db(&db, None, PREFIX).unwrap(); assert_eq!(set, set2); } + + #[test] + fn two_leaves_same_height_can_be_included() { + let mut set = LeafSet::new(); + + set.import(1_1u32, 10u32,0u32); + set.import(1_2, 10, 0); + + assert!(set.storage.contains_key(&Reverse(10))); + assert!(set.contains(10, 1_1)); + assert!(set.contains(10, 1_2)); + assert!(!set.contains(10, 1_3)); + } + + #[test] + fn finalization_consistent_with_disk() { + const PREFIX: &[u8] = b"prefix"; + let db = ::kvdb_memorydb::create(0); + + let mut set = LeafSet::new(); + set.import(10_1u32, 10u32, 0u32); + set.import(11_1, 11, 10_2); + set.import(11_2, 11, 10_2); + set.import(12_1, 12, 11_123); + + assert!(set.contains(10, 10_1)); + + let mut tx = DBTransaction::new(); + set.prepare_transaction(&mut tx, None, PREFIX); + db.write(tx).unwrap(); + + let _ = set.finalize_height(11); + let mut tx = DBTransaction::new(); + set.prepare_transaction(&mut tx, None, PREFIX); + db.write(tx).unwrap(); + + assert!(set.contains(11, 11_1)); + assert!(set.contains(11, 11_2)); + assert!(set.contains(12, 12_1)); + assert!(!set.contains(10, 10_1)); + + let set2 = LeafSet::read_from_db(&db, None, PREFIX).unwrap(); + assert_eq!(set, set2); + } + + #[test] + fn undo_finalization() { + let mut set = LeafSet::new(); + set.import(10_1u32, 10u32, 0u32); + set.import(11_1, 11, 10_2); + set.import(11_2, 11, 10_2); + set.import(12_1, 12, 11_123); + + let displaced = set.finalize_height(11); + assert!(!set.contains(10, 10_1)); + + set.undo().undo_finalization(displaced); + assert!(set.contains(10, 10_1)); + } } diff --git a/core/client/src/lib.rs b/core/client/src/lib.rs index 44eaa449245bb36551e2b3c01959c5e261ba1807..d2da243d14a4db3980bcc91c200deb80ba0aed0e 100644 --- a/core/client/src/lib.rs +++ b/core/client/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -38,9 +38,9 @@ pub mod block_builder; #[cfg(feature = "std")] pub mod light; #[cfg(feature = "std")] -pub mod children; +pub mod leaves; #[cfg(feature = "std")] -mod leaves; +pub mod children; #[cfg(feature = "std")] mod call_executor; #[cfg(feature = "std")] diff --git a/core/client/src/light/backend.rs b/core/client/src/light/backend.rs index 948db23d34ac57b23693349838142c4211ac941d..a00d42e67394f239023491fa3a4888c12935cc39 100644 --- a/core/client/src/light/backend.rs +++ b/core/client/src/light/backend.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -35,7 +35,7 @@ use hash_db::Hasher; use trie::MemoryDB; use heapsize::HeapSizeOf; -const IN_MEMORY_EXPECT_PROOF: &'static 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 suceeds; qed"; /// Light client backend. pub struct Backend { diff --git a/core/client/src/light/blockchain.rs b/core/client/src/light/blockchain.rs index 73d530ce455454f8b4295d4403aee137bfde8a90..add183f67df59390bde9425168bbbea3fce91695 100644 --- a/core/client/src/light/blockchain.rs +++ b/core/client/src/light/blockchain.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -109,7 +109,7 @@ impl BlockchainHeaderBackend for Blockchain where Bloc }; // if the header is from future or genesis (we never prune genesis) => return - if number.is_zero() || self.storage.status(BlockId::Number(number))? != BlockStatus::InChain { + if number.is_zero() || self.storage.status(BlockId::Number(number))? == BlockStatus::Unknown { return Ok(None); } diff --git a/core/client/src/light/call_executor.rs b/core/client/src/light/call_executor.rs index c2857e07a08acde0a42e7ada0bb748c56cf26647..00a3d8895beb1226f8fbb727d8e268bafc63a9ce 100644 --- a/core/client/src/light/call_executor.rs +++ b/core/client/src/light/call_executor.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -21,11 +21,11 @@ use std::{collections::HashSet, sync::Arc, panic::UnwindSafe, result, marker::Ph use futures::{IntoFuture, Future}; use parity_codec::{Encode, Decode}; -use primitives::{H256, Blake2Hasher, convert_hash, NativeOrEncoded}; +use primitives::{H256, Blake2Hasher, convert_hash, NativeOrEncoded, OffchainExt}; use runtime_primitives::generic::BlockId; use runtime_primitives::traits::{As, Block as BlockT, Header as HeaderT}; use state_machine::{self, Backend as StateBackend, CodeExecutor, OverlayedChanges, ExecutionStrategy, - create_proof_check_backend, execution_proof_check_on_trie_backend, ExecutionManager}; + create_proof_check_backend, execution_proof_check_on_trie_backend, ExecutionManager, NeverOffchainExt}; use hash_db::Hasher; use crate::backend::RemoteBackend; @@ -80,7 +80,16 @@ where { type Error = ClientError; - fn call(&self, id: &BlockId, method: &str, call_data: &[u8], _strategy: ExecutionStrategy) + fn call< + O: OffchainExt, + >( + &self, + id: &BlockId, + method: &str, + call_data: &[u8], + _strategy: ExecutionStrategy, + _side_effects_handler: Option<&mut O>, + ) -> ClientResult> { let block_hash = self.blockchain.expect_block_hash_from_id(id)?; let block_header = self.blockchain.expect_header(id.clone())?; @@ -95,6 +104,7 @@ where } fn contextual_call< + O: OffchainExt, PB: Fn() -> ClientResult, EM: Fn( Result, Self::Error>, @@ -112,22 +122,24 @@ where _prepare_environment_block: PB, execution_manager: ExecutionManager, _native_call: Option, + side_effects_handler: Option<&mut O>, ) -> ClientResult> where ExecutionManager: Clone { // it is only possible to execute contextual call if changes are empty if !changes.is_empty() || initialised_block.is_some() { return Err(ClientErrorKind::NotAvailableOnLightClient.into()); } - self.call(at, method, call_data, (&execution_manager).into()).map(NativeOrEncoded::Encoded) + self.call(at, method, call_data, (&execution_manager).into(), side_effects_handler).map(NativeOrEncoded::Encoded) } fn runtime_version(&self, id: &BlockId) -> ClientResult { - let call_result = self.call(id, "version", &[], ExecutionStrategy::NativeElseWasm)?; + let call_result = self.call(id, "version", &[], ExecutionStrategy::NativeElseWasm, NeverOffchainExt::new())?; RuntimeVersion::decode(&mut call_result.as_slice()) .ok_or_else(|| ClientErrorKind::VersionInvalid.into()) } fn call_at_state< + O: OffchainExt, S: StateBackend, FF: FnOnce( Result, Self::Error>, @@ -142,6 +154,7 @@ where _call_data: &[u8], _m: ExecutionManager, _native_call: Option, + _side_effects_handler: Option<&mut O>, ) -> ClientResult<(NativeOrEncoded, S::Transaction, Option>)> { Err(ClientErrorKind::NotAvailableOnLightClient.into()) } @@ -201,15 +214,24 @@ impl CallExecutor for { type Error = ClientError; - fn call(&self, id: &BlockId, method: &str, call_data: &[u8], strategy: ExecutionStrategy) - -> ClientResult> { + fn call< + O: OffchainExt, + >( + &self, + id: &BlockId, + method: &str, + call_data: &[u8], + strategy: ExecutionStrategy, + side_effects_handler: Option<&mut O>, + ) -> ClientResult> { match self.backend.is_local_state_available(id) { - true => self.local.call(id, method, call_data, strategy), - false => self.remote.call(id, method, call_data, strategy), + true => self.local.call(id, method, call_data, strategy, side_effects_handler), + false => self.remote.call(id, method, call_data, strategy, side_effects_handler), } } fn contextual_call< + O: OffchainExt, PB: Fn() -> ClientResult, EM: Fn( Result, Self::Error>, @@ -227,12 +249,14 @@ impl CallExecutor for prepare_environment_block: PB, _manager: ExecutionManager, native_call: Option, + side_effects_handler: Option<&mut O>, ) -> ClientResult> where ExecutionManager: Clone { // there's no actual way/need to specify native/wasm execution strategy on light node // => we can safely ignore passed values match self.backend.is_local_state_available(at) { true => CallExecutor::contextual_call::< + _, _, fn( Result, Local::Error>, @@ -250,8 +274,10 @@ impl CallExecutor for prepare_environment_block, ExecutionManager::NativeWhenPossible, native_call, + side_effects_handler, ).map_err(|e| ClientErrorKind::Execution(Box::new(e.to_string())).into()), false => CallExecutor::contextual_call::< + _, _, fn( Result, Remote::Error>, @@ -269,6 +295,7 @@ impl CallExecutor for prepare_environment_block, ExecutionManager::NativeWhenPossible, native_call, + side_effects_handler, ).map_err(|e| ClientErrorKind::Execution(Box::new(e.to_string())).into()), } } @@ -281,6 +308,7 @@ impl CallExecutor for } fn call_at_state< + O: OffchainExt, S: StateBackend, FF: FnOnce( Result, Self::Error>, @@ -295,11 +323,13 @@ impl CallExecutor for call_data: &[u8], _manager: ExecutionManager, native_call: Option, + side_effects_handler: Option<&mut O>, ) -> ClientResult<(NativeOrEncoded, S::Transaction, Option>)> { // there's no actual way/need to specify native/wasm execution strategy on light node // => we can safely ignore passed values CallExecutor::call_at_state::< + _, _, fn( Result, Remote::Error>, @@ -315,6 +345,7 @@ impl CallExecutor for call_data, ExecutionManager::NativeWhenPossible, native_call, + side_effects_handler, ).map_err(|e| ClientErrorKind::Execution(Box::new(e.to_string())).into()) } @@ -509,7 +540,7 @@ mod tests { let local_executor = RemoteCallExecutor::new(Arc::new(backend.blockchain().clone()), Arc::new(OkCallFetcher::new(vec![1]))); let remote_executor = RemoteCallExecutor::new(Arc::new(backend.blockchain().clone()), Arc::new(OkCallFetcher::new(vec![2]))); let remote_or_local = RemoteOrLocalCallExecutor::new(backend, remote_executor, local_executor); - assert_eq!(remote_or_local.call(&BlockId::Number(0), "test_method", &[], ExecutionStrategy::NativeElseWasm).unwrap(), vec![1]); - assert_eq!(remote_or_local.call(&BlockId::Number(1), "test_method", &[], ExecutionStrategy::NativeElseWasm).unwrap(), vec![2]); + assert_eq!(remote_or_local.call(&BlockId::Number(0), "test_method", &[], ExecutionStrategy::NativeElseWasm, NeverOffchainExt::new()).unwrap(), vec![1]); + assert_eq!(remote_or_local.call(&BlockId::Number(1), "test_method", &[], ExecutionStrategy::NativeElseWasm, NeverOffchainExt::new()).unwrap(), vec![2]); } } diff --git a/core/client/src/light/fetcher.rs b/core/client/src/light/fetcher.rs index 1c1697eb34867268b4de3aa05aa93a88a56c5380..893682d5f8698a44f45f6647c52143ded316fd41 100644 --- a/core/client/src/light/fetcher.rs +++ b/core/client/src/light/fetcher.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -282,7 +282,7 @@ impl, F> LightDataChecker ChangesTrieRootsStorage for RootsStorage<'a, Number pub mod tests { use futures::future::{ok, err, FutureResult}; use parking_lot::Mutex; - use keyring::Keyring; use crate::client::tests::prepare_client_with_key_changes; use executor::{self, NativeExecutionDispatch}; use crate::error::Error as ClientError; - use test_client::{self, TestClient, blockchain::HeaderBackend}; - use test_client::runtime::{self, Hash, Block, Header}; + use test_client::{ + self, TestClient, blockchain::HeaderBackend, AccountKeyring, + runtime::{self, Hash, Block, Header} + }; use consensus::BlockOrigin; use crate::in_mem::{Blockchain as InMemoryBlockchain}; @@ -583,7 +584,7 @@ pub mod tests { // we're testing this test case here: // (1, 4, dave.clone(), vec![(4, 0), (1, 1), (1, 0)]), let (remote_client, remote_roots, _) = prepare_client_with_key_changes(); - let dave = twox_128(&runtime::system::balance_of_key(Keyring::Dave.to_raw_public().into())).to_vec(); + let dave = twox_128(&runtime::system::balance_of_key(AccountKeyring::Dave.into())).to_vec(); let dave = StorageKey(dave); // 'fetch' changes proof from remote node: @@ -695,7 +696,7 @@ pub mod tests { let (remote_client, remote_roots, _) = prepare_client_with_key_changes(); let local_cht_root = cht::compute_root::( 4, 0, remote_roots.iter().cloned().map(|ct| Ok(Some(ct)))).unwrap(); - let dave = twox_128(&runtime::system::balance_of_key(Keyring::Dave.to_raw_public().into())).to_vec(); + let dave = twox_128(&runtime::system::balance_of_key(AccountKeyring::Dave.into())).to_vec(); let dave = StorageKey(dave); // 'fetch' changes proof from remote node: diff --git a/core/client/src/light/mod.rs b/core/client/src/light/mod.rs index f847d22a0e747c928850ae9119bc14b65ee6cef7..2cdcaf49907ac9c8d2abce6843ff0badb48492b0 100644 --- a/core/client/src/light/mod.rs +++ b/core/client/src/light/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/client/src/notifications.rs b/core/client/src/notifications.rs index dae0ad25995f8013d25dab12042ad6c420c57040..139238f3435e6e3a96a4a7c11dc3bef5adeaa043 100644 --- a/core/client/src/notifications.rs +++ b/core/client/src/notifications.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/client/src/runtime_api.rs b/core/client/src/runtime_api.rs index 024816246d200769373b79879ae6e2f4e5e59c8c..77d733f64ed5ce04723308849406f13fbaac51be 100644 --- a/core/client/src/runtime_api.rs +++ b/core/client/src/runtime_api.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -24,10 +24,12 @@ pub use state_machine::OverlayedChanges; pub use primitives::NativeOrEncoded; #[doc(hidden)] pub use runtime_primitives::{ - traits::{AuthorityIdFor, Block as BlockT, GetNodeBlockType, GetRuntimeBlockType, ApiRef, RuntimeApiInfo}, - generic::BlockId, transaction_validity::TransactionValidity, ExecutionContext, + traits::{AuthorityIdFor, Block as BlockT, GetNodeBlockType, GetRuntimeBlockType, Header as HeaderT, ApiRef, RuntimeApiInfo}, + generic::BlockId, transaction_validity::TransactionValidity, }; #[doc(hidden)] +pub use primitives::{ExecutionContext, OffchainExt}; +#[doc(hidden)] pub use runtime_version::{ApiId, RuntimeVersion, ApisVec, create_apis_vec}; #[doc(hidden)] pub use rstd::{slice, mem}; @@ -91,7 +93,10 @@ pub trait ApiExt { pub trait CallRuntimeAt { /// Calls the given api function with the given encoded arguments at the given block /// and returns the encoded result. - fn call_api_at result::Result + UnwindSafe>( + fn call_api_at< + R: Encode + Decode + PartialEq, + NC: FnOnce() -> result::Result + UnwindSafe, + >( &self, at: &BlockId, function: &'static str, @@ -99,7 +104,7 @@ pub trait CallRuntimeAt { changes: &mut OverlayedChanges, initialised_block: &mut Option>, native_call: Option, - context: ExecutionContext + context: ExecutionContext, ) -> error::Result>; /// Returns the runtime version at the given block. @@ -132,3 +137,4 @@ decl_runtime_apis! { fn validate_transaction(tx: ::Extrinsic) -> TransactionValidity; } } + diff --git a/core/consensus/aura/Cargo.toml b/core/consensus/aura/Cargo.toml index 1b7f44cd38adce77e5e9320045a918c463a01842..ca4f139ee4901b8598898351409ed2a7a7713ec1 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.0" +parity-codec = "3.2" client = { package = "substrate-client", path = "../../client" } primitives = { package = "substrate-primitives", path = "../../primitives" } runtime_support = { package = "srml-support", path = "../../../srml/support" } @@ -18,6 +18,7 @@ aura_primitives = { package = "substrate-consensus-aura-primitives", path = "pri inherents = { package = "substrate-inherents", path = "../../inherents" } srml-consensus = { path = "../../../srml/consensus" } srml-aura = { path = "../../../srml/aura" } +substrate-telemetry = { path = "../../telemetry" } futures = "0.1.17" tokio = "0.1.7" parking_lot = "0.7.1" diff --git a/core/consensus/aura/primitives/src/lib.rs b/core/consensus/aura/primitives/src/lib.rs index 27f9a123bc98ce5004061ecef2789d21225d769d..9401b164ced943bc4657128ecb555ad724491f27 100644 --- a/core/consensus/aura/primitives/src/lib.rs +++ b/core/consensus/aura/primitives/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/consensus/aura/slots/Cargo.toml b/core/consensus/aura/slots/Cargo.toml index fce628161eb493fe86ea8f3acb5820275e9e9a6e..3ad763cc181e128d61f5e2c0c652e930183820d5 100644 --- a/core/consensus/aura/slots/Cargo.toml +++ b/core/consensus/aura/slots/Cargo.toml @@ -6,7 +6,7 @@ description = "Generic slots-based utilities for consensus" edition = "2018" [dependencies] -codec = { package = "parity-codec", version = "3.0" } +codec = { package = "parity-codec", version = "3.2" } 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/aura/src/lib.rs b/core/consensus/aura/src/lib.rs index e3a87e8ac988fac961da96c89545c56ac15259dd..3a9bfd971abde77642f20049633971e3faa91fa2 100644 --- a/core/consensus/aura/src/lib.rs +++ b/core/consensus/aura/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -26,22 +26,22 @@ //! Blocks from future steps will be either deferred or rejected depending on how //! far in the future they are. -use std::{sync::Arc, time::Duration, thread}; +use std::{sync::Arc, time::Duration, thread, marker::PhantomData, hash::Hash, fmt::Debug}; -use parity_codec::Encode; +use parity_codec::{Encode, Decode}; use consensus_common::{ Authorities, BlockImport, Environment, Proposer, ForkChoiceStrategy }; use consensus_common::import_queue::{Verifier, BasicQueue, SharedBlockImport, SharedJustificationImport}; use client::ChainHead; -use client::block_builder::api::{BlockBuilder as BlockBuilderApi, self as block_builder_api}; +use client::block_builder::api::BlockBuilder as BlockBuilderApi; use client::runtime_api::ApiExt; use consensus_common::{ImportBlock, BlockOrigin}; use runtime_primitives::{generic, generic::BlockId, Justification}; use runtime_primitives::traits::{ Block, Header, Digest, DigestItemFor, DigestItem, ProvideRuntimeApi }; -use primitives::{Ed25519AuthorityId, ed25519}; +use primitives::Pair; use inherents::{InherentDataProviders, InherentData, RuntimeString}; use futures::{Stream, Future, IntoFuture, future}; @@ -52,6 +52,7 @@ use srml_aura::{ InherentType as AuraInherent, AuraInherentData, timestamp::{TimestampInherentData, InherentType as TimestampInherent, InherentError as TIError} }; +use substrate_telemetry::{telemetry, CONSENSUS_TRACE, CONSENSUS_DEBUG, CONSENSUS_WARN, CONSENSUS_INFO}; use aura_slots::{CheckedHeader, SlotWorker, SlotInfo, SlotCompatible}; @@ -59,6 +60,9 @@ pub use aura_slots::SlotDuration; pub use aura_primitives::*; pub use consensus_common::SyncOracle; +type AuthorityId

=

::Public; +type Signature

=

::Signature; + /// A handle to the network. This is generally implemented by providing some /// handle to a gossip service or similar. /// @@ -72,18 +76,21 @@ pub trait Network: Clone { } /// Get slot author for given block along with authorities. -fn slot_author(slot_num: u64, authorities: &[Ed25519AuthorityId]) -> Option { +fn slot_author(slot_num: u64, authorities: &[AuthorityId

]) -> Option> + where P::Public: Clone, +{ if authorities.is_empty() { return None } let idx = slot_num % (authorities.len() as u64); assert!(idx <= usize::max_value() as u64, "It is impossible to have a vector with length beyond the address space; qed"); - let current_author = *authorities.get(idx as usize) + let current_author = authorities.get(idx as usize) .expect("authorities not empty; index constrained to list length;\ - this is a valid index; qed"); + this is a valid index; qed") + .clone(); - Some(current_author) + Some(current_author.clone()) } fn duration_now() -> Option { @@ -105,25 +112,27 @@ fn inherent_to_common_error(err: RuntimeString) -> consensus_common::Error { } /// A digest item which is usable with aura consensus. -pub trait CompatibleDigestItem: Sized { +pub trait CompatibleDigestItem: Sized { /// Construct a digest item which is a slot number and a signature on the /// hash. - fn aura_seal(slot_number: u64, signature: ed25519::Signature) -> Self; + fn aura_seal(slot_number: u64, signature: Signature) -> Self; /// If this item is an Aura seal, return the slot number and signature. - fn as_aura_seal(&self) -> Option<(u64, &ed25519::Signature)>; + fn as_aura_seal(&self) -> Option<(u64, Signature)>; } -impl CompatibleDigestItem for generic::DigestItem { +impl CompatibleDigestItem for generic::DigestItem> + where T::Signature: Clone +{ /// Construct a digest item which is a slot number and a signature on the /// hash. - fn aura_seal(slot_number: u64, signature: ed25519::Signature) -> Self { + fn aura_seal(slot_number: u64, signature: Signature) -> Self { generic::DigestItem::Seal(slot_number, signature) } /// If this item is an Aura seal, return the slot number and signature. - fn as_aura_seal(&self) -> Option<(u64, &ed25519::Signature)> { + fn as_aura_seal(&self) -> Option<(u64, Signature)> { match self { - generic::DigestItem::Seal(slot, ref sign) => Some((*slot, sign)), + generic::DigestItem::Seal(slot, ref sig) => Some((*slot, (*sig).clone())), _ => None } } @@ -142,15 +151,16 @@ impl SlotCompatible for AuraSlotCompatible { } /// Start the aura worker in a separate thread. -pub fn start_aura_thread( +pub fn start_aura_thread( slot_duration: SlotDuration, - local_key: Arc, + local_key: Arc

, client: Arc, block_import: Arc, env: Arc, sync_oracle: SO, on_exit: OnExit, inherent_data_providers: InherentDataProviders, + force_authoring: bool, ) -> Result<(), consensus_common::Error> where B: Block + 'static, C: Authorities + ChainHead + Send + Sync + 'static, @@ -159,13 +169,21 @@ pub fn start_aura_thread( <>::Create as IntoFuture>::Future: Send + 'static, I: BlockImport + Send + Sync + 'static, Error: From + From + 'static, + P: Pair + Send + Sync + 'static, + P::Public: Encode + Decode + Eq + Clone + Debug + Hash + Send + Sync + 'static, SO: SyncOracle + Send + Sync + Clone + 'static, OnExit: Future + Send + 'static, - DigestItemFor: CompatibleDigestItem + DigestItem + 'static, + DigestItemFor: CompatibleDigestItem

+ DigestItem> + 'static, Error: ::std::error::Error + Send + From<::consensus_common::Error> + 'static, { let worker = AuraWorker { - client: client.clone(), block_import, env, local_key, inherent_data_providers: inherent_data_providers.clone(), sync_oracle: sync_oracle.clone(), + client: client.clone(), + block_import, + env, + local_key, + inherent_data_providers: inherent_data_providers.clone(), + sync_oracle: sync_oracle.clone(), + force_authoring, }; aura_slots::start_slot_worker_thread::<_, _, _, _, AuraSlotCompatible, _>( @@ -179,15 +197,16 @@ pub fn start_aura_thread( } /// Start the aura worker. The returned future should be run in a tokio runtime. -pub fn start_aura( +pub fn start_aura( slot_duration: SlotDuration, - local_key: Arc, + local_key: Arc

, client: Arc, block_import: Arc, env: Arc, sync_oracle: SO, on_exit: OnExit, inherent_data_providers: InherentDataProviders, + force_authoring: bool, ) -> Result, consensus_common::Error> where B: Block, C: Authorities + ChainHead, @@ -196,13 +215,21 @@ pub fn start_aura( <>::Create as IntoFuture>::Future: Send + 'static, I: BlockImport + Send + Sync + 'static, Error: From + From, + P: Pair + Send + Sync + 'static, + P::Public: Hash + Eq + Send + Sync + Clone + Debug + Encode + Decode + 'static, SO: SyncOracle + Send + Sync + Clone, - DigestItemFor: CompatibleDigestItem + DigestItem, + DigestItemFor: CompatibleDigestItem

+ DigestItem>, Error: ::std::error::Error + Send + 'static + From<::consensus_common::Error>, OnExit: Future, { let worker = AuraWorker { - client: client.clone(), block_import, env, local_key, inherent_data_providers: inherent_data_providers.clone(), sync_oracle: sync_oracle.clone(), + client: client.clone(), + block_import, + env, + local_key, + inherent_data_providers: inherent_data_providers.clone(), + sync_oracle: sync_oracle.clone(), + force_authoring, }; aura_slots::start_slot_worker::<_, _, _, _, AuraSlotCompatible, _>( slot_duration, @@ -214,24 +241,27 @@ pub fn start_aura( ) } -struct AuraWorker { +struct AuraWorker { client: Arc, block_import: Arc, env: Arc, - local_key: Arc, + local_key: Arc

, sync_oracle: SO, inherent_data_providers: InherentDataProviders, + force_authoring: bool, } -impl SlotWorker for AuraWorker where +impl SlotWorker for AuraWorker where C: Authorities, E: Environment, E::Proposer: Proposer, <>::Create as IntoFuture>::Future: Send + 'static, I: BlockImport + Send + Sync + 'static, + P: Pair + Send + Sync + 'static, + P::Public: Hash + Eq + Send + Sync + Clone + Debug + Encode + Decode + 'static, Error: From + From, SO: SyncOracle + Send + Clone, - DigestItemFor: CompatibleDigestItem + DigestItem, + DigestItemFor: CompatibleDigestItem

+ DigestItem>, Error: ::std::error::Error + Send + 'static + From<::consensus_common::Error>, { type OnSlot = Box + Send>; @@ -265,29 +295,41 @@ impl SlotWorker for AuraWorker whe chain_head.hash(), e ); + telemetry!(CONSENSUS_WARN; "aura.unable_fetching_authorities"; + "slot" => ?chain_head.hash(), "err" => ?e + ); return Box::new(future::ok(())); } }; - if self.sync_oracle.is_offline() && authorities.len() > 1 { - debug!(target: "aura", "Skipping proposal slot. Waiting for the netork."); + if !self.force_authoring && self.sync_oracle.is_offline() && authorities.len() > 1 { + debug!(target: "aura", "Skipping proposal slot. Waiting for the network."); + telemetry!(CONSENSUS_DEBUG; "aura.skipping_proposal_slot"; + "authorities_len" => authorities.len() + ); return Box::new(future::ok(())); } - - let proposal_work = match slot_author(slot_num, &authorities) { + let maybe_author = slot_author::

(slot_num, &authorities); + let proposal_work = match maybe_author { None => return Box::new(future::ok(())), - Some(author) => if author.0 == public_key.0 { + Some(author) => if author == public_key { debug!( target: "aura", "Starting authorship at slot {}; timestamp = {}", slot_num, timestamp ); + telemetry!(CONSENSUS_DEBUG; "aura.starting_authorship"; + "slot_num" => slot_num, "timestamp" => timestamp + ); // we are the slot author. make a block and sign it. let proposer = match env.init(&chain_head, &authorities) { Ok(p) => p, Err(e) => { warn!("Unable to author block in slot {:?}: {:?}", slot_num, e); + telemetry!(CONSENSUS_WARN; "aura.unable_authoring_block"; + "slot" => slot_num, "err" => ?e + ); return Box::new(future::ok(())) } }; @@ -315,6 +357,9 @@ impl SlotWorker for AuraWorker whe "Discarding proposal for slot {}; block production took too long", slot_num ); + telemetry!(CONSENSUS_INFO; "aura.discarding_proposal_took_too_long"; + "slot" => slot_num + ); return } @@ -327,7 +372,7 @@ impl SlotWorker for AuraWorker whe // add it to a digest item. let to_sign = (slot_num, pre_hash).encode(); let signature = pair.sign(&to_sign[..]); - let item = as CompatibleDigestItem>::aura_seal( + let item = as CompatibleDigestItem

>::aura_seal( slot_num, signature, ); @@ -348,10 +393,18 @@ impl SlotWorker for AuraWorker whe import_block.post_header().hash(), pre_hash ); + telemetry!(CONSENSUS_INFO; "aura.pre_sealed_block"; + "header_num" => ?header_num, + "hash_now" => ?import_block.post_header().hash(), + "hash_previously" => ?pre_hash + ); if let Err(e) = block_import.import_block(import_block, None) { warn!(target: "aura", "Error with block built on {:?}: {:?}", parent_hash, e); + telemetry!(CONSENSUS_WARN; "aura.err_with_block_built_on"; + "hash" => ?parent_hash, "err" => ?e + ); } }) .map_err(|e| consensus_common::ErrorKind::ClientImport(format!("{:?}", e)).into()) @@ -363,15 +416,16 @@ impl SlotWorker for AuraWorker whe /// if it's successful, returns the pre-header, the slot number, and the signat. // // FIXME #1018 needs misbehavior types -fn check_header(slot_now: u64, mut header: B::Header, hash: B::Hash, authorities: &[Ed25519AuthorityId]) - -> Result, String> - where DigestItemFor: CompatibleDigestItem +fn check_header(slot_now: u64, mut header: B::Header, hash: B::Hash, authorities: &[AuthorityId

]) + -> Result, String> + where DigestItemFor: CompatibleDigestItem

, + P::Public: Clone + AsRef, { let digest_item = match header.digest_mut().pop() { Some(x) => x, None => return Err(format!("Header {:?} is unsealed", hash)), }; - let (slot_num, &sig) = match digest_item.as_aura_seal() { + let (slot_num, sig) = match digest_item.as_aura_seal() { Some(x) => x, None => return Err(format!("Header {:?} is unsealed", hash)), }; @@ -383,16 +437,16 @@ fn check_header(slot_now: u64, mut header: B::Header, hash: B::Hash, a // check the signature is valid under the expected authority and // chain state. - let expected_author = match slot_author(slot_num, &authorities) { + let expected_author = match slot_author::

(slot_num, &authorities) { None => return Err("Slot Author not found".to_string()), Some(author) => author }; let pre_hash = header.hash(); let to_sign = (slot_num, pre_hash).encode(); - let public = ed25519::Public(expected_author.0); + let public = expected_author; - if ed25519::verify_strong(&sig, &to_sign[..], public) { + if P::verify(&sig, &to_sign[..], public) { Ok(CheckedHeader::Checked(header, slot_num, sig)) } else { Err(format!("Bad signature on {:?}", hash)) @@ -414,13 +468,15 @@ pub trait ExtraVerification: Send + Sync { } /// A verifier for Aura blocks. -pub struct AuraVerifier { +pub struct AuraVerifier { client: Arc, extra: E, + phantom: PhantomData

, inherent_data_providers: inherents::InherentDataProviders, } -impl AuraVerifier +impl AuraVerifier + where P: Send + Sync + 'static { fn check_inherents( &self, @@ -456,6 +512,9 @@ impl AuraVerifier "halting for block {} seconds in the future", diff ); + telemetry!(CONSENSUS_INFO; "aura.halting_for_future_block"; + "diff" => ?diff + ); thread::sleep(Duration::from_secs(diff)); Ok(()) }, @@ -466,50 +525,6 @@ impl AuraVerifier Ok(()) } } - - #[allow(deprecated)] - fn old_check_inherents( - &self, - block: B, - block_id: BlockId, - inherent_data: InherentData, - timestamp_now: u64, - ) -> Result<(), String> - where C: ProvideRuntimeApi, C::Api: BlockBuilderApi - { - use block_builder_api::{OldInherentData, OldCheckInherentError}; - const MAX_TIMESTAMP_DRIFT_SECS: u64 = 60; - - let (timestamp, slot) = AuraSlotCompatible::extract_timestamp_and_slot(&inherent_data).map_err(|e| format!("{:?}", e))?; - let inherent_data = OldInherentData::new(timestamp, slot); - - let inherent_res = self.client.runtime_api().check_inherents_before_version_2( - &block_id, - block, - inherent_data, - ).map_err(|e| format!("{:?}", e))?; - - match inherent_res { - Ok(()) => Ok(()), - Err(OldCheckInherentError::ValidAtTimestamp(timestamp)) => { - // halt import until timestamp is valid. - // reject when too far ahead. - if timestamp > timestamp_now + MAX_TIMESTAMP_DRIFT_SECS { - return Err("Rejecting block too far in future".into()); - } - - let diff = timestamp.saturating_sub(timestamp_now); - info!( - target: "aura", - "halting for block {} seconds in the future", - diff - ); - thread::sleep(Duration::from_secs(diff)); - Ok(()) - }, - Err(OldCheckInherentError::Other(e)) => Err(e.into()) - } - } } /// No-op extra verification. @@ -524,11 +539,13 @@ impl ExtraVerification for NothingExtra { } } -impl Verifier for AuraVerifier where +impl Verifier for AuraVerifier where C: Authorities + ProvideRuntimeApi + Send + Sync, C::Api: BlockBuilderApi, - DigestItemFor: CompatibleDigestItem + DigestItem, + DigestItemFor: CompatibleDigestItem

+ DigestItem>, E: ExtraVerification, + P: Pair + Send + Sync + 'static, + P::Public: Send + Sync + Hash + Eq + Clone + Decode + Encode + Debug + AsRef + 'static, { fn verify( &self, @@ -536,7 +553,7 @@ impl Verifier for AuraVerifier where header: B::Header, justification: Option, mut body: Option>, - ) -> Result<(ImportBlock, Option>), String> { + ) -> 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) .map_err(|e| format!("Could not extract timestamp and slot: {:?}", e))?; @@ -552,7 +569,7 @@ impl Verifier for AuraVerifier where // we add one to allow for some small drift. // FIXME #1019 in the future, alter this queue to allow deferring of headers - let checked_header = check_header::(slot_now + 1, header, hash, &authorities[..])?; + let checked_header = check_header::(slot_now + 1, header, hash, &authorities[..])?; match checked_header { CheckedHeader::Checked(pre_header, slot_num, sig) => { let item = >::aura_seal(slot_num, sig); @@ -564,18 +581,12 @@ impl Verifier for AuraVerifier where inherent_data.aura_replace_inherent_data(slot_num); let block = B::new(pre_header.clone(), inner_body); + // skip the inherents verification if the runtime API is old. if self.client .runtime_api() - .has_api_with::, _>(&BlockId::Hash(parent_hash), |v| v < 2) + .has_api_with::, _>(&BlockId::Hash(parent_hash), |v| v >= 2) .map_err(|e| format!("{:?}", e))? { - self.old_check_inherents( - block.clone(), - BlockId::Hash(parent_hash), - inherent_data, - timestamp_now, - )?; - } else { self.check_inherents( block.clone(), BlockId::Hash(parent_hash), @@ -589,6 +600,7 @@ impl Verifier for AuraVerifier where } trace!(target: "aura", "Checked {:?}; importing.", pre_header); + telemetry!(CONSENSUS_TRACE; "aura.checked_and_importing"; "pre_header" => ?pre_header); extra_verification.into_future().wait()?; @@ -608,6 +620,9 @@ impl Verifier for AuraVerifier where } CheckedHeader::Deferred(a, b) => { debug!(target: "aura", "Checking {:?} failed; {:?}, {:?}.", hash, a, b); + telemetry!(CONSENSUS_DEBUG; "aura.header_too_far_in_future"; + "hash" => ?hash, "a" => ?a, "b" => ?b + ); Err(format!("Header {:?} rejected: too far in the future", hash)) } } @@ -632,7 +647,7 @@ fn register_aura_inherent_data_provider( } /// Start an import queue for the Aura consensus algorithm. -pub fn import_queue( +pub fn import_queue( slot_duration: SlotDuration, block_import: SharedBlockImport, justification_import: Option>, @@ -643,13 +658,20 @@ pub fn import_queue( B: Block, C: 'static + Authorities + ProvideRuntimeApi + Send + Sync, C::Api: BlockBuilderApi, - DigestItemFor: CompatibleDigestItem + DigestItem, + DigestItemFor: CompatibleDigestItem

+ DigestItem>, E: 'static + ExtraVerification, + P: Pair + Send + Sync + 'static, + P::Public: Clone + Eq + Send + Sync + Hash + Debug + Encode + Decode + AsRef, { register_aura_inherent_data_provider(&inherent_data_providers, slot_duration.get())?; let verifier = Arc::new( - AuraVerifier { client: client.clone(), extra, inherent_data_providers } + AuraVerifier { + client: client.clone(), + extra, + inherent_data_providers, + phantom: PhantomData, + } ); Ok(BasicQueue::new(verifier, block_import, justification_import)) } @@ -664,7 +686,8 @@ mod tests { use network::config::ProtocolConfig; use parking_lot::Mutex; use tokio::runtime::current_thread; - use keyring::Keyring; + use keyring::ed25519::Keyring; + use primitives::ed25519; use client::BlockchainEvents; use test_client; @@ -679,7 +702,7 @@ mod tests { type Proposer = DummyProposer; type Error = Error; - fn init(&self, parent_header: &::Header, _authorities: &[Ed25519AuthorityId]) + fn init(&self, parent_header: &::Header, _authorities: &[AuthorityId]) -> Result { Ok(DummyProposer(parent_header.number + 1, self.0.clone())) @@ -699,12 +722,13 @@ mod tests { const TEST_ROUTING_INTERVAL: Duration = Duration::from_millis(50); pub struct AuraTestNet { - peers: Vec>>, + peers: Vec>>, started: bool, } impl TestNetFactory for AuraTestNet { - type Verifier = AuraVerifier; + type Specialization = DummySpecialization; + type Verifier = AuraVerifier; type PeerData = (); /// Create new test network with peers and given config. @@ -731,18 +755,19 @@ mod tests { client, extra: NothingExtra, inherent_data_providers, + phantom: Default::default(), }) } - fn peer(&self, i: usize) -> &Peer { + 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); } @@ -789,7 +814,7 @@ mod tests { &inherent_data_providers, slot_duration.get() ).expect("Registers aura inherent data provider"); - let aura = start_aura( + let aura = start_aura::<_, _, _, _, ed25519::Pair, _, _, _>( slot_duration, Arc::new(key.clone().into()), client.clone(), @@ -798,6 +823,7 @@ mod tests { DummyOracle, futures::empty(), inherent_data_providers, + false, ).expect("Starts aura"); runtime.spawn(aura); diff --git a/core/consensus/common/Cargo.toml b/core/consensus/common/Cargo.toml index 0979cc45de5e19a37649862130d2b1ece4d663eb..814857fe69f2e6c4f823502d4eb886047db3512f 100644 --- a/core/consensus/common/Cargo.toml +++ b/core/consensus/common/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" [dependencies] crossbeam-channel = "0.3.4" +libp2p = { git = "https://github.com/tomaka/libp2p-rs", branch = "substrate-tmp-2019-03-20", default-features = false } log = "0.4" primitives = { package = "substrate-primitives", path= "../../primitives" } inherents = { package = "substrate-inherents", path = "../../inherents" } @@ -15,8 +16,8 @@ futures = "0.1" runtime_version = { package = "sr-version", path = "../../sr-version" } runtime_primitives = { package = "sr-primitives", path = "../../sr-primitives" } tokio = "0.1.7" -parity-codec = "3.0" -parity-codec-derive = "3.0" +parity-codec = "3.2" +parity-codec-derive = "3.1" [dev-dependencies] test_client = { package = "substrate-test-client", path = "../../test-client" } diff --git a/core/consensus/common/src/block_import.rs b/core/consensus/common/src/block_import.rs index 6cc5b329be9dee38b115a1a9782924e8dc2cac6e..06c78d74afd43225fece0045c7e306ea7b8e84c1 100644 --- a/core/consensus/common/src/block_import.rs +++ b/core/consensus/common/src/block_import.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -23,19 +23,43 @@ use std::borrow::Cow; /// Block import result. #[derive(Debug, PartialEq, Eq)] pub enum ImportResult { - /// Added to the import queue. - Queued, - /// Already in the import queue. - AlreadyQueued, + /// Block imported. + Imported(ImportedAux), /// Already in the blockchain. AlreadyInChain, /// Block or parent is known to be bad. KnownBad, /// Block parent is not in the chain. UnknownParent, - /// Added to the import queue but must be justified - /// (usually required to safely enact consensus changes). - NeedsJustification, +} + +/// Auxiliary data associated with an imported block result. +#[derive(Debug, PartialEq, Eq)] +pub struct ImportedAux { + /// Clear all pending justification requests. + pub clear_justification_requests: bool, + /// Request a justification for the given block. + pub needs_justification: bool, + /// Received a bad justification. + pub bad_justification: bool, +} + +impl Default for ImportedAux { + fn default() -> ImportedAux { + ImportedAux { + clear_justification_requests: false, + needs_justification: false, + bad_justification: false, + } + } +} + +impl ImportResult { + /// Returns default value for `ImportResult::Imported` with both + /// `clear_justification_requests` and `needs_justification` set to false. + pub fn imported() -> ImportResult { + ImportResult::Imported(ImportedAux::default()) + } } /// Block data origin. diff --git a/core/consensus/common/src/error.rs b/core/consensus/common/src/error.rs index 337bbeeea55d8eb700fceb3a2b7cc9be01bd36c6..58362b8e80e2e964da42cdfd03ff2ad55c07eed6 100644 --- a/core/consensus/common/src/error.rs +++ b/core/consensus/common/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -18,6 +18,7 @@ use runtime_version::RuntimeVersion; use error_chain::{error_chain, error_chain_processing, impl_error_chain_processed, impl_extract_backtrace, impl_error_chain_kind}; +use primitives::ed25519::{Public, Signature}; error_chain! { errors { @@ -52,13 +53,13 @@ error_chain! { } /// Error checking signature - InvalidSignature(s: ::primitives::ed25519::Signature, a: ::primitives::Ed25519AuthorityId) { + InvalidSignature(s: Signature, a: Public) { description("Message signature is invalid"), display("Message signature {:?} by {:?} is invalid.", s, a), } /// Account is not an authority. - InvalidAuthority(a: ::primitives::Ed25519AuthorityId) { + InvalidAuthority(a: Public) { description("Message sender is not a valid authority"), display("Message sender {:?} is not a valid authority.", a), } diff --git a/core/consensus/common/src/evaluation.rs b/core/consensus/common/src/evaluation.rs index c0fdcc45f1af2f56656af0bceff0efe34dd71fac..48016b1e94c93f0b55e8806d8e28cdcc79e6a6bc 100644 --- a/core/consensus/common/src/evaluation.rs +++ b/core/consensus/common/src/evaluation.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/consensus/common/src/import_queue.rs b/core/consensus/common/src/import_queue.rs index cb09f57caf39bda973fed5b73fc88549764ad3d8..2e1c29d4d804de7ea2dd8924a6c0841d6d3d34b4 100644 --- a/core/consensus/common/src/import_queue.rs +++ b/core/consensus/common/src/import_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -24,15 +24,16 @@ //! The `BasicQueue` and `BasicVerifier` traits allow serial queues to be //! instantiated simply. -use crate::block_import::{ImportBlock, BlockImport, JustificationImport, ImportResult, BlockOrigin}; +use crate::block_import::{ + BlockImport, BlockOrigin, ImportBlock, ImportedAux, ImportResult, JustificationImport, +}; use crossbeam_channel::{self as channel, Receiver, Sender}; -use std::collections::HashSet; use std::sync::Arc; use std::thread; use runtime_primitives::traits::{ - AuthorityIdFor, Block as BlockT, Header as HeaderT, NumberFor, Zero, + AuthorityIdFor, Block as BlockT, Header as HeaderT, NumberFor }; use runtime_primitives::Justification; @@ -45,7 +46,7 @@ pub type SharedBlockImport = Arc + pub type SharedJustificationImport = Arc + Send + Sync>; /// Maps to the Origin used by the network. -pub type Origin = usize; +pub type Origin = libp2p::PeerId; /// Block data used by the queue. #[derive(Debug, PartialEq, Eq, Clone)] @@ -85,14 +86,8 @@ pub trait ImportQueue: Send + Sync + ImportQueueClone { fn start(&self, _link: Box>) -> Result<(), std::io::Error> { Ok(()) } - /// Clear the queue when sync is restarting. - fn clear(&self); /// Clears the import queue and stops importing. fn stop(&self); - /// Get queue status. - fn status(&self) -> ImportQueueStatus; - /// Is block with given hash currently in the queue. - fn is_importing(&self, hash: &B::Hash) -> bool; /// Import bunch of blocks. fn import_blocks(&self, origin: BlockOrigin, blocks: Vec>); /// Import a block justification. @@ -109,15 +104,6 @@ impl Clone for Box> { } } -/// Import queue status. It isn't completely accurate. -#[derive(Debug)] -pub struct ImportQueueStatus { - /// Number of blocks that are currently in the queue. - pub importing_count: usize, - /// The number of the best block that was ever in the queue since start/last failure. - pub best_importing_number: NumberFor, -} - /// Interface to a basic block import queue that is importing blocks sequentially in a separate thread, /// with pluggable verification. #[derive(Clone)] @@ -134,7 +120,7 @@ impl ImportQueueClone for BasicQueue { /// "BasicQueue" is a wrapper around a channel sender to the "BlockImporter". /// "BasicQueue" itself does not keep any state or do any importing work, and can therefore be send to other threads. /// -/// "BasiqQueue" implements "ImportQueue" by sending messages to the "BlockImporter", which runs in it's own thread. +/// "BasicQueue" implements "ImportQueue" by sending messages to the "BlockImporter", which runs in it's own thread. /// /// The "BlockImporter" is responsible for handling incoming requests from the "BasicQueue", /// some of these requests are handled by the "BlockImporter" itself, such as "is_importing" or "status", @@ -165,43 +151,19 @@ impl BasicQueue { impl ImportQueue for BasicQueue { fn start(&self, link: Box>) -> Result<(), std::io::Error> { - let _ = self - .sender - .send(BlockImportMsg::Start(link)) - .expect("1. self is holding a sender to the Importer, 2. Importer should handle messages while there are senders around; qed"); - Ok(()) - } - - fn clear(&self) { - let _ = self - .sender - .send(BlockImportMsg::Clear) - .expect("1. self is holding a sender to the Importer, 2. Importer should handle messages while there are senders around; qed"); - } - - fn stop(&self) { - let _ = self - .sender - .send(BlockImportMsg::Stop) - .expect("1. self is holding a sender to the Importer, 2. Importer should handle messages while there are senders around; qed"); - } - - fn status(&self) -> ImportQueueStatus { let (sender, port) = channel::unbounded(); let _ = self .sender - .send(BlockImportMsg::Status(sender)) + .send(BlockImportMsg::Start(link, sender)) .expect("1. self is holding a sender to the Importer, 2. Importer should handle messages while there are senders around; qed"); port.recv().expect("1. self is holding a sender to the Importer, 2. Importer should handle messages while there are senders around; qed") } - fn is_importing(&self, hash: &B::Hash) -> bool { - let (sender, port) = channel::unbounded(); + fn stop(&self) { let _ = self .sender - .send(BlockImportMsg::IsImporting(hash.clone(), sender)) + .send(BlockImportMsg::Stop) .expect("1. self is holding a sender to the Importer, 2. Importer should handle messages while there are senders around; qed"); - port.recv().expect("1. self is holding a sender to the Importer, 2. Importer should handle messages while there are senders around; qed") } fn import_blocks(&self, origin: BlockOrigin, blocks: Vec>) { @@ -217,18 +179,15 @@ impl ImportQueue for BasicQueue { fn import_justification(&self, who: Origin, hash: B::Hash, number: NumberFor, justification: Justification) { let _ = self .sender - .send(BlockImportMsg::ImportJustification(who, hash, number, justification)) + .send(BlockImportMsg::ImportJustification(who.clone(), hash, number, justification)) .expect("1. self is holding a sender to the Importer, 2. Importer should handle messages while there are senders around; qed"); } } pub enum BlockImportMsg { ImportBlocks(BlockOrigin, Vec>), - Clear, - Status(Sender>), - IsImporting(B::Hash, Sender), ImportJustification(Origin, B::Hash, NumberFor, Justification), - Start(Box>), + Start(Box>, Sender>), Stop, } @@ -251,8 +210,6 @@ struct BlockImporter { port: Receiver>, result_port: Receiver>, worker_sender: Sender>, - queue_blocks: HashSet, - best_importing_number: NumberFor, link: Option>>, justification_import: Option>, } @@ -263,7 +220,7 @@ impl BlockImporter { worker_sender: Sender>, justification_import: Option>, ) -> Sender> { - let (sender, port) = channel::unbounded(); + let (sender, port) = channel::bounded(4); let _ = thread::Builder::new() .name("ImportQueue".into()) .spawn(move || { @@ -271,8 +228,6 @@ impl BlockImporter { port, result_port, worker_sender, - queue_blocks: HashSet::new(), - best_importing_number: Zero::zero(), link: None, justification_import, }; @@ -310,25 +265,18 @@ impl BlockImporter { match msg { BlockImportMsg::ImportBlocks(origin, incoming_blocks) => { self.handle_import_blocks(origin, incoming_blocks) - } - BlockImportMsg::Clear => self.handle_clear(), - BlockImportMsg::Status(reply_sender) => self.handle_status(reply_sender), - BlockImportMsg::IsImporting(hash, reply_sender) => { - self.handle_is_importing(hash, reply_sender) - } + }, BlockImportMsg::ImportJustification(who, hash, number, justification) => { self.handle_import_justification(who, hash, number, justification) - } - BlockImportMsg::Start(link) => { + }, + BlockImportMsg::Start(link, sender) => { if let Some(justification_import) = self.justification_import.as_ref() { justification_import.on_start(&*link); } self.link = Some(link); - } - BlockImportMsg::Stop => { - self.handle_clear(); - return false; - } + let _ = sender.send(Ok(())); + }, + BlockImportMsg::Stop => return false, } true } @@ -339,15 +287,15 @@ impl BlockImporter { _ => unreachable!("Import Worker does not send ImportBlocks message; qed"), }; let mut has_error = false; + let mut hashes = vec![]; for (result, hash) in results { - self.queue_blocks.remove(&hash); + hashes.push(hash); if has_error { continue; } if result.is_err() { - self.best_importing_number = Zero::zero(); has_error = true; } @@ -361,81 +309,67 @@ impl BlockImporter { match result { Ok(BlockImportResult::ImportedKnown(number)) => link.block_imported(&hash, number), - Ok(BlockImportResult::ImportedUnknown(number)) => { - link.block_imported(&hash, number) - } - Ok(BlockImportResult::ImportedUnjustified(number)) => { + Ok(BlockImportResult::ImportedUnknown(number, aux, who)) => { link.block_imported(&hash, number); - link.request_justification(&hash, number); + + if aux.clear_justification_requests { + trace!(target: "sync", "Block imported clears all pending justification requests {}: {:?}", number, hash); + link.clear_justification_requests(); + } + + if aux.needs_justification { + trace!(target: "sync", "Block imported but requires justification {}: {:?}", number, hash); + link.request_justification(&hash, number); + } + + if aux.bad_justification { + if let Some(peer) = who { + link.useless_peer(peer, "Sent block with bad justification to import"); + } + } }, Err(BlockImportError::IncompleteHeader(who)) => { if let Some(peer) = who { link.note_useless_and_restart_sync(peer, "Sent block with incomplete header to import"); } - } + }, Err(BlockImportError::VerificationFailed(who, e)) => { if let Some(peer) = who { link.note_useless_and_restart_sync(peer, &format!("Verification failed: {}", e)); } - } + }, Err(BlockImportError::BadBlock(who)) => { if let Some(peer) = who { link.note_useless_and_restart_sync(peer, "Sent us a bad block"); } - } + }, Err(BlockImportError::UnknownParent) | Err(BlockImportError::Error) => { - link.restart() - } + link.restart(); + }, }; } if let Some(link) = self.link.as_ref() { - link.maintain_sync(); + link.blocks_processed(hashes, has_error); } true } - fn handle_clear(&mut self) { - self.queue_blocks.clear(); - self.best_importing_number = Zero::zero(); - } - - fn handle_status(&self, reply_sender: Sender>) { - let status = ImportQueueStatus { - importing_count: self.queue_blocks.len(), - best_importing_number: self.best_importing_number, - }; - let _ = reply_sender.send(status); - } - - fn handle_is_importing(&self, hash: B::Hash, reply_sender: Sender) { - let _ = reply_sender.send(self.queue_blocks.contains(&hash)); - } - fn handle_import_justification(&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!("Justification import failed with {:?} for hash: {:?} number: {:?} coming from node: {:?}", e, hash, number, who); + debug!(target: "sync", "Justification import failed with {:?} for hash: {:?} number: {:?} coming from node: {:?}", e, hash, number, who); e }).is_ok() }).unwrap_or(false); + if let Some(link) = self.link.as_ref() { link.justification_imported(who, &hash, number, success); } } fn handle_import_blocks(&mut self, origin: BlockOrigin, blocks: Vec>) { - trace!(target:"sync", "Scheduling {} blocks for import", blocks.len()); - - let new_best_importing_number = blocks - .last() - .and_then(|b| b.header.as_ref().map(|h| h.number().clone())) - .unwrap_or_else(|| Zero::zero()); - self.queue_blocks - .extend(blocks.iter().map(|b| b.hash.clone())); - if new_best_importing_number > self.best_importing_number { - self.best_importing_number = new_best_importing_number; - } + trace!(target: "sync", "Scheduling {} blocks for import", blocks.len()); self.worker_sender .send(BlockImportWorkerMsg::ImportBlocks(origin, blocks)) .expect("1. This is holding a sender to the worker, 2. the worker should not quit while a sender is still held; qed"); @@ -454,7 +388,7 @@ impl> BlockImportWorker { verifier: Arc, block_import: SharedBlockImport, ) -> Sender> { - let (sender, port) = channel::unbounded(); + let (sender, port) = channel::bounded(4); let _ = thread::Builder::new() .name("ImportQueueWorker".into()) .spawn(move || { @@ -490,7 +424,7 @@ impl> BlockImportWorker { _ => Default::default(), }; - trace!(target:"sync", "Starting import of {} blocks {}", count, blocks_range); + trace!(target: "sync", "Starting import of {} blocks {}", count, blocks_range); let mut results = vec![]; @@ -501,12 +435,12 @@ impl> BlockImportWorker { let import_result = if has_error { Err(BlockImportError::Error) } else { - import_single_block( - &*self.block_import, - origin.clone(), - block.clone(), - self.verifier.clone(), - ) + import_single_block( + &*self.block_import, + origin.clone(), + block.clone(), + self.verifier.clone(), + ) }; let was_ok = import_result.is_ok(); results.push((import_result, block.hash)); @@ -529,13 +463,15 @@ impl> BlockImportWorker { /// algorithm. pub trait Link: Send { /// Block imported. - fn block_imported(&self, _hash: &B::Hash, _number: NumberFor) { } + fn block_imported(&self, _hash: &B::Hash, _number: NumberFor) {} + /// Batch of blocks imported, with or without error. + fn blocks_processed(&self, _processed_blocks: Vec, _has_error: bool) {} /// Justification import result. - fn justification_imported(&self, _who: Origin, _hash: &B::Hash, _number: NumberFor, _success: bool) { } + fn justification_imported(&self, _who: Origin, _hash: &B::Hash, _number: NumberFor, _success: bool) {} + /// Clear all pending justification requests. + fn clear_justification_requests(&self) {} /// Request a justification for the given block. - fn request_justification(&self, _hash: &B::Hash, _number: NumberFor) { } - /// Maintain sync. - fn maintain_sync(&self) {} + fn request_justification(&self, _hash: &B::Hash, _number: NumberFor) {} /// Disconnect from peer. fn useless_peer(&self, _who: Origin, _reason: &str) {} /// Disconnect from peer and restart sync. @@ -550,9 +486,7 @@ pub enum BlockImportResult { /// Imported known block. ImportedKnown(N), /// Imported unknown block. - ImportedUnknown(N), - /// Imported unjustified block that requires one. - ImportedUnjustified(N), + ImportedUnknown(N, ImportedAux, Option), } /// Block import error. @@ -582,7 +516,7 @@ pub fn import_single_block>( let (header, justification) = match (block.header, block.justification) { (Some(header), justification) => (header, justification), (None, _) => { - if let Some(peer) = peer { + if let Some(ref peer) = peer { debug!(target: "sync", "Header {} was not provided by {} ", block.hash, peer); } else { debug!(target: "sync", "Header {} was not provided ", block.hash); @@ -601,24 +535,14 @@ pub fn import_single_block>( trace!(target: "sync", "Block already in chain {}: {:?}", number, hash); Ok(BlockImportResult::ImportedKnown(number)) }, - Ok(ImportResult::AlreadyQueued) => { - trace!(target: "sync", "Block already queued {}: {:?}", number, hash); - Ok(BlockImportResult::ImportedKnown(number)) - }, - Ok(ImportResult::Queued) => { - Ok(BlockImportResult::ImportedUnknown(number)) - }, - Ok(ImportResult::NeedsJustification) => { - trace!(target: "sync", "Block queued but requires justification {}: {:?}", number, hash); - Ok(BlockImportResult::ImportedUnjustified(number)) - }, + Ok(ImportResult::Imported(aux)) => Ok(BlockImportResult::ImportedUnknown(number, aux, peer.clone())), Ok(ImportResult::UnknownParent) => { debug!(target: "sync", "Block with unknown parent {}: {:?}, parent: {:?}", number, hash, parent); Err(BlockImportError::UnknownParent) }, Ok(ImportResult::KnownBad) => { debug!(target: "sync", "Peer gave us a bad block {}: {:?}", number, hash); - Err(BlockImportError::BadBlock(peer)) + Err(BlockImportError::BadBlock(peer.clone())) }, Err(e) => { debug!(target: "sync", "Error importing block {}: {:?}: {:?}", number, hash, e); @@ -628,18 +552,18 @@ pub fn import_single_block>( }; match import_error(import_handle.check_block(hash, parent))? { - BlockImportResult::ImportedUnknown(_) => (), + BlockImportResult::ImportedUnknown { .. } => (), r @ _ => return Ok(r), // Any other successfull result means that the block is already imported. } let (import_block, new_authorities) = verifier.verify(block_origin, header, justification, block.body) .map_err(|msg| { - if let Some(peer) = peer { + if let Some(ref peer) = peer { trace!(target: "sync", "Verifying {}({}) from {} failed: {}", number, hash, peer, msg); } else { trace!(target: "sync", "Verifying {}({}) failed: {}", number, hash, msg); } - BlockImportError::VerificationFailed(peer, msg) + BlockImportError::VerificationFailed(peer.clone(), msg) })?; import_error(import_handle.import_block(import_block, new_authorities)) @@ -648,6 +572,7 @@ pub fn import_single_block>( #[cfg(test)] mod tests { use super::*; + use libp2p::PeerId; use test_client::runtime::{Block, Hash}; #[derive(Debug, PartialEq)] @@ -674,8 +599,6 @@ mod tests { fn block_imported(&self, _hash: &Hash, _number: NumberFor) { let _ = self.sender.send(LinkMsg::BlockImported); } - fn maintain_sync(&self) { - } fn useless_peer(&self, _: Origin, _: &str) { let _ = self.sender.send(LinkMsg::Disconnected); } @@ -695,12 +618,11 @@ mod tests { let (link_sender, link_port) = channel::unbounded(); let importer_sender = BlockImporter::::new(result_port, worker_sender, None); let link = TestLink::new(link_sender); - let _ = importer_sender.send(BlockImportMsg::Start(Box::new(link.clone()))); + let (ack_sender, start_ack_port) = channel::bounded(4); + let _ = importer_sender.send(BlockImportMsg::Start(Box::new(link.clone()), ack_sender)); // Ensure the importer handles Start before any result messages. - let (ack_sender, ack_port) = channel::unbounded(); - let _ = importer_sender.send(BlockImportMsg::Status(ack_sender)); - let _ = ack_port.recv(); + let _ = start_ack_port.recv(); // Send a known let results = vec![(Ok(BlockImportResult::ImportedKnown(Default::default())), Default::default())]; @@ -713,12 +635,21 @@ mod tests { assert_eq!(link_port.recv(), Ok(LinkMsg::BlockImported)); // Send an unknown - let results = vec![(Ok(BlockImportResult::ImportedUnknown(Default::default())), Default::default())]; + let results = vec![(Ok(BlockImportResult::ImportedUnknown(Default::default(), Default::default(), None)), Default::default())]; let _ = result_sender.send(BlockImportWorkerMsg::Imported(results)).ok().unwrap(); assert_eq!(link_port.recv(), Ok(LinkMsg::BlockImported)); + // Send an unknown with peer and bad justification + let peer_id = PeerId::random(); + let results = vec![(Ok(BlockImportResult::ImportedUnknown(Default::default(), + ImportedAux { needs_justification: true, clear_justification_requests: false, bad_justification: true }, + Some(peer_id.clone()))), Default::default())]; + let _ = result_sender.send(BlockImportWorkerMsg::Imported(results)).ok().unwrap(); + assert_eq!(link_port.recv(), Ok(LinkMsg::BlockImported)); + assert_eq!(link_port.recv(), Ok(LinkMsg::Disconnected)); + // Send an incomplete header - let results = vec![(Err(BlockImportError::IncompleteHeader(Some(Default::default()))), Default::default())]; + let results = vec![(Err(BlockImportError::IncompleteHeader(Some(peer_id.clone()))), Default::default())]; let _ = result_sender.send(BlockImportWorkerMsg::Imported(results)).ok().unwrap(); assert_eq!(link_port.recv(), Ok(LinkMsg::Disconnected)); assert_eq!(link_port.recv(), Ok(LinkMsg::Restarted)); @@ -729,7 +660,7 @@ mod tests { assert_eq!(link_port.recv(), Ok(LinkMsg::Restarted)); // Send a verification failed - let results = vec![(Err(BlockImportError::VerificationFailed(Some(0), String::new())), Default::default())]; + let results = vec![(Err(BlockImportError::VerificationFailed(Some(peer_id.clone()), String::new())), Default::default())]; let _ = result_sender.send(BlockImportWorkerMsg::Imported(results)).ok().unwrap(); assert_eq!(link_port.recv(), Ok(LinkMsg::Disconnected)); assert_eq!(link_port.recv(), Ok(LinkMsg::Restarted)); diff --git a/core/consensus/common/src/lib.rs b/core/consensus/common/src/lib.rs index 53ffe1fec3e4dd36083c83043f362bba11cee3cd..73315ed7aa9c676ec1564662055676ac106903a6 100644 --- a/core/consensus/common/src/lib.rs +++ b/core/consensus/common/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate Consensus Common. // Substrate Demo is free software: you can redistribute it and/or modify @@ -47,7 +47,9 @@ pub mod evaluation; const MAX_BLOCK_SIZE: usize = 4 * 1024 * 1024 + 512; pub use self::error::{Error, ErrorKind}; -pub use block_import::{BlockImport, JustificationImport, ImportBlock, BlockOrigin, ImportResult, ForkChoiceStrategy}; +pub use block_import::{ + BlockImport, BlockOrigin, ForkChoiceStrategy, ImportedAux, ImportBlock, ImportResult, JustificationImport, +}; /// Trait for getting the authorities at a given block. pub trait Authorities { diff --git a/core/consensus/common/src/offline_tracker.rs b/core/consensus/common/src/offline_tracker.rs index 1ed923da2c590e64ce1b54f63f76801bfaaa3cb0..3c6755d9411d7230bc2aaaa575737a208a13953d 100644 --- a/core/consensus/common/src/offline_tracker.rs +++ b/core/consensus/common/src/offline_tracker.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -112,25 +112,25 @@ impl OfflineTracker { #[cfg(test)] mod tests { use super::*; - use primitives::Ed25519AuthorityId; + use primitives::ed25519::Public as AuthorityId; #[test] fn validator_offline() { - let mut tracker = OfflineTracker::::new(); - let v = [0; 32].into(); - let v2 = [1; 32].into(); - let v3 = [2; 32].into(); - tracker.note_round_end(v, true); - tracker.note_round_end(v2, true); - tracker.note_round_end(v3, true); + let mut tracker = OfflineTracker::::new(); + let v = AuthorityId::from_raw([0; 32]); + let v2 = AuthorityId::from_raw([1; 32]); + let v3 = AuthorityId::from_raw([2; 32]); + tracker.note_round_end(v.clone(), true); + tracker.note_round_end(v2.clone(), true); + tracker.note_round_end(v3.clone(), true); let slash_time = REPORT_TIME + Duration::from_secs(5); tracker.observed.get_mut(&v).unwrap().offline_since -= slash_time; tracker.observed.get_mut(&v2).unwrap().offline_since -= slash_time; - assert_eq!(tracker.reports(&[v, v2, v3]), vec![0, 1]); + assert_eq!(tracker.reports(&[v.clone(), v2.clone(), v3.clone()]), vec![0, 1]); - tracker.note_new_block(&[v, v3]); + tracker.note_new_block(&[v.clone(), v3.clone()]); assert_eq!(tracker.reports(&[v, v2, v3]), vec![0]); } } diff --git a/core/consensus/rhd/Cargo.toml b/core/consensus/rhd/Cargo.toml index 83edbe5e1d519a845d268c2a07126cd61d4c7f4c..71b45cf41b6749f419a9b9d9093fbee2b93b412d 100644 --- a/core/consensus/rhd/Cargo.toml +++ b/core/consensus/rhd/Cargo.toml @@ -7,8 +7,7 @@ edition = "2018" [dependencies] futures = "0.1.17" -codec = { package = "parity-codec", version = "3.0" } -parity-codec-derive = { version = "3.0" } +codec = { package = "parity-codec", version = "3.2", features = ["derive"] } primitives = { package = "substrate-primitives", path = "../../primitives" } consensus = { package = "substrate-consensus-common", path = "../common" } client = { package = "substrate-client", path = "../../client" } diff --git a/core/consensus/rhd/src/error.rs b/core/consensus/rhd/src/error.rs index 7a97bbcace83741939813b1620aa2db3d42a3ffc..38081109754555b73c02c48f2c51bb1404425cf7 100644 --- a/core/consensus/rhd/src/error.rs +++ b/core/consensus/rhd/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/consensus/rhd/src/lib.rs b/core/consensus/rhd/src/lib.rs index 020703ab205c0b5a2e782850399c754fdce2f728..e42083a40b30952e128542823be5729c902a1688 100644 --- a/core/consensus/rhd/src/lib.rs +++ b/core/consensus/rhd/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -38,7 +38,6 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::{self, Instant, Duration}; use parity_codec::{Decode, Encode}; -use parity_codec_derive::{Decode, Encode}; use consensus::offline_tracker::OfflineTracker; use consensus::error::{ErrorKind as CommonErrorKind}; use consensus::{Authorities, BlockImport, Environment, Proposer as BaseProposer}; @@ -763,7 +762,7 @@ fn check_justification_signed_message( let auth_id = sig.signer.clone().into(); if !authorities.contains(&auth_id) { return None } - if ed25519::verify_strong(&sig.signature, message, &sig.signer) { + if ed25519::Pair::verify(&sig.signature, message, &sig.signer) { Some(sig.signer.0) } else { None @@ -839,7 +838,7 @@ pub fn check_vote( fn check_action(action: Action, parent_hash: &B::Hash, sig: &LocalizedSignature) -> Result<(), Error> { let message = localized_encode(*parent_hash, action); - if ed25519::verify_strong(&sig.signature, &message, &sig.signer) { + if ed25519::Pair::verify(&sig.signature, &message, &sig.signer) { Ok(()) } else { Err(CommonErrorKind::InvalidSignature(sig.signature.into(), sig.signer.clone().into()).into()) @@ -1316,7 +1315,7 @@ mod tests { use runtime_primitives::testing::{Block as GenericTestBlock, Header as TestHeader}; use primitives::H256; - use self::keyring::Keyring; + use keyring::AuthorityKeyring; type TestBlock = GenericTestBlock<()>; @@ -1421,7 +1420,7 @@ mod tests { start_round: 0, })), round_timeout_multiplier: 10, - key: Arc::new(Keyring::One.into()), + key: Arc::new(AuthorityKeyring::One.into()), factory: DummyFactory } } @@ -1447,10 +1446,10 @@ mod tests { fn future_gets_preempted() { let client = FakeClient { authorities: vec![ - Keyring::One.to_raw_public().into(), - Keyring::Two.to_raw_public().into(), - Keyring::Alice.to_raw_public().into(), - Keyring::Eve.to_raw_public().into(), + AuthorityKeyring::One.into(), + AuthorityKeyring::Two.into(), + AuthorityKeyring::Alice.into(), + AuthorityKeyring::Eve.into(), ], imported_heights: Mutex::new(HashSet::new()), }; @@ -1494,17 +1493,17 @@ mod tests { let hash = [0xff; 32].into(); let authorities = vec![ - Keyring::One.to_raw_public().into(), - Keyring::Two.to_raw_public().into(), - Keyring::Alice.to_raw_public().into(), - Keyring::Eve.to_raw_public().into(), + AuthorityKeyring::One.into(), + AuthorityKeyring::Two.into(), + AuthorityKeyring::Alice.into(), + AuthorityKeyring::Eve.into(), ]; let authorities_keys = vec![ - Keyring::One.into(), - Keyring::Two.into(), - Keyring::Alice.into(), - Keyring::Eve.into(), + AuthorityKeyring::One.into(), + AuthorityKeyring::Two.into(), + AuthorityKeyring::Alice.into(), + AuthorityKeyring::Eve.into(), ]; let unchecked = UncheckedJustification(rhododendron::UncheckedJustification { @@ -1555,8 +1554,8 @@ mod tests { let parent_hash = Default::default(); let authorities = vec![ - Keyring::Alice.to_raw_public().into(), - Keyring::Eve.to_raw_public().into(), + AuthorityKeyring::Alice.into(), + AuthorityKeyring::Eve.into(), ]; let block = TestBlock { @@ -1564,7 +1563,7 @@ mod tests { extrinsics: Default::default() }; - let proposal = sign_message(rhododendron::Message::Propose(1, block.clone()), &Keyring::Alice.pair(), parent_hash);; + let proposal = sign_message(rhododendron::Message::Propose(1, block.clone()), &AuthorityKeyring::Alice.pair(), parent_hash);; if let rhododendron::LocalizedMessage::Propose(proposal) = proposal { assert!(check_proposal(&authorities, &parent_hash, &proposal).is_ok()); let mut invalid_round = proposal.clone(); @@ -1578,7 +1577,7 @@ mod tests { } // Not an authority - let proposal = sign_message::(rhododendron::Message::Propose(1, block), &Keyring::Bob.pair(), parent_hash);; + let proposal = sign_message::(rhododendron::Message::Propose(1, block), &AuthorityKeyring::Bob.pair(), parent_hash);; if let rhododendron::LocalizedMessage::Propose(proposal) = proposal { assert!(check_proposal(&authorities, &parent_hash, &proposal).is_err()); } else { @@ -1592,8 +1591,8 @@ mod tests { let hash: H256 = [0xff; 32].into(); let authorities = vec![ - Keyring::Alice.to_raw_public().into(), - Keyring::Eve.to_raw_public().into(), + AuthorityKeyring::Alice.into(), + AuthorityKeyring::Eve.into(), ]; let vote = sign_message::(rhododendron::Message::Vote(rhododendron::Vote::Prepare(1, hash)), &Keyring::Alice.pair(), parent_hash);; @@ -1619,10 +1618,10 @@ mod tests { fn drop_bft_future_does_not_deadlock() { let client = FakeClient { authorities: vec![ - Keyring::One.to_raw_public().into(), - Keyring::Two.to_raw_public().into(), - Keyring::Alice.to_raw_public().into(), - Keyring::Eve.to_raw_public().into(), + AuthorityKeyring::One.into(), + AuthorityKeyring::Two.into(), + AuthorityKeyring::Alice.into(), + AuthorityKeyring::Eve.into(), ], imported_heights: Mutex::new(HashSet::new()), }; @@ -1644,10 +1643,10 @@ mod tests { fn bft_can_build_though_skipped() { let client = FakeClient { authorities: vec![ - Keyring::One.to_raw_public().into(), - Keyring::Two.to_raw_public().into(), - Keyring::Alice.to_raw_public().into(), - Keyring::Eve.to_raw_public().into(), + AuthorityKeyring::One.into(), + AuthorityKeyring::Two.into(), + AuthorityKeyring::Alice.into(), + AuthorityKeyring::Eve.into(), ], imported_heights: Mutex::new(HashSet::new()), }; diff --git a/core/consensus/rhd/src/misbehaviour_check.rs b/core/consensus/rhd/src/misbehaviour_check.rs index be8e25ccc9e2984bdc51323e25c095a51ccc139e..58b36542f692bfe16dda219a1d5fd53cb83bf160 100644 --- a/core/consensus/rhd/src/misbehaviour_check.rs +++ b/core/consensus/rhd/src/misbehaviour_check.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -74,8 +74,7 @@ pub fn evaluate_misbehavior( mod tests { use super::*; - use keyring::ed25519; - use keyring::Keyring; + use keyring::AuthorityKeyring; use rhododendron; use runtime_primitives::testing::{H256, Block as RawBlock}; @@ -110,7 +109,7 @@ mod tests { #[test] fn evaluates_double_prepare() { - let key: ed25519::Pair = Keyring::One.into(); + let key = AuthorityKeyring::One.pair(); let parent_hash = [0xff; 32].into(); let hash_1 = [0; 32].into(); let hash_2 = [1; 32].into(); @@ -127,7 +126,7 @@ mod tests { // same signature twice is not misbehavior. let signed = sign_prepare(&key, 1, hash_1, parent_hash); - assert!(evaluate_misbehavior::( + assert!(!evaluate_misbehavior::( &key.public().into(), parent_hash, &MisbehaviorKind::BftDoublePrepare( @@ -135,23 +134,23 @@ mod tests { signed, signed, ) - ) == false); + )); // misbehavior has wrong target. - assert!(evaluate_misbehavior::( - &Keyring::Two.to_raw_public().into(), + assert!(!evaluate_misbehavior::( + &AuthorityKeyring::Two.into(), parent_hash, &MisbehaviorKind::BftDoublePrepare( 1, sign_prepare(&key, 1, hash_1, parent_hash), sign_prepare(&key, 1, hash_2, parent_hash), ) - ) == false); + )); } #[test] fn evaluates_double_commit() { - let key: ed25519::Pair = Keyring::One.into(); + let key = AuthorityKeyring::One.pair(); let parent_hash = [0xff; 32].into(); let hash_1 = [0; 32].into(); let hash_2 = [1; 32].into(); @@ -168,7 +167,7 @@ mod tests { // same signature twice is not misbehavior. let signed = sign_commit(&key, 1, hash_1, parent_hash); - assert!(evaluate_misbehavior::( + assert!(!evaluate_misbehavior::( &key.public().into(), parent_hash, &MisbehaviorKind::BftDoubleCommit( @@ -176,17 +175,17 @@ mod tests { signed, signed, ) - ) == false); + )); // misbehavior has wrong target. - assert!(evaluate_misbehavior::( - &Keyring::Two.to_raw_public().into(), + assert!(!evaluate_misbehavior::( + &AuthorityKeyring::Two.into(), parent_hash, &MisbehaviorKind::BftDoubleCommit( 1, sign_commit(&key, 1, hash_1, parent_hash), sign_commit(&key, 1, hash_2, parent_hash), ) - ) == false); + )); } } diff --git a/core/consensus/rhd/src/service.rs b/core/consensus/rhd/src/service.rs index 34efc942d4dae2a4e77b58d023ea5405be30e0e9..e2858f767a8c08d3977803a68ce6bab46188cb60 100644 --- a/core/consensus/rhd/src/service.rs +++ b/core/consensus/rhd/src/service.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/executor/Cargo.toml b/core/executor/Cargo.toml index ef4eb23dfa692530e174981977044c2fb7275ff7..f34bfbbe916414b58b3a1a81cc0e3c143559d9d0 100644 --- a/core/executor/Cargo.toml +++ b/core/executor/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] error-chain = "0.12" -parity-codec = "3.0" +parity-codec = "3.2" runtime_io = { package = "sr-io", path = "../sr-io" } primitives = { package = "substrate-primitives", path = "../primitives" } trie = { package = "substrate-trie", path = "../trie" } diff --git a/core/executor/src/error.rs b/core/executor/src/error.rs index 98993519f4399ddfecd3e0caef5b1304ab41d732..b27ccf01bf4cef520c3e22d0d9ce8923f7456f5c 100644 --- a/core/executor/src/error.rs +++ b/core/executor/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/executor/src/lib.rs b/core/executor/src/lib.rs index 774850d5d1bda0c37a6259069d9e07c28b90b025..fa7cc71eea6d6273866f9ac53244cf548629c6cf 100644 --- a/core/executor/src/lib.rs +++ b/core/executor/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/executor/src/native_executor.rs b/core/executor/src/native_executor.rs index 4ee58e4493d7a986a329ed8b206487a436f273c4..0944cbdbbdd608007486921673533100641fa4a0 100644 --- a/core/executor/src/native_executor.rs +++ b/core/executor/src/native_executor.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/executor/src/sandbox.rs b/core/executor/src/sandbox.rs index aa7ecac7128ddec1bb318a88717b064c98bfd827..cc21d762bec11fd13645a5a971640e5ddedd155b 100644 --- a/core/executor/src/sandbox.rs +++ b/core/executor/src/sandbox.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/executor/src/wasm_executor.rs b/core/executor/src/wasm_executor.rs index 200403873f28e2eb9202e4e3efe02ceff084f820..42af29e9bae033b3210f987403fcde2cf6d51ffe 100644 --- a/core/executor/src/wasm_executor.rs +++ b/core/executor/src/wasm_executor.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -23,12 +23,12 @@ use secp256k1; use wasmi::{ Module, ModuleInstance, MemoryInstance, MemoryRef, TableRef, ImportsBuilder, ModuleRef, }; -use wasmi::RuntimeValue::{I32, I64}; +use wasmi::RuntimeValue::{I32, I64, self}; use wasmi::memory_units::{Pages}; use state_machine::Externalities; use crate::error::{Error, ErrorKind, Result}; use crate::wasm_utils::UserError; -use primitives::{blake2_256, twox_128, twox_256, ed25519, sr25519}; +use primitives::{blake2_256, twox_128, twox_256, ed25519, sr25519, Pair}; use primitives::hexdisplay::HexDisplay; use primitives::sandbox as sandbox_primitives; use primitives::{H256, Blake2Hasher}; @@ -393,10 +393,12 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, .map_err(|_| UserError("Invalid attempt to get parent_hash in ext_storage_changes_root"))?; parent_hash.as_mut().copy_from_slice(&raw_parent_hash[..]); let r = this.ext.storage_changes_root(parent_hash, parent_number); - if let Some(ref r) = r { + if let Some(r) = r { this.memory.set(result, &r[..]).map_err(|_| UserError("Invalid attempt to set memory in ext_storage_changes_root"))?; + Ok(1) + } else { + Ok(0) } - Ok(if r.is_some() { 1u32 } else { 0u32 }) }, ext_blake2_256_enumerated_trie_root(values_data: *const u8, lens_data: *const u32, lens_len: u32, result: *mut u8) => { let values = (0..lens_len) @@ -474,7 +476,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, this.memory.get_into(pubkey_data, &mut pubkey[..]).map_err(|_| UserError("Invalid attempt to get pubkey in ext_ed25519_verify"))?; let msg = this.memory.get(msg_data, msg_len as usize).map_err(|_| UserError("Invalid attempt to get message in ext_ed25519_verify"))?; - Ok(if ed25519::verify(&sig, &msg, &pubkey) { + Ok(if ed25519::Pair::verify_weak(&sig, &msg, &pubkey) { 0 } else { 5 @@ -487,7 +489,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, this.memory.get_into(pubkey_data, &mut pubkey[..]).map_err(|_| UserError("Invalid attempt to get pubkey in ext_sr25519_verify"))?; let msg = this.memory.get(msg_data, msg_len as usize).map_err(|_| UserError("Invalid attempt to get message in ext_sr25519_verify"))?; - Ok(if sr25519::verify(&sig, &msg, &pubkey) { + Ok(if sr25519::Pair::verify_weak(&sig, &msg, &pubkey) { 0 } else { 5 @@ -518,6 +520,15 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, Ok(0) }, + ext_submit_extrinsic(msg_data: *const u8, len: u32) => { + let extrinsic = this.memory.get(msg_data, len as usize) + .map_err(|_| UserError("OOB while ext_submit_extrinsic: wasm"))?; + + this.ext.submit_extrinsic(extrinsic) + .map_err(|_| UserError("Calling unavailable API ext_submit_extrinsic: wasm"))?; + + Ok(()) + }, ext_sandbox_instantiate( dispatch_thunk_idx: usize, wasm_ptr: *const u8, @@ -637,17 +648,19 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, /// /// Executes the provided code in a sandboxed wasm runtime. #[derive(Debug, Clone)] -pub struct WasmExecutor { -} +pub struct WasmExecutor; impl WasmExecutor { /// Create a new instance. pub fn new() -> Self { - WasmExecutor{} + WasmExecutor } /// Call a given method in the given code. + /// + /// Signature of this method needs to be `(I32, I32) -> I64`. + /// /// This should be used for tests only. pub fn call>( &self, @@ -656,12 +669,34 @@ impl WasmExecutor { code: &[u8], method: &str, data: &[u8], - ) -> Result> { + ) -> Result> { let module = ::wasmi::Module::from_buffer(code)?; let module = self.prepare_module(ext, heap_pages, &module)?; self.call_in_wasm_module(ext, &module, method, data) } + /// Call a given method with a custom signature in the given code. + /// + /// This should be used for tests only. + pub fn call_with_custom_signature< + E: Externalities, + F: FnOnce(&mut FnMut(&[u8]) -> Result) -> Result>, + FR: FnOnce(Option, &MemoryRef) -> Result>, + R, + >( + &self, + ext: &mut E, + heap_pages: usize, + code: &[u8], + method: &str, + create_parameters: F, + filter_result: FR, + ) -> Result { + let module = wasmi::Module::from_buffer(code)?; + let module = self.prepare_module(ext, heap_pages, &module)?; + self.call_in_wasm_module_with_custom_signature(ext, &module, method, create_parameters, filter_result) + } + fn get_mem_instance(module: &ModuleRef) -> Result { Ok(module .export_by_name("memory") @@ -679,6 +714,40 @@ impl WasmExecutor { method: &str, data: &[u8], ) -> Result> { + self.call_in_wasm_module_with_custom_signature( + ext, + module_instance, + method, + |alloc| { + let offset = alloc(data)?; + Ok(vec![I32(offset as i32), I32(data.len() as i32)]) + }, + |res, memory| { + if let Some(I64(r)) = res { + let offset = r as u32; + let length = (r as u64 >> 32) as usize; + memory.get(offset, length).map_err(|_| ErrorKind::Runtime.into()).map(Some) + } else { + Ok(None) + } + } + ) + } + + /// Call a given method in the given wasm-module runtime. + fn call_in_wasm_module_with_custom_signature< + E: Externalities, + F: FnOnce(&mut FnMut(&[u8]) -> Result) -> Result>, + FR: FnOnce(Option, &MemoryRef) -> Result>, + R, + >( + &self, + ext: &mut E, + module_instance: &ModuleRef, + method: &str, + create_parameters: F, + filter_result: FR, + ) -> Result { // extract a reference to a linear memory, optional reference to a table // and then initialize FunctionExecutor. let memory = Self::get_mem_instance(module_instance)?; @@ -689,26 +758,22 @@ impl WasmExecutor { let low = memory.lowest_used(); let used_mem = memory.used_size(); let mut fec = FunctionExecutor::new(memory.clone(), table, ext)?; - let size = data.len() as u32; - let offset = fec.heap.allocate(size).map_err(|_| ErrorKind::Runtime)?; - memory.set(offset, &data)?; + let parameters = create_parameters(&mut |data: &[u8]| { + let offset = fec.heap.allocate(data.len() as u32).map_err(|_| ErrorKind::Runtime)?; + memory.set(offset, &data)?; + Ok(offset) + })?; let result = module_instance.invoke_export( method, - &[ - I32(offset as i32), - I32(size as i32) - ], + ¶meters, &mut fec ); let result = match result { - Ok(Some(I64(r))) => { - let offset = r as u32; - let length = (r >> 32) as u32 as usize; - memory.get(offset, length) - .map_err(|_| ErrorKind::Runtime.into()) + Ok(val) => match filter_result(val, &memory)? { + Some(val) => Ok(val), + None => Err(ErrorKind::InvalidReturn.into()), }, - Ok(_) => Err(ErrorKind::InvalidReturn.into()), Err(e) => { trace!(target: "wasm-executor", "Failed to execute code with {} pages", memory.current_size().0); Err(e.into()) @@ -738,7 +803,7 @@ impl WasmExecutor { module, &ImportsBuilder::new() .with_resolver("env", FunctionExecutor::::resolver()) - )?; + )?; // extract a reference to a linear memory, optional reference to a table // and then initialize FunctionExecutor. @@ -759,7 +824,9 @@ impl WasmExecutor { #[cfg(test)] mod tests { use super::*; + use parity_codec::Encode; + use state_machine::TestExternalities; use hex_literal::{hex, hex_impl}; use primitives::map; @@ -875,7 +942,7 @@ mod tests { 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 key = ed25519::Pair::from_seed(&blake2_256(b"test")); + let key = ed25519::Pair::from_seed(blake2_256(b"test")); let sig = key.sign(b"all ok!"); let mut calldata = vec![]; calldata.extend_from_slice(key.public().as_ref()); @@ -901,7 +968,7 @@ mod tests { 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 key = sr25519::Pair::from_seed(&blake2_256(b"test")); + let key = sr25519::Pair::from_seed(blake2_256(b"test")); let sig = key.sign(b"all ok!"); let mut calldata = vec![]; calldata.extend_from_slice(key.public().as_ref()); diff --git a/core/executor/src/wasm_utils.rs b/core/executor/src/wasm_utils.rs index 310240651481dee41489670c89c43fdbf85b315c..4ad9541dbd0d99baa3831c86b4f92c641bb933df 100644 --- a/core/executor/src/wasm_utils.rs +++ b/core/executor/src/wasm_utils.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/executor/wasm/Cargo.lock b/core/executor/wasm/Cargo.lock index dcde882fc4e3a77acf5d26bc0747094c2e51a349..efbb31d9d8e9392d6a259a105045cb5b3bf7fd22 100644 --- a/core/executor/wasm/Cargo.lock +++ b/core/executor/wasm/Cargo.lock @@ -8,16 +8,31 @@ dependencies = [ "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "autocfg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" version = "1.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cfg-if" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "crunchy" version = "0.2.1" 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" + [[package]] name = "fixed-hash" version = "0.3.0" @@ -28,23 +43,47 @@ dependencies = [ [[package]] name = "hash-db" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.12.2" [[package]] name = "hash256-std-hasher" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.12.2" dependencies = [ "crunchy 0.2.1 (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 = "impl-codec" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.51" +source = "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.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memory-db" +version = "0.12.2" +dependencies = [ + "hash-db 0.12.2", + "hashmap_core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -54,17 +93,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "parity-codec" -version = "3.0.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "parity-codec-derive" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "proc-macro-crate 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", @@ -80,6 +121,14 @@ dependencies = [ "uint 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "proc-macro-crate" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "proc-macro2" version = "0.4.19" @@ -96,6 +145,88 @@ dependencies = [ "proc-macro2 0.4.19 (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.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (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.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.6 (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.2 (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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.51 (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.6 (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.2 (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 = "runtime-test" version = "0.1.0" @@ -140,18 +271,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "sr-io" version = "0.1.0" dependencies = [ - "hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", + "parity-codec 3.2.0 (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 0.1.0", "substrate-primitives 0.1.0", + "substrate-trie 0.4.0", ] [[package]] name = "sr-sandbox" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (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 0.1.0", "substrate-primitives 0.1.0", @@ -174,16 +306,26 @@ name = "substrate-primitives" version = "0.1.0" dependencies = [ "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hash256-std-hasher 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", + "hash256-std-hasher 0.12.2", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "primitive-types 0.2.1 (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.79 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 0.1.0", ] +[[package]] +name = "substrate-trie" +version = "0.4.0" +dependencies = [ + "hash-db 0.12.2", + "memory-db 0.12.2", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-std 0.1.0", + "trie-db 0.12.2", + "trie-root 0.12.2", +] + [[package]] name = "syn" version = "0.15.26" @@ -194,6 +336,32 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "toml" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "trie-db" +version = "0.12.2" +dependencies = [ + "elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", + "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" +dependencies = [ + "hash-db 0.12.2", +] + [[package]] name = "uint" version = "0.6.1" @@ -209,20 +377,57 @@ name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winapi" +version = "0.3.6" +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-i686-pc-windows-gnu" +version = "0.4.0" +source = "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" + +[[patch.unused]] +name = "trie-bench" +version = "0.12.2" + [metadata] "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" +"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" "checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781" +"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" "checksum crunchy 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c240f247c278fa08a6d4820a6a222bfc6e0d999e51ba67be94f44c905b2161f2" +"checksum elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "073be79b6538296faf81c631872676600616073817dd9a440c477ad09b408983" "checksum fixed-hash 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a557e80084b05c32b455963ff565a9de6f2866da023d6671705c6aff6f65e01c" -"checksum hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b03501f6e1a2a97f1618879aba3156f14ca2847faa530c4e28859638bd11483" -"checksum hash256-std-hasher 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5c13dbac3cc50684760f54af18545c9e80fb75e93a3e586d71ebdc13138f6a4" +"checksum hashmap_core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8e04cb7a5051270ef3fa79f8c7604d581ecfa73d520e74f554e45541c4b5881a" "checksum impl-codec 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2050d823639fbeae26b2b5ba09aca8907793117324858070ade0673c49f793b" +"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917" +"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" -"checksum parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "88f69984317b736dceac3baa86600fc089856f69b44b07231f39b5648b02bcd4" -"checksum parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a58ba33211595f92cc2163ac583961d3dc767e656934146636b05256cc9acd7f" +"checksum parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "21c9c3a1623c71ed83964ff28cac6126e178920f7646d32c337eacb9152b2907" +"checksum parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "864e9f66b58c0b38f0d6b511b6576afa2b678ae801b64220553bced57ac12df9" "checksum primitive-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edb92f1ebfc177432c03287b15d48c202e6e2c95993a7af3ba039abb43b1492e" +"checksum proc-macro-crate 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4c6cf4e5b00300d151dfffae39f529dfa5188f42eeb14201229aa420d6aad10c" "checksum proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)" = "ffe022fb8c8bd254524b0b3305906c1921fa37a84a644e29079a9e62200c3901" "checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" +"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.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832" +"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 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" @@ -230,5 +435,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)" = "84257ccd054dc351472528c8587b4de2dbf0dc0fe2e634030c1a90bfdacebaa9" "checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" "checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" +"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" "checksum uint 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e7780bb27fd8a22295e0d9d53ae3be253f715a0dccb1808527f478f1c2603708" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/core/executor/wasm/Cargo.toml b/core/executor/wasm/Cargo.toml index 9683cd764eebbc4daaf05e670be8271a9b9d1b4a..4c21fc20cb033fc9d9ea967d9fb22cf0e9121b57 100644 --- a/core/executor/wasm/Cargo.toml +++ b/core/executor/wasm/Cargo.toml @@ -18,3 +18,11 @@ lto = true [workspace] members = [] + +[patch.crates-io] +trie-db = { path = "../../../../parity-trie/trie-db" } +trie-root = { path = "../../../../parity-trie/trie-root" } +hash-db = { path = "../../../../parity-trie/hash-db" } +memory-db = { path = "../../../../parity-trie/memory-db" } +trie-bench = { path = "../../../../parity-trie/test-support/trie-bench" } +hash256-std-hasher = { path = "../../../../parity-trie/hash256-std-hasher" } diff --git a/core/finality-grandpa/Cargo.toml b/core/finality-grandpa/Cargo.toml index d94f950287ee594536eb45658c1bda9386238e87..070b073b99774ab0c4755e5c98de6890c5f23586 100644 --- a/core/finality-grandpa/Cargo.toml +++ b/core/finality-grandpa/Cargo.toml @@ -11,14 +11,16 @@ log = "0.4" parking_lot = "0.7.1" tokio = "0.1.7" rand = "0.6" -parity-codec = "3.0" -parity-codec-derive = "3.0" +parity-codec = { version = "3.2", features = ["derive"] } runtime_primitives = { package = "sr-primitives", path = "../sr-primitives" } consensus_common = { package = "substrate-consensus-common", path = "../consensus/common" } substrate-primitives = { path = "../primitives" } +substrate-telemetry = { path = "../telemetry" } client = { package = "substrate-client", path = "../client" } +inherents = { package = "substrate-inherents", path = "../../core/inherents" } 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.6.0", features = ["derive-codec"] } diff --git a/core/finality-grandpa/primitives/Cargo.toml b/core/finality-grandpa/primitives/Cargo.toml index d4752176fc7a6ac92958e199a843a2b8bb3e46c5..a0bd36eb9a43df5e292a0f4bf42dba177cfa3580 100644 --- a/core/finality-grandpa/primitives/Cargo.toml +++ b/core/finality-grandpa/primitives/Cargo.toml @@ -7,8 +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.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", default-features = false, features = ["derive"] } sr-primitives = { path = "../../sr-primitives", default-features = false } rstd = { package = "sr-std", path = "../../sr-std", default-features = false } @@ -18,7 +17,6 @@ std = [ "substrate-primitives/std", "client/std", "parity-codec/std", - "parity-codec-derive/std", "sr-primitives/std", "rstd/std", ] diff --git a/core/finality-grandpa/primitives/src/lib.rs b/core/finality-grandpa/primitives/src/lib.rs index 9055156ca355dc6805e907cf8769ba6cd63bfb22..92bd0e4584c83863afa4ec7fa01f5aea4d551276 100644 --- a/core/finality-grandpa/primitives/src/lib.rs +++ b/core/finality-grandpa/primitives/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -22,18 +22,20 @@ #[cfg(not(feature = "std"))] extern crate alloc; -use parity_codec_derive::{Encode, Decode}; -use substrate_primitives::Ed25519AuthorityId; +use parity_codec::{Encode, Decode}; +use substrate_primitives::ed25519; use sr_primitives::traits::{DigestFor, NumberFor}; use client::decl_runtime_apis; use rstd::vec::Vec; +use ed25519::Public as AuthorityId; + /// A scheduled change of authority set. #[cfg_attr(feature = "std", derive(Debug, PartialEq))] #[derive(Clone, Encode, Decode)] pub struct ScheduledChange { /// The new authorities after the change, along with their respective weights. - pub next_authorities: Vec<(Ed25519AuthorityId, u64)>, + pub next_authorities: Vec<(AuthorityId, u64)>, /// The number of blocks to delay. pub delay: N, } @@ -61,6 +63,7 @@ decl_runtime_apis! { /// applied in the runtime after those N blocks have passed. /// /// The consensus protocol will coordinate the handoff externally. + #[api_version(2)] pub trait GrandpaApi { /// Check a digest for pending changes. /// Return `None` if there are no pending changes. @@ -77,12 +80,34 @@ decl_runtime_apis! { fn grandpa_pending_change(digest: &DigestFor) -> Option>>; + /// Check a digest for forced changes. + /// Return `None` if there are no forced changes. Otherwise, return a + /// tuple containing the pending change and the median last finalized + /// block number at the time the change was signalled. + /// + /// Added in version 2. + /// + /// 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. + fn grandpa_forced_change(digest: &DigestFor) + -> Option<(NumberFor, ScheduledChange>)>; + /// Get the current GRANDPA authorities and weights. This should not change except /// for when changes are scheduled and the corresponding delay has passed. /// /// When called at block B, it will return the set of authorities that should be /// used to finalize descendants of this block (B+1, B+2, ...). The block B itself /// is finalized by the authorities from block B-1. - fn grandpa_authorities() -> Vec<(Ed25519AuthorityId, u64)>; + fn grandpa_authorities() -> Vec<(AuthorityId, u64)>; } } diff --git a/core/finality-grandpa/src/authorities.rs b/core/finality-grandpa/src/authorities.rs index d8849acc36ce048c163902ffdcf4e22877290f34..49917ae1c2702ed6f9abaabc32f76e5b1478b551 100644 --- a/core/finality-grandpa/src/authorities.rs +++ b/core/finality-grandpa/src/authorities.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -18,16 +18,19 @@ use fork_tree::ForkTree; use parking_lot::RwLock; -use substrate_primitives::Ed25519AuthorityId; +use substrate_primitives::ed25519; use grandpa::VoterSet; -use parity_codec_derive::{Encode, Decode}; +use parity_codec::{Encode, Decode}; use log::{debug, info}; +use substrate_telemetry::{telemetry, CONSENSUS_INFO}; use std::cmp::Ord; use std::fmt::Debug; use std::ops::Add; use std::sync::Arc; +use ed25519::Public as AuthorityId; + /// A shared authority set. pub(crate) struct SharedAuthoritySet { inner: Arc>>, @@ -39,17 +42,7 @@ impl Clone for SharedAuthoritySet { } } -impl SharedAuthoritySet -where H: PartialEq, - N: Ord, -{ - /// The genesis authority set. - pub(crate) fn genesis(initial: Vec<(Ed25519AuthorityId, u64)>) -> Self { - SharedAuthoritySet { - inner: Arc::new(RwLock::new(AuthoritySet::genesis(initial))) - } - } - +impl SharedAuthoritySet { /// Acquire a reference to the inner read-write lock. pub(crate) fn inner(&self) -> &RwLock> { &*self.inner @@ -71,7 +64,7 @@ where N: Add + Ord + Clone + Debug, } /// Get the current authorities and their weights (for the current set ID). - pub(crate) fn current_authorities(&self) -> VoterSet { + pub(crate) fn current_authorities(&self) -> VoterSet { self.inner.read().current_authorities.iter().cloned().collect() } } @@ -93,11 +86,18 @@ pub(crate) struct Status { } /// A set of authorities. -#[derive(Debug, Clone, Encode, Decode)] +#[derive(Debug, Clone, Encode, Decode, PartialEq)] pub(crate) struct AuthoritySet { - current_authorities: Vec<(Ed25519AuthorityId, u64)>, - set_id: u64, - pending_changes: ForkTree>, + pub(crate) current_authorities: Vec<(AuthorityId, u64)>, + pub(crate) set_id: u64, + // Tree of pending standard changes across forks. Standard changes are + // enacted on finality and must be enacted (i.e. finalized) in-order across + // a given branch + pub(crate) pending_standard_changes: ForkTree>, + // Pending forced changes across different forks (at most one per fork). + // Forced changes are enacted on block depth (not finality), for this reason + // only one forced change should exist per fork. + pub(crate) pending_forced_changes: Vec>, } impl AuthoritySet @@ -105,16 +105,17 @@ where H: PartialEq, N: Ord, { /// Get a genesis set with given authorities. - pub(crate) fn genesis(initial: Vec<(Ed25519AuthorityId, u64)>) -> Self { + pub(crate) fn genesis(initial: Vec<(AuthorityId, u64)>) -> Self { AuthoritySet { current_authorities: initial, set_id: 0, - pending_changes: ForkTree::new(), + pending_standard_changes: ForkTree::new(), + pending_forced_changes: Vec::new(), } } /// Get the current set id and a reference to the current authority set. - pub(crate) fn current(&self) -> (u64, &[(Ed25519AuthorityId, u64)]) { + pub(crate) fn current(&self) -> (u64, &[(AuthorityId, u64)]) { (self.set_id, &self.current_authorities[..]) } } @@ -124,12 +125,7 @@ where N: Add + Ord + Clone + Debug, H: Clone + Debug { - /// Note an upcoming pending transition. Multiple pending changes on the - /// same branch can be added as long as they don't overlap. This method - /// assumes that changes on the same branch will be added in-order. The - /// given function `is_descendent_of` should return `true` if the second - /// hash (target) is a descendent of the first hash (base). - pub(crate) fn add_pending_change( + fn add_standard_change( &mut self, pending: PendingChange, is_descendent_of: &F, @@ -140,65 +136,183 @@ where let hash = pending.canon_hash.clone(); let number = pending.canon_height.clone(); - debug!(target: "afg", "Inserting potential set change signalled at block {:?} \ + debug!(target: "afg", "Inserting potential standard set change signalled at block {:?} \ (delayed by {:?} blocks).", - (&number, &hash), pending.finalization_depth); + (&number, &hash), pending.delay); - self.pending_changes.import( + self.pending_standard_changes.import( hash.clone(), number.clone(), pending, is_descendent_of, )?; - debug!(target: "afg", "There are now {} alternatives for the next pending change (roots), \ - and a total of {} pending changes (across all forks).", - self.pending_changes.roots().count(), - self.pending_changes.iter().count(), + debug!(target: "afg", "There are now {} alternatives for the next pending standard change (roots), \ + and a total of {} pending standard changes (across all forks).", + self.pending_standard_changes.roots().count(), + self.pending_standard_changes.iter().count(), ); Ok(()) } - /// Inspect pending changes. Pending changes in the tree are traversed in pre-order. + fn add_forced_change( + &mut self, + pending: PendingChange, + is_descendent_of: &F, + ) -> Result<(), fork_tree::Error> where + F: Fn(&H, &H) -> Result, + E: std::error::Error, + { + for change in self.pending_forced_changes.iter() { + if change.canon_hash == pending.canon_hash || + is_descendent_of(&change.canon_hash, &pending.canon_hash)? + { + return Err(fork_tree::Error::UnfinalizedAncestor); + } + } + + // ordered first by effective number and then by signal-block number. + let key = (pending.effective_number(), pending.canon_height.clone()); + let idx = self.pending_forced_changes + .binary_search_by_key(&key, |change| ( + change.effective_number(), + change.canon_height.clone(), + )) + .unwrap_or_else(|i| i); + + debug!(target: "afg", "Inserting potential forced set change at block {:?} \ + (delayed by {:?} blocks).", + (&pending.canon_height, &pending.canon_hash), pending.delay); + + self.pending_forced_changes.insert(idx, pending); + + debug!(target: "afg", "There are now {} pending forced changes.", self.pending_forced_changes.len()); + + Ok(()) + } + + /// Note an upcoming pending transition. Multiple pending standard changes + /// on the same branch can be added as long as they don't overlap. Forced + /// changes are restricted to one per fork. This method assumes that changes + /// on the same branch will be added in-order. The given function + /// `is_descendent_of` should return `true` if the second hash (target) is a + /// descendent of the first hash (base). + pub(crate) fn add_pending_change( + &mut self, + pending: PendingChange, + is_descendent_of: &F, + ) -> Result<(), fork_tree::Error> where + F: Fn(&H, &H) -> Result, + E: std::error::Error, + { + match pending.delay_kind { + DelayKind::Best { .. } => { + self.add_forced_change(pending, is_descendent_of) + }, + DelayKind::Finalized => { + self.add_standard_change(pending, is_descendent_of) + }, + } + } + + /// Inspect pending changes. Standard pending changes are iterated first, + /// and the changes in the tree are traversed in pre-order, afterwards all + /// forced changes are iterated. pub(crate) fn pending_changes(&self) -> impl Iterator> { - self.pending_changes.iter().map(|(_, _, c)| c) + self.pending_standard_changes.iter().map(|(_, _, c)| c) + .chain(self.pending_forced_changes.iter()) } - /// Get the earliest limit-block number, if any. If there are pending - /// changes across different forks, this method will return the earliest - /// effective number (across the different branches). + /// Get the earliest limit-block number, if any. If there are pending changes across + /// different forks, this method will return the earliest effective number (across the + /// different branches). Only standard changes are taken into account for the current + /// limit, since any existing forced change should preclude the voter from voting. pub(crate) fn current_limit(&self) -> Option { - self.pending_changes.roots() + self.pending_standard_changes.roots() .min_by_key(|&(_, _, c)| c.effective_number()) .map(|(_, _, c)| c.effective_number()) } - /// Apply or prune any pending transitions. This method ensures that if - /// there are multiple changes in the same branch, finalizing this block - /// won't finalize past multiple transitions (i.e. transitions must be - /// finalized in-order). The given function `is_descendent_of` should return - /// `true` if the second hash (target) is a descendent of the first hash - /// (base). + /// Apply or prune any pending transitions based on a best-block trigger. + /// + /// Returns `Ok((median, new_set))` when a forced change has occurred. The + /// median represents the median last finalized block at the time the change + /// was signaled, and it should be used as the canon block when starting the + /// new grandpa voter. Only alters the internal state in this case. + /// + /// These transitions are always forced and do not lead to justifications + /// which light clients can follow. + pub(crate) fn apply_forced_changes( + &self, + best_hash: H, + best_number: N, + is_descendent_of: &F, + ) -> Result, E> + where F: Fn(&H, &H) -> Result, + { + let mut new_set = None; + + for change in self.pending_forced_changes.iter() + .take_while(|c| c.effective_number() <= best_number) // to prevent iterating too far + .filter(|c| c.effective_number() == best_number) + { + // check if the given best block is in the same branch as the block that signalled the change. + if is_descendent_of(&change.canon_hash, &best_hash)? { + // apply this change: make the set canonical + info!(target: "finality", "Applying authority set change forced at block #{:?}", + change.canon_height); + telemetry!(CONSENSUS_INFO; "afg.applying_forced_authority_set_change"; + "block" => ?change.canon_height + ); + + let median_last_finalized = match change.delay_kind { + DelayKind::Best { ref median_last_finalized } => median_last_finalized.clone(), + _ => unreachable!("pending_forced_changes only contains forced changes; forced changes have delay kind Best; qed."), + }; + + new_set = Some((median_last_finalized, AuthoritySet { + current_authorities: change.next_authorities.clone(), + set_id: self.set_id + 1, + pending_standard_changes: ForkTree::new(), // new set, new changes. + pending_forced_changes: Vec::new(), + })); + + break; + } + + // we don't wipe forced changes until another change is + // applied + } + + Ok(new_set) + } + + /// Apply or prune any pending transitions based on a finality trigger. This + /// method ensures that if there are multiple changes in the same branch, + /// finalizing this block won't finalize past multiple transitions (i.e. + /// transitions must be finalized in-order). The given function + /// `is_descendent_of` should return `true` if the second hash (target) is a + /// descendent of the first hash (base). /// /// When the set has changed, the return value will be `Ok(Some((H, N)))` /// which is the canonical block where the set last changed (i.e. the given /// hash and number). - pub(crate) fn apply_changes( + pub(crate) fn apply_standard_changes( &mut self, finalized_hash: H, finalized_number: N, is_descendent_of: &F, ) -> Result, fork_tree::Error> - where F: Fn(&H, &H) -> Result, - E: std::error::Error, + where F: Fn(&H, &H) -> Result, + E: std::error::Error, { let mut status = Status { changed: false, new_set_block: None, }; - match self.pending_changes.finalize_with_descendent_if( + match self.pending_standard_changes.finalize_with_descendent_if( &finalized_hash, finalized_number.clone(), is_descendent_of, @@ -207,9 +321,16 @@ where fork_tree::FinalizationResult::Changed(change) => { status.changed = true; + // if we are able to finalize any standard change then we can + // discard all pending forced changes (on different forks) + self.pending_forced_changes.clear(); + if let Some(change) = change { info!(target: "finality", "Applying authority set change scheduled at block #{:?}", change.canon_height); + telemetry!(CONSENSUS_INFO; "afg.applying_scheduled_authority_set_change"; + "block" => ?change.canon_height + ); self.current_authorities = change.next_authorities; self.set_id += 1; @@ -226,22 +347,26 @@ where Ok(status) } - /// Check whether the given finalized block number enacts any authority set - /// change (without triggering it), ensuring that if there are multiple - /// changes in the same branch, finalizing this block won't finalize past - /// multiple transitions (i.e. transitions must be finalized in-order). The - /// given function `is_descendent_of` should return `true` if the second - /// hash (target) is a descendent of the first hash (base). - pub fn enacts_change( + /// Check whether the given finalized block number enacts any standard + /// authority set change (without triggering it), ensuring that if there are + /// multiple changes in the same branch, finalizing this block won't + /// finalize past multiple transitions (i.e. transitions must be finalized + /// in-order). Returns `Some(true)` if the block being finalized enacts a + /// change that can be immediately applied, `Some(false)` if the block being + /// finalized enacts a change but it cannot be applied yet since there are + /// other dependent changes, and `None` if no change is enacted. The given + /// function `is_descendent_of` should return `true` if the second hash + /// (target) is a descendent of the first hash (base). + pub fn enacts_standard_change( &self, finalized_hash: H, finalized_number: N, is_descendent_of: &F, - ) -> Result> + ) -> Result, fork_tree::Error> where F: Fn(&H, &H) -> Result, E: std::error::Error, { - self.pending_changes.finalizes_any_with_descendent_if( + self.pending_standard_changes.finalizes_any_with_descendent_if( &finalized_hash, finalized_number.clone(), is_descendent_of, @@ -250,27 +375,58 @@ where } } +/// Kinds of delays for pending changes. +#[derive(Debug, Clone, Encode, Decode, PartialEq)] +pub(crate) enum DelayKind { + /// Depth in finalized chain. + Finalized, + /// Depth in best chain. The median last finalized block is calculated at the time the + /// change was signalled. + Best { median_last_finalized: N }, +} + /// A pending change to the authority set. /// /// This will be applied when the announcing block is at some depth within -/// the finalized chain. -#[derive(Debug, Clone, Encode, Decode, PartialEq)] +/// the finalized or unfinalized chain. +#[derive(Debug, Clone, Encode, PartialEq)] pub(crate) struct PendingChange { /// The new authorities and weights to apply. - pub(crate) next_authorities: Vec<(Ed25519AuthorityId, u64)>, - /// How deep in the finalized chain the announcing block must be + pub(crate) next_authorities: Vec<(AuthorityId, u64)>, + /// How deep in the chain the announcing block must be /// before the change is applied. - pub(crate) finalization_depth: N, + pub(crate) delay: N, /// The announcing block's height. pub(crate) canon_height: N, /// The announcing block's hash. pub(crate) canon_hash: H, + /// The delay kind. + pub(crate) delay_kind: DelayKind, +} + +impl Decode for PendingChange { + fn decode(value: &mut I) -> Option { + let next_authorities = Decode::decode(value)?; + let delay = Decode::decode(value)?; + let canon_height = Decode::decode(value)?; + let canon_hash = Decode::decode(value)?; + + let delay_kind = DelayKind::decode(value).unwrap_or(DelayKind::Finalized); + + Some(PendingChange { + next_authorities, + delay, + canon_height, + canon_hash, + delay_kind, + }) + } } impl + Clone> PendingChange { /// Returns the effective number this change will be applied at. pub fn effective_number(&self) -> N { - self.canon_height.clone() + self.finalization_depth.clone() + self.canon_height.clone() + self.delay.clone() } } @@ -295,28 +451,32 @@ mod tests { let mut authorities = AuthoritySet { current_authorities: Vec::new(), set_id: 0, - pending_changes: ForkTree::new(), + pending_standard_changes: ForkTree::new(), + pending_forced_changes: Vec::new(), }; let change_a = PendingChange { next_authorities: Vec::new(), - finalization_depth: 10, + delay: 10, canon_height: 5, canon_hash: "hash_a", + delay_kind: DelayKind::Finalized, }; let change_b = PendingChange { next_authorities: Vec::new(), - finalization_depth: 0, + delay: 0, canon_height: 5, canon_hash: "hash_b", + delay_kind: DelayKind::Finalized, }; let change_c = PendingChange { next_authorities: Vec::new(), - finalization_depth: 5, + delay: 5, canon_height: 10, canon_hash: "hash_c", + delay_kind: DelayKind::Finalized, }; authorities.add_pending_change(change_a.clone(), &static_is_descendent_of(false)).unwrap(); @@ -327,9 +487,29 @@ mod tests { _ => unreachable!(), })).unwrap(); + // forced changes are iterated last + let change_d = PendingChange { + next_authorities: Vec::new(), + delay: 2, + canon_height: 1, + canon_hash: "hash_d", + delay_kind: DelayKind::Best { median_last_finalized: 0 }, + }; + + let change_e = PendingChange { + next_authorities: Vec::new(), + delay: 2, + canon_height: 0, + canon_hash: "hash_e", + delay_kind: DelayKind::Best { median_last_finalized: 0 }, + }; + + authorities.add_pending_change(change_d.clone(), &static_is_descendent_of(false)).unwrap(); + authorities.add_pending_change(change_e.clone(), &static_is_descendent_of(false)).unwrap(); + assert_eq!( authorities.pending_changes().collect::>(), - vec![&change_b, &change_a, &change_c], + vec![&change_b, &change_a, &change_c, &change_e, &change_d], ); } @@ -338,25 +518,28 @@ mod tests { let mut authorities = AuthoritySet { current_authorities: Vec::new(), set_id: 0, - pending_changes: ForkTree::new(), + pending_standard_changes: ForkTree::new(), + pending_forced_changes: Vec::new(), }; - let set_a = vec![([1; 32].into(), 5)]; - let set_b = vec![([2; 32].into(), 5)]; + let set_a = vec![(AuthorityId([1; 32]), 5)]; + let set_b = vec![(AuthorityId([2; 32]), 5)]; // two competing changes at the same height on different forks let change_a = PendingChange { next_authorities: set_a.clone(), - finalization_depth: 10, + delay: 10, canon_height: 5, canon_hash: "hash_a", + delay_kind: DelayKind::Finalized, }; let change_b = PendingChange { next_authorities: set_b.clone(), - finalization_depth: 10, + delay: 10, canon_height: 5, canon_hash: "hash_b", + delay_kind: DelayKind::Finalized, }; authorities.add_pending_change(change_a.clone(), &static_is_descendent_of(true)).unwrap(); @@ -368,7 +551,7 @@ mod tests { ); // finalizing "hash_c" won't enact the change signalled at "hash_a" but it will prune out "hash_b" - let status = authorities.apply_changes("hash_c", 11, &is_descendent_of(|base, hash| match (*base, *hash) { + let status = authorities.apply_standard_changes("hash_c", 11, &is_descendent_of(|base, hash| match (*base, *hash) { ("hash_a", "hash_c") => true, ("hash_b", "hash_c") => false, _ => unreachable!(), @@ -382,7 +565,7 @@ mod tests { ); // finalizing "hash_d" will enact the change signalled at "hash_a" - let status = authorities.apply_changes("hash_d", 15, &is_descendent_of(|base, hash| match (*base, *hash) { + let status = authorities.apply_standard_changes("hash_d", 15, &is_descendent_of(|base, hash| match (*base, *hash) { ("hash_a", "hash_d") => true, _ => unreachable!(), })).unwrap(); @@ -400,25 +583,28 @@ mod tests { let mut authorities = AuthoritySet { current_authorities: Vec::new(), set_id: 0, - pending_changes: ForkTree::new(), + pending_standard_changes: ForkTree::new(), + pending_forced_changes: Vec::new(), }; - let set_a = vec![([1; 32].into(), 5)]; - let set_c = vec![([2; 32].into(), 5)]; + let set_a = vec![(AuthorityId([1; 32]), 5)]; + let set_c = vec![(AuthorityId([2; 32]), 5)]; // two competing changes at the same height on different forks let change_a = PendingChange { next_authorities: set_a.clone(), - finalization_depth: 10, + delay: 10, canon_height: 5, canon_hash: "hash_a", + delay_kind: DelayKind::Finalized, }; let change_c = PendingChange { next_authorities: set_c.clone(), - finalization_depth: 10, + delay: 10, canon_height: 30, canon_hash: "hash_c", + delay_kind: DelayKind::Finalized, }; authorities.add_pending_change(change_a.clone(), &static_is_descendent_of(true)).unwrap(); @@ -437,12 +623,12 @@ mod tests { }); // trying to finalize past `change_c` without finalizing `change_a` first - match authorities.apply_changes("hash_d", 40, &is_descendent_of) { + match authorities.apply_standard_changes("hash_d", 40, &is_descendent_of) { Err(fork_tree::Error::UnfinalizedAncestor) => {}, _ => unreachable!(), } - let status = authorities.apply_changes("hash_b", 15, &is_descendent_of).unwrap(); + let status = authorities.apply_standard_changes("hash_b", 15, &is_descendent_of).unwrap(); assert!(status.changed); assert_eq!(status.new_set_block, Some(("hash_b", 15))); @@ -450,7 +636,7 @@ mod tests { assert_eq!(authorities.set_id, 1); // after finalizing `change_a` it should be possible to finalize `change_c` - let status = authorities.apply_changes("hash_d", 40, &is_descendent_of).unwrap(); + let status = authorities.apply_standard_changes("hash_d", 40, &is_descendent_of).unwrap(); assert!(status.changed); assert_eq!(status.new_set_block, Some(("hash_d", 40))); @@ -459,37 +645,144 @@ mod tests { } #[test] - fn enacts_change_works() { + fn enacts_standard_change_works() { let mut authorities = AuthoritySet { current_authorities: Vec::new(), set_id: 0, - pending_changes: ForkTree::new(), + pending_standard_changes: ForkTree::new(), + pending_forced_changes: Vec::new(), }; - let set_a = vec![([1; 32].into(), 5)]; + let set_a = vec![(AuthorityId([1; 32]), 5)]; let change_a = PendingChange { next_authorities: set_a.clone(), - finalization_depth: 10, + delay: 10, canon_height: 5, canon_hash: "hash_a", + delay_kind: DelayKind::Finalized, + }; + + let change_b = PendingChange { + next_authorities: set_a.clone(), + delay: 10, + canon_height: 20, + canon_hash: "hash_b", + delay_kind: DelayKind::Finalized, }; authorities.add_pending_change(change_a.clone(), &static_is_descendent_of(false)).unwrap(); + authorities.add_pending_change(change_b.clone(), &static_is_descendent_of(true)).unwrap(); let is_descendent_of = is_descendent_of(|base, hash| match (*base, *hash) { - ("hash_a", "hash_b") => true, + ("hash_a", "hash_d") => true, + ("hash_a", "hash_e") => true, + ("hash_b", "hash_d") => true, + ("hash_b", "hash_e") => true, ("hash_a", "hash_c") => false, + ("hash_b", "hash_c") => false, _ => unreachable!(), }); // "hash_c" won't finalize the existing change since it isn't a descendent - assert!(!authorities.enacts_change("hash_c", 15, &is_descendent_of).unwrap()); + assert_eq!( + authorities.enacts_standard_change("hash_c", 15, &is_descendent_of).unwrap(), + None, + ); - // "hash_b" at depth 14 won't work either - assert!(!authorities.enacts_change("hash_b", 14, &is_descendent_of).unwrap()); + // "hash_d" at depth 14 won't work either + assert_eq!( + authorities.enacts_standard_change("hash_d", 14, &is_descendent_of).unwrap(), + None, + ); // but it should work at depth 15 (change height + depth) - assert!(authorities.enacts_change("hash_b", 15, &is_descendent_of).unwrap()); + assert_eq!( + authorities.enacts_standard_change("hash_d", 15, &is_descendent_of).unwrap(), + Some(true), + ); + + // finalizing "hash_e" at depth 20 will trigger change at "hash_b", but + // it can't be applied yet since "hash_a" must be applied first + assert_eq!( + authorities.enacts_standard_change("hash_e", 30, &is_descendent_of).unwrap(), + Some(false), + ); + } + + #[test] + fn forced_changes() { + let mut authorities = AuthoritySet { + current_authorities: Vec::new(), + set_id: 0, + pending_standard_changes: ForkTree::new(), + pending_forced_changes: Vec::new(), + }; + + let set_a = vec![(AuthorityId([1; 32]), 5)]; + let set_b = vec![(AuthorityId([2; 32]), 5)]; + + let change_a = PendingChange { + next_authorities: set_a.clone(), + delay: 10, + canon_height: 5, + canon_hash: "hash_a", + delay_kind: DelayKind::Best { median_last_finalized: 42 }, + }; + + let change_b = PendingChange { + next_authorities: set_b.clone(), + delay: 10, + canon_height: 5, + canon_hash: "hash_b", + delay_kind: DelayKind::Best { median_last_finalized: 0 }, + }; + + authorities.add_pending_change(change_a, &static_is_descendent_of(false)).unwrap(); + authorities.add_pending_change(change_b, &static_is_descendent_of(false)).unwrap(); + + // there's an effective change triggered at block 15 but not a standard one. + // so this should do nothing. + assert_eq!( + authorities.enacts_standard_change("hash_c", 15, &static_is_descendent_of(true)).unwrap(), + None, + ); + + // throw a standard change into the mix to prove that it's discarded + // for being on the same fork. + // + // NOTE: after https://github.com/paritytech/substrate/issues/1861 + // this should still be rejected based on the "span" rule -- it overlaps + // with another change on the same fork. + let change_c = PendingChange { + next_authorities: set_b.clone(), + delay: 3, + canon_height: 8, + canon_hash: "hash_a8", + delay_kind: DelayKind::Best { median_last_finalized: 0 }, + }; + + let is_descendent_of_a = is_descendent_of(|base: &&str, _| { + base.starts_with("hash_a") + }); + + assert!(authorities.add_pending_change(change_c, &is_descendent_of_a).is_err()); + + // too early. + assert!(authorities.apply_forced_changes("hash_a10", 10, &static_is_descendent_of(true)).unwrap().is_none()); + + // too late. + assert!(authorities.apply_forced_changes("hash_a16", 16, &static_is_descendent_of(true)).unwrap().is_none()); + + // on time -- chooses the right change. + assert_eq!( + authorities.apply_forced_changes("hash_a15", 15, &is_descendent_of_a).unwrap().unwrap(), + (42, AuthoritySet { + current_authorities: set_a, + set_id: 1, + pending_standard_changes: ForkTree::new(), + pending_forced_changes: Vec::new(), + }) + ); } } diff --git a/core/finality-grandpa/src/aux_schema.rs b/core/finality-grandpa/src/aux_schema.rs new file mode 100644 index 0000000000000000000000000000000000000000..cb41d481e3603b183205f7069308a334465b6cb1 --- /dev/null +++ b/core/finality-grandpa/src/aux_schema.rs @@ -0,0 +1,360 @@ +// 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 . + +//! Schema for stuff in the aux-db. + +use std::fmt::Debug; +use std::sync::Arc; +use parity_codec::{Encode, Decode}; +use client::backend::AuxStore; +use client::error::{Result as ClientResult, Error as ClientError, ErrorKind as ClientErrorKind}; +use fork_tree::ForkTree; +use grandpa::round::State as RoundState; +use log::{info, warn}; + +use crate::authorities::{AuthoritySet, SharedAuthoritySet, PendingChange, DelayKind}; +use crate::consensus_changes::{SharedConsensusChanges, ConsensusChanges}; +use crate::NewAuthoritySet; + +use substrate_primitives::ed25519::Public as AuthorityId; + +const VERSION_KEY: &[u8] = b"grandpa_schema_version"; +const SET_STATE_KEY: &[u8] = b"grandpa_completed_round"; +const AUTHORITY_SET_KEY: &[u8] = b"grandpa_voters"; +const CONSENSUS_CHANGES_KEY: &[u8] = b"grandpa_consensus_changes"; + +const CURRENT_VERSION: u32 = 1; + +/// The voter set state. +#[derive(Debug, Clone, Encode, Decode)] +#[cfg_attr(test, derive(PartialEq))] +pub enum VoterSetState { + /// The voter set state, currently paused. + Paused(u64, RoundState), + /// The voter set state, currently live. + Live(u64, RoundState), +} + +impl VoterSetState { + /// Yields the current state. + pub(crate) fn round(&self) -> (u64, RoundState) { + match *self { + VoterSetState::Paused(n, ref s) => (n, s.clone()), + VoterSetState::Live(n, ref s) => (n, s.clone()), + } + } +} + +type V0VoterSetState = (u64, RoundState); + +#[derive(Debug, Clone, Encode, Decode, PartialEq)] +struct V0PendingChange { + next_authorities: Vec<(AuthorityId, u64)>, + delay: N, + canon_height: N, + canon_hash: H, +} + +#[derive(Debug, Clone, Encode, Decode, PartialEq)] +struct V0AuthoritySet { + current_authorities: Vec<(AuthorityId, u64)>, + set_id: u64, + pending_changes: Vec>, +} + +impl Into> for V0AuthoritySet +where H: Clone + Debug + PartialEq, + N: Clone + Debug + Ord, +{ + fn into(self) -> AuthoritySet { + let mut pending_standard_changes = ForkTree::new(); + + for old_change in self.pending_changes { + let new_change = PendingChange { + next_authorities: old_change.next_authorities, + delay: old_change.delay, + canon_height: old_change.canon_height, + canon_hash: old_change.canon_hash, + delay_kind: DelayKind::Finalized, + }; + + if let Err(err) = pending_standard_changes.import::<_, ClientError>( + new_change.canon_hash.clone(), + new_change.canon_height.clone(), + new_change, + // previously we only supported at most one pending change per fork + &|_, _| Ok(false), + ) { + warn!(target: "afg", "Error migrating pending authority set change: {:?}.", err); + warn!(target: "afg", "Node is in a potentially inconsistent state."); + } + } + + AuthoritySet { + current_authorities: self.current_authorities, + set_id: self.set_id, + pending_forced_changes: Vec::new(), + pending_standard_changes + } + } +} + +fn load_decode(backend: &B, key: &[u8]) -> ClientResult> { + match backend.get_aux(key)? { + None => Ok(None), + Some(t) => T::decode(&mut &t[..]) + .ok_or_else( + || ClientErrorKind::Backend(format!("GRANDPA DB is corrupted.")).into(), + ) + .map(Some) + } +} + +/// Persistent data kept between runs. +pub(crate) struct PersistentData { + pub(crate) authority_set: SharedAuthoritySet, + pub(crate) consensus_changes: SharedConsensusChanges, + pub(crate) set_state: VoterSetState, +} + +/// Load or initialize persistent data from backend. +pub(crate) fn load_persistent( + backend: &B, + genesis_hash: H, + genesis_number: N, + genesis_authorities: G, +) + -> ClientResult> + where + B: AuxStore, + H: Debug + Decode + Encode + Clone + PartialEq, + N: Debug + Decode + Encode + Clone + Ord, + G: FnOnce() -> ClientResult> +{ + let version: Option = load_decode(backend, VERSION_KEY)?; + let consensus_changes = load_decode(backend, CONSENSUS_CHANGES_KEY)? + .unwrap_or_else(ConsensusChanges::::empty); + + let make_genesis_round = move || RoundState::genesis((genesis_hash, genesis_number)); + + match version { + None => { + CURRENT_VERSION.using_encoded(|s| + backend.insert_aux(&[(VERSION_KEY, s)], &[]) + )?; + + if let Some(old_set) = load_decode::<_, V0AuthoritySet>(backend, AUTHORITY_SET_KEY)? { + let new_set: AuthoritySet = old_set.into(); + backend.insert_aux(&[(AUTHORITY_SET_KEY, new_set.encode().as_slice())], &[])?; + + let set_state = match load_decode::<_, V0VoterSetState>(backend, SET_STATE_KEY)? { + Some((number, state)) => { + let set_state = VoterSetState::Live(number, state); + backend.insert_aux(&[(SET_STATE_KEY, set_state.encode().as_slice())], &[])?; + set_state + }, + None => VoterSetState::Live(0, make_genesis_round()), + }; + + return Ok(PersistentData { + authority_set: new_set.into(), + consensus_changes: Arc::new(consensus_changes.into()), + set_state, + }); + } + } + Some(1) => { + if let Some(set) = load_decode::<_, AuthoritySet>(backend, AUTHORITY_SET_KEY)? { + let set_state = match load_decode::<_, VoterSetState>(backend, SET_STATE_KEY)? { + Some(state) => state, + None => VoterSetState::Live(0, make_genesis_round()), + }; + + return Ok(PersistentData { + authority_set: set.into(), + consensus_changes: Arc::new(consensus_changes.into()), + set_state, + }); + } + } + Some(other) => return Err(ClientErrorKind::Backend( + format!("Unsupported GRANDPA DB version: {:?}", other) + ).into()), + } + + // genesis. + info!(target: "afg", "Loading GRANDPA authority set \ + from genesis on what appears to be first startup."); + + let genesis_set = AuthoritySet::genesis(genesis_authorities()?); + let genesis_state = VoterSetState::Live(0, make_genesis_round()); + backend.insert_aux( + &[ + (AUTHORITY_SET_KEY, genesis_set.encode().as_slice()), + (SET_STATE_KEY, genesis_state.encode().as_slice()), + ], + &[], + )?; + + Ok(PersistentData { + authority_set: genesis_set.into(), + set_state: genesis_state, + consensus_changes: Arc::new(consensus_changes.into()), + }) +} + +/// Update the authority set on disk after a change. +pub(crate) fn update_authority_set( + set: &AuthoritySet, + new_set: Option<&NewAuthoritySet>, + write_aux: F +) -> R where + H: Encode + Clone, + N: Encode + Clone, + F: FnOnce(&[(&'static [u8], &[u8])]) -> R, +{ + // write new authority set state to disk. + let encoded_set = set.encode(); + + if let Some(new_set) = new_set { + // we also overwrite the "last completed round" entry with a blank slate + // because from the perspective of the finality gadget, the chain has + // reset. + let round_state = RoundState::genesis(( + new_set.canon_hash.clone(), + new_set.canon_number.clone(), + )); + let set_state = VoterSetState::Live(0, round_state); + let encoded = set_state.encode(); + + write_aux(&[ + (AUTHORITY_SET_KEY, &encoded_set[..]), + (SET_STATE_KEY, &encoded[..]), + ]) + } else { + write_aux(&[(AUTHORITY_SET_KEY, &encoded_set[..])]) + } +} + +/// Write voter set state. +pub(crate) fn write_voter_set_state(backend: &B, state: &VoterSetState) + -> ClientResult<()> + where B: AuxStore, H: Encode, N: Encode +{ + backend.insert_aux( + &[(SET_STATE_KEY, state.encode().as_slice())], + &[] + ) +} + +/// Update the consensus changes. +pub(crate) fn update_consensus_changes( + set: &ConsensusChanges, + write_aux: F +) -> R where + H: Encode + Clone, + N: Encode + Clone, + F: FnOnce(&[(&'static [u8], &[u8])]) -> R, +{ + write_aux(&[(CONSENSUS_CHANGES_KEY, set.encode().as_slice())]) +} + +#[cfg(test)] +pub(crate) fn load_authorities(backend: &B) + -> Option> { + load_decode::<_, AuthoritySet>(backend, AUTHORITY_SET_KEY) + .expect("backend error") +} + +#[cfg(test)] +mod test { + use substrate_primitives::H256; + use test_client; + use super::*; + + #[test] + fn load_decode_migrates_data_format() { + let client = test_client::new(); + + let authorities = vec![(AuthorityId::default(), 100)]; + let set_id = 3; + let round_number = 42; + let round_state = RoundState:: { + prevote_ghost: None, + finalized: None, + estimate: None, + completable: false, + }; + + { + let authority_set = V0AuthoritySet:: { + current_authorities: authorities.clone(), + pending_changes: Vec::new(), + set_id, + }; + + let voter_set_state = (round_number, round_state.clone()); + + client.insert_aux( + &[ + (AUTHORITY_SET_KEY, authority_set.encode().as_slice()), + (SET_STATE_KEY, voter_set_state.encode().as_slice()), + ], + &[], + ).unwrap(); + } + + assert_eq!( + load_decode::<_, u32>(&client, VERSION_KEY).unwrap(), + None, + ); + + // should perform the migration + load_persistent( + &client, + H256::random(), + 0, + || unreachable!(), + ).unwrap(); + + assert_eq!( + load_decode::<_, u32>(&client, VERSION_KEY).unwrap(), + Some(1), + ); + + let PersistentData { authority_set, set_state, .. } = load_persistent( + &client, + H256::random(), + 0, + || unreachable!(), + ).unwrap(); + + assert_eq!( + *authority_set.inner().read(), + AuthoritySet { + current_authorities: authorities, + pending_standard_changes: ForkTree::new(), + pending_forced_changes: Vec::new(), + set_id, + }, + ); + + assert_eq!( + set_state, + VoterSetState::Live(round_number, round_state), + ); + } +} diff --git a/core/finality-grandpa/src/communication.rs b/core/finality-grandpa/src/communication.rs index 4f6024fb95b3dcb175f593974f2a963da2c650a2..f498b51460ace8cb46e6276a178e40262680896c 100644 --- a/core/finality-grandpa/src/communication.rs +++ b/core/finality-grandpa/src/communication.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -21,15 +21,18 @@ use std::collections::HashMap; use std::sync::Arc; use grandpa::VoterSet; +use grandpa::Message::{Prevote, Precommit}; use futures::prelude::*; use futures::sync::mpsc; use log::{debug, trace}; use parity_codec::{Encode, Decode}; -use substrate_primitives::{ed25519, Ed25519AuthorityId}; +use substrate_primitives::{ed25519, Pair}; +use substrate_telemetry::{telemetry, CONSENSUS_INFO}; use runtime_primitives::traits::Block as BlockT; use tokio::timer::Interval; use crate::{Error, Network, Message, SignedMessage, Commit, CompactCommit, GossipMessage, FullCommitMessage, VoteOrPrecommitMessage}; +use ed25519::{Public as AuthorityId, Signature as AuthoritySignature}; fn localized_payload(round: u64, set_id: u64, message: &E) -> Vec { (message, round, set_id).encode() @@ -127,12 +130,12 @@ impl> Future for BroadcastWorker { if rebroadcast { let SetId(set_id) = self.set_id; if let Some((Round(c_round), ref c_commit)) = self.last_commit { - self.network.send_commit(c_round, set_id, c_commit.clone()); + self.network.send_commit(c_round, set_id, c_commit.clone(), true); } let Round(round) = self.round_messages.0; for message in self.round_messages.1.iter().cloned() { - self.network.send_message(round, set_id, message); + self.network.send_message(round, set_id, message, true); } for (&announce_hash, &Round(round)) in &self.announcements { @@ -140,6 +143,7 @@ impl> Future for BroadcastWorker { } } } + loop { match self.incoming_broadcast.poll().expect("UnboundedReceiver does not yield errors; qed") { Async::NotReady => return Ok(Async::NotReady), @@ -165,7 +169,7 @@ impl> Future for BroadcastWorker { } // always send out to network. - self.network.send_commit(round.0, self.set_id.0, commit); + self.network.send_commit(round.0, self.set_id.0, commit, false); } Broadcast::Message(round, set_id, message) => { if self.set_id == set_id { @@ -179,7 +183,7 @@ impl> Future for BroadcastWorker { } // always send out to network. - self.network.send_message(round.0, set_id.0, message); + self.network.send_message(round.0, set_id.0, message, false); } Broadcast::Announcement(round, set_id, hash) => { if self.set_id == set_id { @@ -212,7 +216,7 @@ impl> Network for BroadcastHandle { self.network.messages_for(round, set_id) } - fn send_message(&self, round: u64, set_id: u64, message: Vec) { + fn send_message(&self, round: u64, set_id: u64, message: Vec, _force: bool) { let _ = self.relay.unbounded_send(Broadcast::Message(Round(round), SetId(set_id), message)); } @@ -228,7 +232,7 @@ impl> Network for BroadcastHandle { self.network.commit_messages(set_id) } - fn send_commit(&self, round: u64, set_id: u64, message: Vec) { + fn send_commit(&self, round: u64, set_id: u64, message: Vec, _force: bool) { let _ = self.relay.unbounded_send(Broadcast::Commit(Round(round), SetId(set_id), message)); } @@ -242,14 +246,14 @@ impl> Network for BroadcastHandle { // check a message. pub(crate) fn check_message_sig( message: &Message, - id: &Ed25519AuthorityId, - signature: &ed25519::Signature, + id: &AuthorityId, + signature: &AuthoritySignature, round: u64, set_id: u64, ) -> Result<(), ()> { - let as_public = ed25519::Public::from_raw(id.0); + let as_public = AuthorityId::from_raw(id.0); let encoded_raw = localized_payload(round, set_id, message); - if ed25519::verify_strong(signature, &encoded_raw, as_public) { + if ed25519::Pair::verify(signature, &encoded_raw, as_public) { Ok(()) } else { debug!(target: "afg", "Bad signature on message from {:?}", id); @@ -261,7 +265,7 @@ pub(crate) fn check_message_sig( /// the output stream checks signatures also. pub(crate) fn checked_message_stream( inner: S, - voters: Arc>, + voters: Arc>, ) -> impl Stream,Error=Error> where S: Stream,Error=()> @@ -282,6 +286,24 @@ pub(crate) fn checked_message_stream( debug!(target: "afg", "Skipping message from unknown voter {}", msg.message.id); return Ok(None); } + + match &msg.message.message { + Prevote(prevote) => { + telemetry!(CONSENSUS_INFO; "afg.received_prevote"; + "voter" => ?format!("{}", msg.message.id), + "target_number" => ?prevote.target_number, + "target_hash" => ?prevote.target_hash, + ); + }, + Precommit(precommit) => { + telemetry!(CONSENSUS_INFO; "afg.received_precommit"; + "voter" => ?format!("{}", msg.message.id), + "target_number" => ?precommit.target_number, + "target_hash" => ?precommit.target_hash, + ); + }, + }; + Ok(Some(msg.message)) } _ => { @@ -297,7 +319,7 @@ pub(crate) fn checked_message_stream( pub(crate) struct OutgoingMessages> { round: u64, set_id: u64, - locals: Option<(Arc, Ed25519AuthorityId)>, + locals: Option<(Arc, AuthorityId)>, sender: mpsc::UnboundedSender>, network: N, } @@ -309,7 +331,7 @@ impl> Sink for OutgoingMessages fn start_send(&mut self, msg: Message) -> StartSend, Error> { // when locals exist, sign messages on import - if let Some((ref pair, local_id)) = self.locals { + if let Some((ref pair, ref local_id)) = self.locals { let encoded = localized_payload(self.round, self.set_id, &msg); let signature = pair.sign(&encoded[..]); @@ -317,7 +339,7 @@ impl> Sink for OutgoingMessages let signed = SignedMessage:: { message: msg, signature, - id: local_id, + id: local_id.clone(), }; let message = GossipMessage::VoteOrPrecommit(VoteOrPrecommitMessage:: { @@ -329,7 +351,7 @@ impl> Sink for OutgoingMessages // announce our block hash to peers and propagate the // message. self.network.announce(self.round, self.set_id, target_hash); - self.network.send_message(self.round, self.set_id, message.encode()); + self.network.send_message(self.round, self.set_id, message.encode(), false); // forward the message to the inner sender. let _ = self.sender.unbounded_send(signed); @@ -361,7 +383,7 @@ pub(crate) fn outgoing_messages>( round: u64, set_id: u64, local_key: Option>, - voters: Arc>, + voters: Arc>, network: N, ) -> ( impl Stream,Error=Error>, @@ -369,7 +391,7 @@ pub(crate) fn outgoing_messages>( ) { let locals = local_key.and_then(|pair| { let public = pair.public(); - let id = Ed25519AuthorityId(public.0); + let id = AuthorityId(public.0); if voters.contains_key(&id) { Some((pair, id)) } else { @@ -395,7 +417,7 @@ pub(crate) fn outgoing_messages>( fn check_compact_commit( msg: CompactCommit, - voters: &VoterSet, + voters: &VoterSet, ) -> Option> { if msg.precommits.len() != msg.auth_data.len() || msg.precommits.is_empty() { debug!(target: "afg", "Skipping malformed compact commit"); @@ -417,7 +439,7 @@ fn check_compact_commit( /// messages. pub(crate) fn checked_commit_stream( inner: S, - voters: Arc>, + voters: Arc>, ) -> impl Stream),Error=Error> where S: Stream,Error=()> @@ -435,6 +457,15 @@ pub(crate) fn checked_commit_stream( match msg { GossipMessage::Commit(msg) => { let round = msg.round; + 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, + "target_hash" => ?msg.message.target_hash, + ); check_compact_commit::(msg.message, &*voters).map(move |c| (round, c)) }, _ => { @@ -476,6 +507,9 @@ impl> Sink for CommitsOut { } let (round, commit) = input; + telemetry!(CONSENSUS_INFO; "afg.commit_issued"; + "target_number" => ?commit.target_number, "target_hash" => ?commit.target_hash, + ); let (precommits, auth_data) = commit.precommits.into_iter() .map(|signed| (signed.precommit, (signed.signature, signed.id))) .unzip(); @@ -493,7 +527,7 @@ impl> Sink for CommitsOut { message: compact_commit, }); - self.network.send_commit(round, self.set_id, Encode::encode(&message)); + self.network.send_commit(round, self.set_id, Encode::encode(&message), false); Ok(AsyncSink::Ready) } diff --git a/core/finality-grandpa/src/consensus_changes.rs b/core/finality-grandpa/src/consensus_changes.rs index 3e891e8b303445f5d9d0071ad32d7077bbf54ed6..cbd7b30f8e7a5ebcb2883baf4ea0be20683357d6 100644 --- a/core/finality-grandpa/src/consensus_changes.rs +++ b/core/finality-grandpa/src/consensus_changes.rs @@ -15,7 +15,7 @@ // along with Substrate. If not, see . use std::sync::Arc; -use parity_codec_derive::{Encode, Decode}; +use parity_codec::{Encode, Decode}; /// Consensus-related data changes tracker. #[derive(Clone, Debug, Encode, Decode)] @@ -23,11 +23,14 @@ pub(crate) struct ConsensusChanges { pending_changes: Vec<(N, H)>, } -impl ConsensusChanges { +impl ConsensusChanges { /// Create empty consensus changes. pub(crate) fn empty() -> Self { ConsensusChanges { pending_changes: Vec::new(), } } +} + +impl ConsensusChanges { /// Note unfinalized change of consensus-related data. pub(crate) fn note_change(&mut self, at: (N, H)) { diff --git a/core/finality-grandpa/src/environment.rs b/core/finality-grandpa/src/environment.rs index 71424e8be9161089355263d97c8a9e59f9d78496..685337a311b401f9248a09745465dc9dcb311d76 100644 --- a/core/finality-grandpa/src/environment.rs +++ b/core/finality-grandpa/src/environment.rs @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use std::fmt; use std::sync::Arc; use std::time::{Duration, Instant}; @@ -22,6 +21,7 @@ use log::{debug, warn, info}; use parity_codec::Encode; use futures::prelude::*; use tokio::timer::Delay; +use parking_lot::RwLock; use client::{ backend::Backend, BlockchainEvents, CallExecutor, Client, error::Error as ClientError @@ -33,26 +33,58 @@ use runtime_primitives::generic::BlockId; use runtime_primitives::traits::{ As, Block as BlockT, Header as HeaderT, NumberFor, One, Zero, }; -use substrate_primitives::{Blake2Hasher, ed25519,Ed25519AuthorityId, H256}; +use substrate_primitives::{Blake2Hasher, ed25519, H256, Pair}; +use substrate_telemetry::{telemetry, CONSENSUS_INFO}; use crate::{ - AUTHORITY_SET_KEY, CONSENSUS_CHANGES_KEY, LAST_COMPLETED_KEY, - Commit, Config, Error, Network, Precommit, Prevote, LastCompleted, + Commit, Config, Error, Network, Precommit, Prevote, + CommandOrError, NewAuthoritySet, VoterCommand, }; -use crate::authorities::{AuthoritySet, SharedAuthoritySet}; + +use crate::authorities::SharedAuthoritySet; use crate::consensus_changes::SharedConsensusChanges; use crate::justification::GrandpaJustification; use crate::until_imported::UntilVoteTargetImported; +use ed25519::Public as AuthorityId; + +/// Data about a completed round. +pub(crate) type CompletedRound = (u64, RoundState); + +/// A read-only view of the last completed round. +pub(crate) struct LastCompletedRound { + inner: RwLock>, +} + +impl LastCompletedRound { + /// Create a new tracker based on some starting last-completed round. + pub(crate) fn new(round: CompletedRound) -> Self { + LastCompletedRound { inner: RwLock::new(round) } + } + + /// Read the last completed round. + pub(crate) fn read(&self) -> CompletedRound { + self.inner.read().clone() + } + + // NOTE: not exposed outside of this module intentionally. + fn with(&self, f: F) -> R + where F: FnOnce(&mut CompletedRound) -> R + { + f(&mut *self.inner.write()) + } +} + /// The environment we run GRANDPA in. pub(crate) struct Environment, RA> { pub(crate) inner: Arc>, - pub(crate) voters: Arc>, + pub(crate) voters: Arc>, pub(crate) config: Config, pub(crate) authority_set: SharedAuthoritySet>, pub(crate) consensus_changes: SharedConsensusChanges>, pub(crate) network: N, pub(crate) set_id: u64, + pub(crate) last_completed: LastCompletedRound>, } impl, B, E, N, RA> grandpa::Chain> for Environment where @@ -166,54 +198,6 @@ impl, B, E, N, RA> grandpa::Chain { - pub(crate) canon_number: N, - pub(crate) canon_hash: H, - pub(crate) set_id: u64, - pub(crate) authorities: Vec<(Ed25519AuthorityId, u64)>, -} - -/// Signals either an early exit of a voter or an error. -#[derive(Debug)] -pub(crate) enum ExitOrError { - /// An error occurred. - Error(Error), - /// Early exit of the voter: the new set ID and the new authorities along with respective weights. - AuthoritiesChanged(NewAuthoritySet), -} - -impl From for ExitOrError { - fn from(e: Error) -> Self { - ExitOrError::Error(e) - } -} - -impl From for ExitOrError { - fn from(e: ClientError) -> Self { - ExitOrError::Error(Error::Client(e)) - } -} - -impl From for ExitOrError { - fn from(e: grandpa::Error) -> Self { - ExitOrError::Error(Error::from(e)) - } -} - -impl ::std::error::Error for ExitOrError { } - -impl fmt::Display for ExitOrError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ExitOrError::Error(ref e) => write!(f, "{:?}", e), - ExitOrError::AuthoritiesChanged(_) => write!(f, "restarting voter on new authorities"), - } - } -} - - impl, N, RA> voter::Environment> for Environment where Block: 'static, B: Backend + 'static, @@ -224,7 +208,7 @@ impl, N, RA> voter::Environment: BlockNumberOps, { type Timer = Box + Send>; - type Id = Ed25519AuthorityId; + type Id = AuthorityId; type Signature = ed25519::Signature; // regular round message streams @@ -237,7 +221,7 @@ impl, N, RA> voter::Environment + Send>; - type Error = ExitOrError>; + type Error = CommandOrError>; fn round_data( &self, @@ -295,17 +279,32 @@ impl, N, RA> voter::Environment, round: u64, commit: Commit) -> Result<(), Self::Error> { + use client::blockchain::HeaderBackend; + + let status = self.inner.backend().blockchain().info()?; + if number <= status.finalized_number && self.inner.backend().blockchain().hash(number)? == Some(hash) { + // This can happen after a forced change (triggered by the finality tracker when finality is stalled), since + // the voter will be restarted at the median last finalized block, which can be lower than the local best + // finalized block. + warn!(target: "afg", "Re-finalized block #{:?} ({:?}) in the canonical chain, current best finalized is #{:?}", + hash, + number, + status.finalized_number, + ); + + return Ok(()); + } + finalize_block( &*self.inner, &self.authority_set, @@ -375,7 +374,7 @@ pub(crate) fn finalize_block, E, RA>( hash: Block::Hash, number: NumberFor, justification_or_commit: JustificationOrCommit, -) -> Result<(), ExitOrError>> where +) -> Result<(), CommandOrError>> where B: Backend, E: CallExecutor + Send + Sync, RA: Send + Sync, @@ -385,72 +384,43 @@ pub(crate) fn finalize_block, E, RA>( // FIXME #1483: clone only when changed let old_authority_set = authority_set.clone(); - // needed in case there is an authority set change, used for reverting in - // case of error - let mut old_last_completed = None; + // holds the old consensus changes in case it is changed below, needed for + // reverting in case of failure + let mut old_consensus_changes = None; let mut consensus_changes = consensus_changes.lock(); - let status = authority_set.apply_changes( - hash, - number, - &is_descendent_of(client, None), - ).map_err(|e| Error::Safety(e.to_string()))?; - - if status.changed { - // write new authority set state to disk. - let encoded_set = authority_set.encode(); - - let write_result = if let Some((ref canon_hash, ref canon_number)) = status.new_set_block { - // we also overwrite the "last completed round" entry with a blank slate - // because from the perspective of the finality gadget, the chain has - // reset. - let round_state = RoundState::genesis((*canon_hash, *canon_number)); - let last_completed: LastCompleted<_, _> = (0, round_state); - let encoded = last_completed.encode(); - - old_last_completed = Backend::get_aux(&**client.backend(), LAST_COMPLETED_KEY)?; - - Backend::insert_aux( - &**client.backend(), - &[ - (AUTHORITY_SET_KEY, &encoded_set[..]), - (LAST_COMPLETED_KEY, &encoded[..]), - ], - &[] - ) - } else { - Backend::insert_aux(&**client.backend(), &[(AUTHORITY_SET_KEY, &encoded_set[..])], &[]) - }; + let canon_at_height = |canon_number| { + // "true" because the block is finalized + canonical_at_height(client, (hash, number), true, canon_number) + }; - if let Err(e) = write_result { - warn!(target: "finality", "Failed to write updated authority set to disk. Bailing."); - warn!(target: "finality", "Node is in a potentially inconsistent state."); + let update_res: Result<_, Error> = client.lock_import_and_run(|import_op| { + let status = authority_set.apply_standard_changes( + hash, + number, + &is_descendent_of(client, None), + ).map_err(|e| Error::Safety(e.to_string()))?; - return Err(e.into()); - } - } + // check if this is this is the first finalization of some consensus changes + let (alters_consensus_changes, finalizes_consensus_changes) = consensus_changes + .finalize((number, hash), &canon_at_height)?; - // check if this is this is the first finalization of some consensus changes - let (alters_consensus_changes, finalizes_consensus_changes) = consensus_changes - .finalize((number, hash), |at_height| canonical_at_height(client, (hash, number), at_height))?; + if alters_consensus_changes { + old_consensus_changes = Some(consensus_changes.clone()); - // holds the old consensus changes in case it is changed below, needed for - // reverting in case of failure - let mut old_consensus_changes = None; - if alters_consensus_changes { - old_consensus_changes = Some(consensus_changes.clone()); + let write_result = crate::aux_schema::update_consensus_changes( + &*consensus_changes, + |insert| client.apply_aux(import_op, insert, &[]), + ); - let encoded = consensus_changes.encode(); - let write_result = Backend::insert_aux(&**client.backend(), &[(CONSENSUS_CHANGES_KEY, &encoded[..])], &[]); - if let Err(e) = write_result { - warn!(target: "finality", "Failed to write updated consensus changes to disk. Bailing."); - warn!(target: "finality", "Node is in a potentially inconsistent state."); + if let Err(e) = write_result { + warn!(target: "finality", "Failed to write updated consensus changes to disk. Bailing."); + warn!(target: "finality", "Node is in a potentially inconsistent state."); - return Err(e.into()); + return Err(e.into()); + } } - } - let aux = |authority_set: &AuthoritySet>| { // NOTE: this code assumes that honest voters will never vote past a // transition block, thus we don't have to worry about the case where // we have a transition with `effective_block = N`, but we finalize @@ -496,12 +466,15 @@ pub(crate) fn finalize_block, E, RA>( // ideally some handle to a synchronization oracle would be used // to avoid unconditionally notifying. - client.finalize_block(BlockId::Hash(hash), justification, true).map_err(|e| { + client.apply_finality(import_op, BlockId::Hash(hash), justification, true).map_err(|e| { warn!(target: "finality", "Error applying finality to block {:?}: {:?}", (hash, number), e); e })?; + telemetry!(CONSENSUS_INFO; "afg.finalized_blocks_up_to"; + "number" => ?number, "hash" => ?hash, + ); - if let Some((canon_hash, canon_number)) = status.new_set_block { + let new_authorities = if let Some((canon_hash, canon_number)) = status.new_set_block { // the authority set has changed. let (new_id, set_ref) = authority_set.current(); @@ -511,54 +484,51 @@ pub(crate) fn finalize_block, E, RA>( info!("Applying GRANDPA set change to new set {:?}", set_ref); } - Err(ExitOrError::AuthoritiesChanged(NewAuthoritySet { + telemetry!(CONSENSUS_INFO; "afg.generating_new_authority_set"; + "number" => ?canon_number, "hash" => ?canon_hash, + "authorities" => ?set_ref.to_vec(), + "set_id" => ?new_id, + ); + Some(NewAuthoritySet { canon_hash, canon_number, set_id: new_id, authorities: set_ref.to_vec(), - })) + }) } else { - Ok(()) - } - }; - - match aux(&authority_set) { - Err(ExitOrError::Error(err)) => { - debug!(target: "afg", "Reverting authority set and/or consensus changes after block finalization error: {:?}", err); - - let mut revert_aux = Vec::new(); - - if status.changed { - revert_aux.push((AUTHORITY_SET_KEY, old_authority_set.encode())); - if let Some(old_last_completed) = old_last_completed { - revert_aux.push((LAST_COMPLETED_KEY, old_last_completed)); - } - - *authority_set = old_authority_set.clone(); - } - - if let Some(old_consensus_changes) = old_consensus_changes { - revert_aux.push((CONSENSUS_CHANGES_KEY, old_consensus_changes.encode())); - - *consensus_changes = old_consensus_changes; - } + None + }; - let write_result = Backend::insert_aux( - &**client.backend(), - revert_aux.iter().map(|(k, v)| (*k, &**v)).collect::>().iter(), - &[], + if status.changed { + let write_result = crate::aux_schema::update_authority_set( + &authority_set, + new_authorities.as_ref(), + |insert| client.apply_aux(import_op, insert, &[]), ); if let Err(e) = write_result { - warn!(target: "finality", "Failed to revert consensus changes to disk. Bailing."); + warn!(target: "finality", "Failed to write updated authority set to disk. Bailing."); warn!(target: "finality", "Node is in a potentially inconsistent state."); return Err(e.into()); } + } - Err(ExitOrError::Error(err)) - }, - res => res, + Ok(new_authorities.map(VoterCommand::ChangeAuthorities)) + }); + + match update_res { + Ok(Some(command)) => Err(CommandOrError::VoterCommand(command)), + Ok(None) => Ok(()), + Err(e) => { + *authority_set = old_authority_set; + + if let Some(old_consensus_changes) = old_consensus_changes { + *consensus_changes = old_consensus_changes; + } + + Err(CommandOrError::Error(e)) + } } } @@ -567,27 +537,39 @@ pub(crate) fn finalize_block, E, RA>( pub(crate) fn canonical_at_height, RA>( client: &Client, base: (Block::Hash, NumberFor), + base_is_canonical: bool, height: NumberFor, ) -> Result, ClientError> where B: Backend, E: CallExecutor + Send + Sync, { - use runtime_primitives::traits::{One, Zero}; + use runtime_primitives::traits::{One, Zero, BlockNumberToHash}; if height > base.1 { return Ok(None); } if height == base.1 { - return Ok(Some(base.0)); + if base_is_canonical { + return Ok(Some(base.0)); + } else { + return Ok(client.block_number_to_hash(height)); + } + } else if base_is_canonical { + return Ok(client.block_number_to_hash(height)); } - let mut current = match client.header(&BlockId::Hash(base.0))? { + let one = NumberFor::::one(); + + // start by getting _canonical_ block with number at parent position and then iterating + // backwards by hash. + let mut current = match client.header(&BlockId::Number(base.1 - one))? { Some(header) => header, _ => return Ok(None), }; - let mut steps = base.1 - height; + // we've already checked that base > height above. + let mut steps = base.1 - height - one; while steps > NumberFor::::zero() { current = match client.header(&BlockId::Hash(*current.parent_hash()))? { @@ -595,7 +577,7 @@ pub(crate) fn canonical_at_height, RA>( _ => return Ok(None), }; - steps -= NumberFor::::one(); + steps -= one; } Ok(Some(current.hash())) diff --git a/core/finality-grandpa/src/finality_proof.rs b/core/finality-grandpa/src/finality_proof.rs index efce7aa1cb323ac094e8dc54c66ed44d2a4cbc31..2b34a094a06494cad6ff2c1d49f37a35bcf6afe6 100644 --- a/core/finality-grandpa/src/finality_proof.rs +++ b/core/finality-grandpa/src/finality_proof.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -37,13 +37,14 @@ use client::{ light::fetcher::RemoteCallRequest, }; use parity_codec::{Encode, Decode}; -use parity_codec_derive::{Encode, Decode}; use grandpa::BlockNumberOps; use runtime_primitives::generic::BlockId; use runtime_primitives::traits::{ NumberFor, Block as BlockT, Header as HeaderT, One, }; -use substrate_primitives::{Ed25519AuthorityId, H256}; +use substrate_primitives::{ed25519, H256}; +use ed25519::Public as AuthorityId; +use substrate_telemetry::{telemetry, CONSENSUS_INFO}; use crate::justification::GrandpaJustification; @@ -170,14 +171,14 @@ fn do_check_finality_proof, C, J>( } } - // check that the last header in finalization path is the jsutification target block + // check that the last header in finalization path is the justification target block let just_block = proof.justification.target_block(); { let finalized_header = proof.finalization_path.last() .expect("checked above that proof.finalization_path is not empty; qed"); if *finalized_header.number() != just_block.0 || finalized_header.hash() != just_block.1 { return Err(ClientErrorKind::BadJustification( - "finality proof: target jsutification block is not a part of finalized path".into() + "finality proof: target justification block is not a part of finalized path".into() ).into()); } } @@ -190,12 +191,14 @@ fn do_check_finality_proof, C, J>( call_data: vec![], retry_count: None, })?; - let grandpa_authorities: Vec<(Ed25519AuthorityId, u64)> = Decode::decode(&mut &grandpa_authorities[..]) + let grandpa_authorities: Vec<(AuthorityId, u64)> = Decode::decode(&mut &grandpa_authorities[..]) .ok_or_else(|| ClientErrorKind::BadJustification("failed to decode GRANDPA authorities set proof".into()))?; // and now check justification proof.justification.verify(set_id, &grandpa_authorities.into_iter().collect())?; + telemetry!(CONSENSUS_INFO; "afg.finality_proof_ok"; + "set_id" => ?set_id, "finalized_header_hash" => ?block.1); Ok(proof.finalization_path) } @@ -223,7 +226,7 @@ trait ProvableJustification: Encode + Decode { fn target_block(&self) -> (Header::Number, Header::Hash); /// Verify justification with respect to authorities set and authorities set id. - fn verify(&self, set_id: u64, authorities: &VoterSet) -> ClientResult<()>; + fn verify(&self, set_id: u64, authorities: &VoterSet) -> ClientResult<()>; } impl> ProvableJustification for GrandpaJustification @@ -234,7 +237,7 @@ impl> ProvableJustification for GrandpaJ (self.commit.target_number, self.commit.target_hash) } - fn verify(&self, set_id: u64, authorities: &VoterSet) -> ClientResult<()> { + fn verify(&self, set_id: u64, authorities: &VoterSet) -> ClientResult<()> { GrandpaJustification::verify(self, set_id, authorities) } } @@ -254,12 +257,12 @@ mod tests { impl ProvableJustification

for ValidFinalityProof { fn target_block(&self) -> (u64, H256) { (3, header(3).hash()) } - fn verify(&self, set_id: u64, authorities: &VoterSet) -> ClientResult<()> { + fn verify(&self, set_id: u64, authorities: &VoterSet) -> ClientResult<()> { assert_eq!(set_id, 1); assert_eq!(authorities, &vec![ - (Ed25519AuthorityId([1u8; 32]), 1), - (Ed25519AuthorityId([2u8; 32]), 2), - (Ed25519AuthorityId([3u8; 32]), 3), + (AuthorityId([1u8; 32]), 1), + (AuthorityId([2u8; 32]), 2), + (AuthorityId([3u8; 32]), 3), ].into_iter().collect()); Ok(()) } @@ -388,7 +391,7 @@ mod tests { impl ProvableJustification
for InvalidFinalityProof { fn target_block(&self) -> (u64, H256) { (3, header(3).hash()) } - fn verify(&self, _set_id: u64, _authorities: &VoterSet) -> ClientResult<()> { + fn verify(&self, _set_id: u64, _authorities: &VoterSet) -> ClientResult<()> { Err(ClientErrorKind::Backend("test error".into()).into()) } } @@ -416,9 +419,9 @@ mod tests { .unwrap().unwrap(); assert_eq!(do_check_finality_proof::( |_| Ok(vec![ - (Ed25519AuthorityId([1u8; 32]), 1u64), - (Ed25519AuthorityId([2u8; 32]), 2u64), - (Ed25519AuthorityId([3u8; 32]), 3u64), + (AuthorityId([1u8; 32]), 1u64), + (AuthorityId([2u8; 32]), 2u64), + (AuthorityId([3u8; 32]), 3u64), ].encode()), header(1), (2, header(2).hash()), diff --git a/core/finality-grandpa/src/import.rs b/core/finality-grandpa/src/import.rs index 11306f72195c5d614cdb24d8af0e2945efcc1e6a..0c59bd60fe09afd8bd56b8f7fa6e8abca2992861 100644 --- a/core/finality-grandpa/src/import.rs +++ b/core/finality-grandpa/src/import.rs @@ -19,9 +19,12 @@ use std::sync::Arc; use log::{debug, trace, info}; use parity_codec::Encode; use futures::sync::mpsc; +use parking_lot::RwLockWriteGuard; use client::{blockchain, CallExecutor, Client}; +use client::blockchain::HeaderBackend; use client::backend::Backend; +use client::runtime_api::ApiExt; use consensus_common::{ BlockImport, Error as ConsensusError, ErrorKind as ConsensusErrorKind, ImportBlock, ImportResult, JustificationImport, @@ -33,14 +36,16 @@ use runtime_primitives::traits::{ Block as BlockT, DigestFor, DigestItemFor, DigestItem, Header as HeaderT, NumberFor, ProvideRuntimeApi, }; -use substrate_primitives::{H256, Ed25519AuthorityId, Blake2Hasher}; +use substrate_primitives::{H256, ed25519, Blake2Hasher}; -use crate::{AUTHORITY_SET_KEY, Error}; -use crate::authorities::SharedAuthoritySet; +use crate::{Error, CommandOrError, NewAuthoritySet, VoterCommand}; +use crate::authorities::{AuthoritySet, SharedAuthoritySet, DelayKind, PendingChange}; use crate::consensus_changes::SharedConsensusChanges; -use crate::environment::{finalize_block, is_descendent_of, ExitOrError, NewAuthoritySet}; +use crate::environment::{finalize_block, is_descendent_of}; use crate::justification::GrandpaJustification; +use ed25519::Public as AuthorityId; + /// A block-import handler for GRANDPA. /// /// This scans each imported block for signals of changing authority set. @@ -53,7 +58,7 @@ use crate::justification::GrandpaJustification; pub struct GrandpaBlockImport, RA, PRA> { inner: Arc>, authority_set: SharedAuthoritySet>, - authority_set_change: mpsc::UnboundedSender>>, + send_voter_commands: mpsc::UnboundedSender>>, consensus_changes: SharedConsensusChanges>, api: Arc, } @@ -64,7 +69,7 @@ impl, RA, PRA> JustificationImport B: Backend + 'static, E: CallExecutor + 'static + Clone + Send + Sync, DigestFor: Encode, - DigestItemFor: DigestItem, + DigestItemFor: DigestItem, RA: Send + Sync, PRA: ProvideRuntimeApi, PRA::Api: GrandpaApi, @@ -80,7 +85,8 @@ impl, RA, PRA> JustificationImport // request justifications for all pending changes for which change blocks have already been imported let authorities = self.authority_set.inner().read(); for pending_change in authorities.pending_changes() { - if pending_change.effective_number() > chain_info.finalized_number && + if pending_change.delay_kind == DelayKind::Finalized && + pending_change.effective_number() > chain_info.finalized_number && pending_change.effective_number() <= chain_info.best_number { let effective_block_hash = self.inner.best_containing( @@ -109,28 +115,284 @@ impl, RA, PRA> JustificationImport } } +enum AppliedChanges { + Standard(bool), // true if the change is ready to be applied (i.e. it's a root) + Forced(NewAuthoritySet), + None, +} + +impl AppliedChanges { + fn needs_justification(&self) -> bool { + match *self { + AppliedChanges::Standard(_) => true, + AppliedChanges::Forced(_) | AppliedChanges::None => false, + } + } +} + +struct PendingSetChanges<'a, Block: 'a + BlockT> { + just_in_case: Option<( + AuthoritySet>, + RwLockWriteGuard<'a, AuthoritySet>>, + )>, + applied_changes: AppliedChanges>, + do_pause: bool, +} + +impl<'a, Block: 'a + BlockT> PendingSetChanges<'a, Block> { + // revert the pending set change explicitly. + fn revert(self) { } + + fn defuse(mut self) -> (AppliedChanges>, bool) { + self.just_in_case = None; + let applied_changes = ::std::mem::replace(&mut self.applied_changes, AppliedChanges::None); + (applied_changes, self.do_pause) + } +} + +impl<'a, Block: 'a + BlockT> Drop for PendingSetChanges<'a, Block> { + fn drop(&mut self) { + if let Some((old_set, mut authorities)) = self.just_in_case.take() { + *authorities = old_set; + } + } +} + +impl, RA, PRA> GrandpaBlockImport where + NumberFor: grandpa::BlockNumberOps, + B: Backend + 'static, + E: CallExecutor + 'static + Clone + Send + Sync, + DigestFor: Encode, + DigestItemFor: DigestItem, + RA: Send + Sync, + PRA: ProvideRuntimeApi, + PRA::Api: GrandpaApi, +{ + // check for a new authority set change. + fn check_new_change(&self, header: &Block::Header, hash: Block::Hash) + -> Result>>, ConsensusError> + { + let at = BlockId::hash(*header.parent_hash()); + let digest = header.digest(); + + let api = self.api.runtime_api(); + + // check for forced change. + { + let maybe_change = api.grandpa_forced_change( + &at, + digest, + ); + + match maybe_change { + Err(e) => match api.has_api_with::, _>(&at, |v| v >= 2) { + Err(e) => return Err(ConsensusErrorKind::ClientImport(e.to_string()).into()), + Ok(true) => { + // API version is high enough to support forced changes + // but got error, so it is legitimate. + return Err(ConsensusErrorKind::ClientImport(e.to_string()).into()) + }, + Ok(false) => { + // API version isn't high enough to support forced changes + }, + }, + Ok(None) => {}, + Ok(Some((median_last_finalized, change))) => return Ok(Some(PendingChange { + next_authorities: change.next_authorities, + delay: change.delay, + canon_height: *header.number(), + canon_hash: hash, + delay_kind: DelayKind::Best { median_last_finalized }, + })), + } + } + + // check normal scheduled change. + { + let maybe_change = api.grandpa_pending_change( + &at, + digest, + ); + + match maybe_change { + Err(e) => Err(ConsensusErrorKind::ClientImport(e.to_string()).into()), + Ok(Some(change)) => Ok(Some(PendingChange { + next_authorities: change.next_authorities, + delay: change.delay, + canon_height: *header.number(), + canon_hash: hash, + delay_kind: DelayKind::Finalized, + })), + Ok(None) => Ok(None), + } + } + } + + fn make_authorities_changes<'a>(&'a self, block: &mut ImportBlock, hash: Block::Hash) + -> Result, ConsensusError> + { + // when we update the authorities, we need to hold the lock + // until the block is written to prevent a race if we need to restore + // the old authority set on error or panic. + struct InnerGuard<'a, T: 'a> { + old: Option, + guard: Option>, + } + + impl<'a, T: 'a> InnerGuard<'a, T> { + fn as_mut(&mut self) -> &mut T { + &mut **self.guard.as_mut().expect("only taken on deconstruction; qed") + } + + fn set_old(&mut self, old: T) { + if self.old.is_none() { + // ignore "newer" old changes. + self.old = Some(old); + } + } + + fn consume(mut self) -> Option<(T, RwLockWriteGuard<'a, T>)> { + if let Some(old) = self.old.take() { + Some((old, self.guard.take().expect("only taken on deconstruction; qed"))) + } else { + None + } + } + } + + impl<'a, T: 'a> Drop for InnerGuard<'a, T> { + fn drop(&mut self) { + if let (Some(mut guard), Some(old)) = (self.guard.take(), self.old.take()) { + *guard = old; + } + } + } + + let number = block.header.number().clone(); + let maybe_change = self.check_new_change( + &block.header, + hash, + )?; + + // returns a function for checking whether a block is a descendent of another + // consistent with querying client directly after importing the block. + let parent_hash = *block.header.parent_hash(); + let is_descendent_of = is_descendent_of(&self.inner, Some((&hash, &parent_hash))); + + let mut guard = InnerGuard { + guard: Some(self.authority_set.inner().write()), + old: None, + }; + + // whether to pause the old authority set -- happens after import + // of a forced change block. + let mut do_pause = false; + + // add any pending changes. + if let Some(change) = maybe_change { + let old = guard.as_mut().clone(); + guard.set_old(old); + + if let DelayKind::Best { .. } = change.delay_kind { + do_pause = true; + } + + guard.as_mut().add_pending_change( + change, + &is_descendent_of, + ).map_err(|e| ConsensusError::from(ConsensusErrorKind::ClientImport(e.to_string())))?; + } + + let applied_changes = { + let forced_change_set = guard.as_mut().apply_forced_changes(hash, number, &is_descendent_of) + .map_err(|e| ConsensusErrorKind::ClientImport(e.to_string())) + .map_err(ConsensusError::from)?; + + if let Some((median_last_finalized_number, new_set)) = forced_change_set { + let new_authorities = { + let (set_id, new_authorities) = new_set.current(); + + // we will use the median last finalized number as a hint + // for the canon block the new authority set should start + // with. we use the minimum between the median and the local + // best finalized block. + let best_finalized_number = self.inner.backend().blockchain().info() + .map_err(|e| ConsensusErrorKind::ClientImport(e.to_string()))? + .finalized_number; + + let canon_number = best_finalized_number.min(median_last_finalized_number); + + let canon_hash = + self.inner.backend().blockchain().header(BlockId::Number(canon_number)) + .map_err(|e| ConsensusErrorKind::ClientImport(e.to_string()))? + .expect("the given block number is less or equal than the current best finalized number; \ + current best finalized number must exist in chain; qed.") + .hash(); + + NewAuthoritySet { + canon_number, + canon_hash, + set_id, + authorities: new_authorities.to_vec(), + } + }; + let old = ::std::mem::replace(guard.as_mut(), new_set); + guard.set_old(old); + + AppliedChanges::Forced(new_authorities) + } else { + let did_standard = guard.as_mut().enacts_standard_change(hash, number, &is_descendent_of) + .map_err(|e| ConsensusErrorKind::ClientImport(e.to_string())) + .map_err(ConsensusError::from)?; + + if let Some(root) = did_standard { + AppliedChanges::Standard(root) + } else { + AppliedChanges::None + } + } + }; + + // consume the guard safely and write necessary changes. + let just_in_case = guard.consume(); + if let Some((_, ref authorities)) = just_in_case { + let authorities_change = match applied_changes { + AppliedChanges::Forced(ref new) => Some(new), + AppliedChanges::Standard(_) => None, // the change isn't actually applied yet. + AppliedChanges::None => None, + }; + + crate::aux_schema::update_authority_set( + authorities, + authorities_change, + |insert| block.auxiliary.extend( + insert.iter().map(|(k, v)| (k.to_vec(), Some(v.to_vec()))) + ) + ); + } + + Ok(PendingSetChanges { just_in_case, applied_changes, do_pause }) + } +} + impl, RA, PRA> BlockImport for GrandpaBlockImport where NumberFor: grandpa::BlockNumberOps, B: Backend + 'static, E: CallExecutor + 'static + Clone + Send + Sync, DigestFor: Encode, - DigestItemFor: DigestItem, + DigestItemFor: DigestItem, RA: Send + Sync, PRA: ProvideRuntimeApi, PRA::Api: GrandpaApi, { type Error = ConsensusError; - fn import_block(&self, mut block: ImportBlock, new_authorities: Option>) + fn import_block(&self, mut block: ImportBlock, new_authorities: Option>) -> Result { - use crate::authorities::PendingChange; - use client::blockchain::HeaderBackend; - let hash = block.post_header().hash(); - let parent_hash = *block.header.parent_hash(); - let number = *block.header.number(); + let number = block.header.number().clone(); // early exit if block already in chain, otherwise the check for // authority changes will error when trying to re-import a change block @@ -140,82 +402,84 @@ impl, RA, PRA> BlockImport Err(e) => return Err(ConsensusErrorKind::ClientImport(e.to_string()).into()), } - let maybe_change = self.api.runtime_api().grandpa_pending_change( - &BlockId::hash(parent_hash), - &block.header.digest().clone(), - ); - - let maybe_change = match maybe_change { - Err(e) => return Err(ConsensusErrorKind::ClientImport(e.to_string()).into()), - Ok(maybe) => maybe, - }; - - // when we update the authorities, we need to hold the lock - // until the block is written to prevent a race if we need to restore - // the old authority set on error. - let is_descendent_of = is_descendent_of(&self.inner, Some((&hash, &parent_hash))); - let just_in_case = if let Some(change) = maybe_change { - let mut authorities = self.authority_set.inner().write(); - let old_set = authorities.clone(); - - authorities.add_pending_change( - PendingChange { - next_authorities: change.next_authorities, - finalization_depth: change.delay, - canon_height: number, - canon_hash: hash, - }, - &is_descendent_of, - ).map_err(|e| ConsensusError::from(ConsensusErrorKind::ClientImport(e.to_string())))?; - - block.auxiliary.push((AUTHORITY_SET_KEY.to_vec(), Some(authorities.encode()))); - Some((old_set, authorities)) - } else { - None - }; + let pending_changes = self.make_authorities_changes(&mut block, hash)?; // we don't want to finalize on `inner.import_block` - let justification = block.justification.take(); + let mut justification = block.justification.take(); let enacts_consensus_change = new_authorities.is_some(); let import_result = self.inner.import_block(block, new_authorities); - let import_result = { - // we scope this so that `just_in_case` is dropped eagerly and releases the authorities lock - let revert_authorities = || if let Some((old_set, mut authorities)) = just_in_case { - *authorities = old_set; - }; - + let mut imported_aux = { match import_result { - Ok(ImportResult::Queued) => ImportResult::Queued, + Ok(ImportResult::Imported(aux)) => aux, Ok(r) => { debug!(target: "afg", "Restoring old authority set after block import result: {:?}", r); - revert_authorities(); + pending_changes.revert(); return Ok(r); }, Err(e) => { debug!(target: "afg", "Restoring old authority set after block import error: {:?}", e); - revert_authorities(); + pending_changes.revert(); return Err(ConsensusErrorKind::ClientImport(e.to_string()).into()); }, } }; - let enacts_change = self.authority_set.inner().read().enacts_change( - hash, - number, - &is_descendent_of, - ).map_err(|e| ConsensusError::from(ConsensusErrorKind::ClientImport(e.to_string())))?; + let (applied_changes, do_pause) = pending_changes.defuse(); - if !enacts_change && !enacts_consensus_change { - return Ok(import_result); + // Send the pause signal after import but BEFORE sending a `ChangeAuthorities` message. + if do_pause { + let _ = self.send_voter_commands.unbounded_send( + VoterCommand::Pause(format!("Forced change scheduled after inactivity")) + ); + } + + let needs_justification = applied_changes.needs_justification(); + + match applied_changes { + AppliedChanges::Forced(new) => { + // NOTE: when we do a force change we are "discrediting" the old set so we + // ignore any justifications from them. this block may contain a justification + // which should be checked and imported below against the new authority + // triggered by this forced change. the new grandpa voter will start at the + // last median finalized block (which is before the block that enacts the + // change), full nodes syncing the chain will not be able to successfully + // import justifications for those blocks since their local authority set view + // is still of the set before the forced change was enacted, still after #1867 + // they should import the block and discard the justification, and they will + // then request a justification from sync if it's necessary (which they should + // then be able to successfully validate). + let _ = self.send_voter_commands.unbounded_send(VoterCommand::ChangeAuthorities(new)); + + // we must clear all pending justifications requests, presumably they won't be + // finalized hence why this forced changes was triggered + imported_aux.clear_justification_requests = true; + }, + AppliedChanges::Standard(false) => { + // we can't apply this change yet since there are other dependent changes that we + // need to apply first, drop any justification that might have been provided with + // the block to make sure we request them from `sync` which will ensure they'll be + // applied in-order. + justification.take(); + }, + _ => {}, + } + + if !needs_justification && !enacts_consensus_change { + return Ok(ImportResult::Imported(imported_aux)); } match justification { Some(justification) => { - self.import_justification(hash, number, justification, enacts_change)?; + self.import_justification(hash, number, justification, needs_justification).unwrap_or_else(|err| { + debug!(target: "finality", "Imported block #{} that enacts authority set change with \ + invalid justification: {:?}, requesting justification from peers.", number, err); + imported_aux.bad_justification = true; + imported_aux.needs_justification = true; + }); }, None => { - if enacts_change { + if needs_justification { trace!( target: "finality", "Imported unjustified block #{} that enacts authority set change, waiting for finality for enactment.", @@ -229,11 +493,11 @@ impl, RA, PRA> BlockImport self.consensus_changes.lock().note_change((number, hash)); } - return Ok(ImportResult::NeedsJustification); + imported_aux.needs_justification = true; } } - Ok(import_result) + Ok(ImportResult::Imported(imported_aux)) } fn check_block( @@ -249,22 +513,22 @@ impl, RA, PRA> GrandpaBlockImport>, authority_set: SharedAuthoritySet>, - authority_set_change: mpsc::UnboundedSender>>, + send_voter_commands: mpsc::UnboundedSender>>, consensus_changes: SharedConsensusChanges>, api: Arc, ) -> GrandpaBlockImport { GrandpaBlockImport { inner, authority_set, - authority_set_change, + send_voter_commands, consensus_changes, api, } } } -impl, RA, PRA> - GrandpaBlockImport where +impl, RA, PRA> GrandpaBlockImport + where NumberFor: grandpa::BlockNumberOps, B: Backend + 'static, E: CallExecutor + 'static + Clone + Send + Sync, @@ -304,13 +568,15 @@ impl, RA, PRA> ); match result { - Err(ExitOrError::AuthoritiesChanged(new)) => { - info!(target: "finality", "Imported justification for block #{} that enacts authority set change, signalling voter.", number); - if let Err(e) = self.authority_set_change.unbounded_send(new) { + Err(CommandOrError::VoterCommand(command)) => { + info!(target: "finality", "Imported justification for block #{} that triggers \ + command {}, signalling voter.", number, command); + + if let Err(e) = self.send_voter_commands.unbounded_send(command) { return Err(ConsensusErrorKind::ClientImport(e.to_string()).into()); } }, - Err(ExitOrError::Error(e)) => { + Err(CommandOrError::Error(e)) => { return Err(match e { Error::Grandpa(error) => ConsensusErrorKind::ClientImport(error.to_string()), Error::Network(error) => ConsensusErrorKind::ClientImport(error), diff --git a/core/finality-grandpa/src/justification.rs b/core/finality-grandpa/src/justification.rs index 563840bc17ba9d57816f5f0b043d7d9ccaa1f68d..d837e6a30862ea36a7fef9a91a986ed3c0a5c98d 100644 --- a/core/finality-grandpa/src/justification.rs +++ b/core/finality-grandpa/src/justification.rs @@ -20,17 +20,18 @@ use client::{CallExecutor, Client}; use client::backend::Backend; use client::blockchain::HeaderBackend; use client::error::{Error as ClientError, ErrorKind as ClientErrorKind}; -use parity_codec::Decode; -use parity_codec_derive::{Encode, Decode}; +use parity_codec::{Encode, Decode}; use grandpa::VoterSet; use grandpa::{Error as GrandpaError}; use runtime_primitives::generic::BlockId; use runtime_primitives::traits::{NumberFor, Block as BlockT, Header as HeaderT}; -use substrate_primitives::{H256, Ed25519AuthorityId, Blake2Hasher}; +use substrate_primitives::{H256, ed25519, Blake2Hasher}; use crate::{Commit, Error}; use crate::communication; +use ed25519::Public as AuthorityId; + /// A GRANDPA justification for block finality, it includes a commit message and /// an ancestry proof including all headers routing all precommit target blocks /// to the commit target block. Due to the current voting strategy the precommit @@ -96,7 +97,7 @@ impl> GrandpaJustification { pub(crate) fn decode_and_verify( encoded: Vec, set_id: u64, - voters: &VoterSet, + voters: &VoterSet, ) -> Result, ClientError> where NumberFor: grandpa::BlockNumberOps, { @@ -107,7 +108,7 @@ impl> GrandpaJustification { } /// Validate the commit and the votes' ancestry proofs. - pub(crate) fn verify(&self, set_id: u64, voters: &VoterSet) -> Result<(), ClientError> + pub(crate) fn verify(&self, set_id: u64, voters: &VoterSet) -> Result<(), ClientError> where NumberFor: grandpa::BlockNumberOps, { diff --git a/core/finality-grandpa/src/lib.rs b/core/finality-grandpa/src/lib.rs index ad00980d3c4e413d64048e225a26b9b1f3d561a0..d6eda5a0916b8783e7933d1daf27e3fb244ea1fe 100644 --- a/core/finality-grandpa/src/lib.rs +++ b/core/finality-grandpa/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -61,26 +61,32 @@ use client::{ }; use client::blockchain::HeaderBackend; use parity_codec::{Encode, Decode}; -use parity_codec_derive::{Encode, Decode}; use runtime_primitives::traits::{ NumberFor, Block as BlockT, Header as HeaderT, DigestFor, ProvideRuntimeApi, Hash as HashT, DigestItemFor, DigestItem, }; use fg_primitives::GrandpaApi; +use inherents::InherentDataProviders; use runtime_primitives::generic::BlockId; -use substrate_primitives::{ed25519, H256, Ed25519AuthorityId, Blake2Hasher}; +use substrate_primitives::{ed25519, H256, Blake2Hasher, Pair}; +use substrate_telemetry::{telemetry, CONSENSUS_TRACE, CONSENSUS_DEBUG, CONSENSUS_WARN, CONSENSUS_INFO}; + +use srml_finality_tracker; use grandpa::Error as GrandpaError; use grandpa::{voter, round::State as RoundState, BlockNumberOps, VoterSet}; use network::Service as NetworkService; use network::consensus_gossip as network_gossip; + +use std::fmt; use std::sync::Arc; use std::time::Duration; pub use fg_primitives::ScheduledChange; mod authorities; +mod aux_schema; mod communication; mod consensus_changes; mod environment; @@ -94,35 +100,28 @@ mod service_integration; #[cfg(feature="service-integration")] pub use service_integration::{LinkHalfForService, BlockImportForService}; -use authorities::SharedAuthoritySet; -use consensus_changes::{ConsensusChanges, SharedConsensusChanges}; -use environment::{Environment, ExitOrError, NewAuthoritySet}; +use aux_schema::{PersistentData, VoterSetState}; +use environment::Environment; pub use finality_proof::{prove_finality, check_finality_proof}; use import::GrandpaBlockImport; use until_imported::UntilCommitBlocksImported; +use ed25519::{Public as AuthorityId, Signature as AuthoritySignature}; + #[cfg(test)] mod tests; -const LAST_COMPLETED_KEY: &[u8] = b"grandpa_completed_round"; -const AUTHORITY_SET_KEY: &[u8] = b"grandpa_voters"; -const CONSENSUS_CHANGES_KEY: &[u8] = b"grandpa_consensus_changes"; - const GRANDPA_ENGINE_ID: network::ConsensusEngineId = [b'a', b'f', b'g', b'1']; - const MESSAGE_ROUND_TOLERANCE: u64 = 2; -/// round-number, round-state -type LastCompleted = (u64, RoundState); - /// A GRANDPA message for a substrate chain. pub type Message = grandpa::Message<::Hash, NumberFor>; /// A signed message. pub type SignedMessage = grandpa::SignedMessage< ::Hash, NumberFor, - ed25519::Signature, - Ed25519AuthorityId, + AuthoritySignature, + AuthorityId, >; /// Grandpa gossip message type. @@ -151,15 +150,15 @@ pub type Precommit = grandpa::Precommit<::Hash, NumberFo pub type Commit = grandpa::Commit< ::Hash, NumberFor, - ed25519::Signature, - Ed25519AuthorityId + AuthoritySignature, + AuthorityId >; /// A compact commit message for this chain's block type. pub type CompactCommit = grandpa::CompactCommit< ::Hash, NumberFor, - ed25519::Signature, - Ed25519AuthorityId + AuthoritySignature, + AuthorityId >; /// Network level commit message with topic information. @@ -252,6 +251,43 @@ struct TopicTracker { set_id: u64, } +impl TopicTracker { + fn is_expired(&self, round: u64, set_id: u64) -> bool { + if set_id < self.set_id { + trace!(target: "afg", "Expired: Message with expired set_id {} (ours {})", set_id, self.set_id); + telemetry!(CONSENSUS_TRACE; "afg.expired_set_id"; + "set_id" => ?set_id, "ours" => ?self.set_id + ); + return true; + } else if set_id == self.set_id + 1 { + // allow a few first rounds of future set. + if round > MESSAGE_ROUND_TOLERANCE { + trace!(target: "afg", "Expired: Message too far in the future set, round {} (ours set_id {})", round, self.set_id); + telemetry!(CONSENSUS_TRACE; "afg.expired_msg_too_far_in_future_set"; + "round" => ?round, "ours" => ?self.set_id + ); + return true; + } + } else if set_id == self.set_id { + if round < self.min_live_round.saturating_sub(MESSAGE_ROUND_TOLERANCE) { + trace!(target: "afg", "Expired: Message round is out of bounds {} (ours {}-{})", round, self.min_live_round, self.max_round); + telemetry!(CONSENSUS_TRACE; "afg.msg_round_oob"; + "round" => ?round, "our_min_live_round" => ?self.min_live_round, "our_max_round" => ?self.max_round + ); + return true; + } + } else { + trace!(target: "afg", "Expired: Message in invalid future set {} (ours {})", set_id, self.set_id); + telemetry!(CONSENSUS_TRACE; "afg.expired_msg_in_invalid_future_set"; + "set_id" => ?set_id, "ours" => ?self.set_id + ); + return true; + } + + false + } +} + struct GossipValidator { rounds: parking_lot::RwLock, _marker: ::std::marker::PhantomData, @@ -293,26 +329,7 @@ impl GossipValidator { } fn is_expired(&self, round: u64, set_id: u64) -> bool { - let rounds = self.rounds.read(); - if set_id < rounds.set_id { - trace!(target: "afg", "Expired: Message with expired set_id {} (ours {})", set_id, rounds.set_id); - return true; - } else if set_id == rounds.set_id + 1 { - // allow a few first rounds of future set. - if round > MESSAGE_ROUND_TOLERANCE { - trace!(target: "afg", "Expired: Message too far in the future set, round {} (ours set_id {})", round, rounds.set_id); - return true; - } - } else if set_id == rounds.set_id { - if round < rounds.min_live_round.saturating_sub(MESSAGE_ROUND_TOLERANCE) { - trace!(target: "afg", "Expired: Message round is out of bounds {} (ours {}-{})", round, rounds.min_live_round, rounds.max_round); - return true; - } - } else { - trace!(target: "afg", "Expired: Message in invalid future set {} (ours {})", set_id, rounds.set_id); - return true; - } - false + self.rounds.read().is_expired(round, set_id) } fn validate_round_message(&self, full: VoteOrPrecommitMessage) @@ -330,6 +347,7 @@ impl GossipValidator { full.set_id ) { debug!(target: "afg", "Bad message signature {}", full.message.id); + telemetry!(CONSENSUS_DEBUG; "afg.bad_msg_signature"; "signature" => ?full.message.id); return network_gossip::ValidationResult::Invalid; } @@ -341,12 +359,18 @@ impl GossipValidator { -> network_gossip::ValidationResult { use grandpa::Message as GrandpaMessage; + if self.is_expired(full.round, full.set_id) { return network_gossip::ValidationResult::Expired; } if full.message.precommits.len() != full.message.auth_data.len() || full.message.precommits.is_empty() { debug!(target: "afg", "Malformed compact commit"); + telemetry!(CONSENSUS_DEBUG; "afg.malformed_compact_commit"; + "precommits_len" => ?full.message.precommits.len(), + "auth_data_len" => ?full.message.auth_data.len(), + "precommits_is_empty" => ?full.message.precommits.is_empty(), + ); return network_gossip::ValidationResult::Invalid; } @@ -360,11 +384,24 @@ impl GossipValidator { full.set_id, ) { debug!(target: "afg", "Bad commit message signature {}", id); + telemetry!(CONSENSUS_DEBUG; "afg.bad_commit_msg_signature"; "id" => ?id); return network_gossip::ValidationResult::Invalid; } } let topic = commit_topic::(full.set_id); + + let precommits_signed_by: Vec = full.message.auth_data.iter().map(move |(_, a)| { + format!("{}", a) + }).collect(); + + telemetry!(CONSENSUS_INFO; "afg.received_commit_msg"; + "contains_precommits_signed_by" => ?precommits_signed_by, + "round" => ?full.round, + "set_id" => ?full.set_id, + "topic" => ?topic, + "block_hash" => ?full.message, + ); network_gossip::ValidationResult::Valid(topic) } } @@ -376,10 +413,23 @@ impl network_gossip::Validator for GossipValidator self.validate_commit_message(message), None => { debug!(target: "afg", "Error decoding message"); + telemetry!(CONSENSUS_DEBUG; "afg.err_decoding_msg"; "" => ""); network_gossip::ValidationResult::Invalid } } } + + fn message_expired<'a>(&'a self) -> Box bool + 'a> { + let rounds = self.rounds.read(); + Box::new(move |_topic, mut data| { + match GossipMessage::::decode(&mut data) { + None => true, + Some(GossipMessage::Commit(full)) => rounds.is_expired(full.round, full.set_id), + Some(GossipMessage::VoteOrPrecommit(full)) => + rounds.is_expired(full.round, full.set_id), + } + }) + } } /// A handle to the network. This is generally implemented by providing some @@ -395,7 +445,7 @@ pub trait Network: Clone { fn messages_for(&self, round: u64, set_id: u64) -> Self::In; /// Send a message at a specific round out. - fn send_message(&self, round: u64, set_id: u64, message: Vec); + fn send_message(&self, round: u64, set_id: u64, message: Vec, force: bool); /// Clean up messages for a round. fn drop_round_messages(&self, round: u64, set_id: u64); @@ -408,7 +458,7 @@ pub trait Network: Clone { fn commit_messages(&self, set_id: u64) -> Self::In; /// Send message over the commit channel. - fn send_commit(&self, round: u64, set_id: u64, message: Vec); + fn send_commit(&self, round: u64, set_id: u64, message: Vec, force: bool); /// Inform peers that a block with given hash should be downloaded. fn announce(&self, round: u64, set_id: u64, block: Block::Hash); @@ -455,15 +505,15 @@ impl,> Network(round, set_id)); + let inner_rx = gossip.messages_for(GRANDPA_ENGINE_ID, message_topic::(round, set_id)); let _ = tx.send(inner_rx); }); NetworkStream { outer: rx, inner: None } } - fn send_message(&self, round: u64, set_id: u64, message: Vec) { + fn send_message(&self, round: u64, set_id: u64, message: Vec, force: bool) { let topic = message_topic::(round, set_id); - self.service.gossip_consensus_message(topic, GRANDPA_ENGINE_ID, message); + self.service.gossip_consensus_message(topic, GRANDPA_ENGINE_ID, message, force); } fn drop_round_messages(&self, round: u64, set_id: u64) { @@ -480,19 +530,22 @@ impl,> Network(set_id)); + let inner_rx = gossip.messages_for(GRANDPA_ENGINE_ID, commit_topic::(set_id)); let _ = tx.send(inner_rx); }); NetworkStream { outer: rx, inner: None } } - fn send_commit(&self, _round: u64, set_id: u64, message: Vec) { + fn send_commit(&self, _round: u64, set_id: u64, message: Vec, force: bool) { let topic = commit_topic::(set_id); - self.service.gossip_consensus_message(topic, GRANDPA_ENGINE_ID, message); + self.service.gossip_consensus_message(topic, GRANDPA_ENGINE_ID, message, force); } fn announce(&self, round: u64, _set_id: u64, block: B::Hash) { debug!(target: "afg", "Announcing block {} to peers which we voted on in round {}", block, round); + telemetry!(CONSENSUS_DEBUG; "afg.announcing_blocks_to_voted_peers"; + "block" => ?block, "round" => ?round + ); self.service.announce_block(block) } } @@ -517,13 +570,81 @@ impl, RA> BlockStatus for Arc { + pub(crate) canon_number: N, + pub(crate) canon_hash: H, + pub(crate) set_id: u64, + pub(crate) authorities: Vec<(AuthorityId, u64)>, +} + +/// Commands issued to the voter. +#[derive(Debug)] +pub(crate) enum VoterCommand { + /// Pause the voter for given reason. + Pause(String), + /// New authorities. + ChangeAuthorities(NewAuthoritySet) +} + +impl fmt::Display for VoterCommand { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + VoterCommand::Pause(ref reason) => write!(f, "Pausing voter: {}", reason), + VoterCommand::ChangeAuthorities(_) => write!(f, "Changing authorities"), + } + } +} + +/// Signals either an early exit of a voter or an error. +#[derive(Debug)] +pub(crate) enum CommandOrError { + /// An error occurred. + Error(Error), + /// A command to the voter. + VoterCommand(VoterCommand), +} + +impl From for CommandOrError { + fn from(e: Error) -> Self { + CommandOrError::Error(e) + } +} + +impl From for CommandOrError { + fn from(e: ClientError) -> Self { + CommandOrError::Error(Error::Client(e)) + } +} + +impl From for CommandOrError { + fn from(e: grandpa::Error) -> Self { + CommandOrError::Error(Error::from(e)) + } +} + +impl From> for CommandOrError { + fn from(e: VoterCommand) -> Self { + CommandOrError::VoterCommand(e) + } +} + +impl ::std::error::Error for CommandOrError { } + +impl fmt::Display for CommandOrError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + CommandOrError::Error(ref e) => write!(f, "{:?}", e), + CommandOrError::VoterCommand(ref cmd) => write!(f, "{}", cmd), + } + } +} + pub struct LinkHalf, RA> { client: Arc>, - authority_set: SharedAuthoritySet>, - authority_set_change: mpsc::UnboundedReceiver>>, - consensus_changes: SharedConsensusChanges>, + persistent_data: PersistentData>, + voter_commands_rx: mpsc::UnboundedReceiver>>, } /// Make block importer and link half necessary to tie the background voter @@ -537,57 +658,41 @@ pub fn block_import, RA, PRA>( E: CallExecutor + 'static + Clone + Send + Sync, RA: Send + Sync, PRA: ProvideRuntimeApi, - PRA::Api: GrandpaApi + PRA::Api: GrandpaApi, { use runtime_primitives::traits::Zero; - let authority_set = match Backend::get_aux(&**client.backend(), AUTHORITY_SET_KEY)? { - None => { - info!(target: "afg", "Loading GRANDPA authorities \ - from genesis on what appears to be first startup."); - - // no authority set on disk: fetch authorities from genesis state. - // if genesis state is not available, we may be a light client, but these - // are unsupported for following GRANDPA directly. - let genesis_authorities = api.runtime_api() - .grandpa_authorities(&BlockId::number(Zero::zero()))?; - let authority_set = SharedAuthoritySet::genesis(genesis_authorities); - let encoded = authority_set.inner().read().encode(); - Backend::insert_aux(&**client.backend(), &[(AUTHORITY_SET_KEY, &encoded[..])], &[])?; + let chain_info = client.info()?; + let genesis_hash = chain_info.chain.genesis_hash; - authority_set + let persistent_data = aux_schema::load_persistent( + &**client.backend(), + genesis_hash, + >::zero(), + || { + let genesis_authorities = api.runtime_api() + .grandpa_authorities(&BlockId::number(Zero::zero()))?; + telemetry!(CONSENSUS_DEBUG; "afg.loading_authorities"; + "authorities_len" => ?genesis_authorities.len() + ); + Ok(genesis_authorities) } - Some(raw) => crate::authorities::AuthoritySet::decode(&mut &raw[..]) - .ok_or_else(|| ::client::error::ErrorKind::Backend( - format!("GRANDPA authority set kept in invalid format") - ))? - .into(), - }; - - let consensus_changes = Backend::get_aux(&**client.backend(), CONSENSUS_CHANGES_KEY)?; - let consensus_changes = Arc::new(parking_lot::Mutex::new(match consensus_changes { - Some(raw) => ConsensusChanges::decode(&mut &raw[..]) - .ok_or_else(|| ::client::error::ErrorKind::Backend( - format!("GRANDPA consensus changes kept in invalid format") - ))?, - None => ConsensusChanges::empty(), - })); - - let (authority_set_change_tx, authority_set_change_rx) = mpsc::unbounded(); + )?; + + let (voter_commands_tx, voter_commands_rx) = mpsc::unbounded(); Ok(( GrandpaBlockImport::new( client.clone(), - authority_set.clone(), - authority_set_change_tx, - consensus_changes.clone(), + persistent_data.authority_set.clone(), + voter_commands_tx, + persistent_data.consensus_changes.clone(), api, ), LinkHalf { client, - authority_set, - authority_set_change: authority_set_change_rx, - consensus_changes, + persistent_data, + voter_commands_rx, }, )) } @@ -595,17 +700,17 @@ pub fn block_import, RA, PRA>( fn committer_communication, B, E, N, RA>( local_key: Option>, set_id: u64, - voters: &Arc>, + voters: &Arc>, client: &Arc>, network: &N, ) -> ( impl Stream< - Item = (u64, ::grandpa::CompactCommit, ed25519::Signature, Ed25519AuthorityId>), - Error = ExitOrError>, + Item = (u64, ::grandpa::CompactCommit, AuthoritySignature, AuthorityId>), + Error = CommandOrError>, >, impl Sink< - SinkItem = (u64, ::grandpa::Commit, ed25519::Signature, Ed25519AuthorityId>), - SinkError = ExitOrError>, + SinkItem = (u64, ::grandpa::Commit, AuthoritySignature, AuthorityId>), + SinkError = CommandOrError>, >, ) where B: Backend, @@ -613,7 +718,7 @@ fn committer_communication, B, E, N, RA>( N: Network, RA: Send + Sync, NumberFor: BlockNumberOps, - DigestItemFor: DigestItem, + DigestItemFor: DigestItem, { // verification stream let commit_in = crate::communication::checked_commit_stream::( @@ -644,12 +749,43 @@ fn committer_communication, B, E, N, RA>( (commit_in, commit_out) } +/// Register the finality tracker inherent data provider (which is used by +/// GRANDPA), if not registered already. +fn register_finality_tracker_inherent_data_provider, RA>( + client: Arc>, + inherent_data_providers: &InherentDataProviders, +) -> Result<(), consensus_common::Error> where + B: Backend + 'static, + E: CallExecutor + Send + Sync + 'static, + RA: Send + Sync + 'static, +{ + if !inherent_data_providers.has_provider(&srml_finality_tracker::INHERENT_IDENTIFIER) { + inherent_data_providers + .register_provider(srml_finality_tracker::InherentDataProvider::new(move || { + match client.backend().blockchain().info() { + Err(e) => Err(std::borrow::Cow::Owned(e.to_string())), + Ok(info) => { + telemetry!(CONSENSUS_INFO; "afg.finalized"; + "finalized_number" => ?info.finalized_number, + "finalized_hash" => ?info.finalized_hash, + ); + Ok(info.finalized_number) + }, + } + })) + .map_err(|err| consensus_common::ErrorKind::InherentData(err.into()).into()) + } else { + Ok(()) + } +} + /// Run a GRANDPA voter as a task. Provide configuration and a link to a /// block import worker that has already been instantiated with `block_import`. pub fn run_grandpa, N, RA>( config: Config, link: LinkHalf, network: N, + inherent_data_providers: InherentDataProviders, on_exit: impl Future + Send + 'static, ) -> ::client::error::Result + Send + 'static> where Block::Hash: Ord, @@ -659,33 +795,22 @@ pub fn run_grandpa, N, RA>( N::In: Send + 'static, NumberFor: BlockNumberOps, DigestFor: Encode, - DigestItemFor: DigestItem, + DigestItemFor: DigestItem, RA: Send + Sync + 'static, { use futures::future::{self, Loop as FutureLoop}; - use runtime_primitives::traits::Zero; let LinkHalf { client, - authority_set, - authority_set_change, - consensus_changes, + persistent_data, + voter_commands_rx, } = link; - - let chain_info = client.info()?; - let genesis_hash = chain_info.chain.genesis_hash; - // we shadow network with the wrapping/rebroadcasting network to avoid // accidental reuse. let (broadcast_worker, network) = communication::rebroadcasting_network(network); + let PersistentData { authority_set, set_state, consensus_changes } = persistent_data; - let (last_round_number, last_state) = match Backend::get_aux(&**client.backend(), LAST_COMPLETED_KEY)? { - None => (0, RoundState::genesis((genesis_hash, >::zero()))), - Some(raw) => LastCompleted::decode(&mut &raw[..]) - .ok_or_else(|| ::client::error::ErrorKind::Backend( - format!("Last GRANDPA round state kept in invalid format") - ))? - }; + register_finality_tracker_inherent_data_provider(client.clone(), &inherent_data_providers)?; let voters = authority_set.current_authorities(); @@ -697,92 +822,141 @@ pub fn run_grandpa, N, RA>( set_id: authority_set.set_id(), authority_set: authority_set.clone(), consensus_changes: consensus_changes.clone(), + last_completed: environment::LastCompletedRound::new(set_state.round()), }); - let initial_state = (initial_environment, last_round_number, last_state, authority_set_change.into_future()); + let initial_state = (initial_environment, set_state, voter_commands_rx.into_future()); let voter_work = future::loop_fn(initial_state, move |params| { - let (env, last_round_number, last_state, authority_set_change) = params; + let (env, set_state, voter_commands_rx) = params; debug!(target: "afg", "{}: Starting new voter with set ID {}", config.name(), env.set_id); - - let chain_info = match client.info() { - Ok(i) => i, - Err(e) => return future::Either::B(future::err(Error::Client(e))), - }; - - let last_finalized = ( - chain_info.chain.finalized_hash, - chain_info.chain.finalized_number, + telemetry!(CONSENSUS_DEBUG; "afg.starting_new_voter"; + "name" => ?config.name(), "set_id" => ?env.set_id ); - let committer_data = committer_communication( - config.local_key.clone(), - env.set_id, - &env.voters, - &client, - &network, - ); + let mut maybe_voter = match set_state.clone() { + VoterSetState::Live(last_round_number, last_round_state) => { + let chain_info = match client.info() { + Ok(i) => i, + Err(e) => return future::Either::B(future::err(Error::Client(e))), + }; + + let last_finalized = ( + chain_info.chain.finalized_hash, + chain_info.chain.finalized_number, + ); + + let committer_data = committer_communication( + config.local_key.clone(), + env.set_id, + &env.voters, + &client, + &network, + ); + + let voters = (*env.voters).clone(); + + Some(voter::Voter::new( + env.clone(), + voters, + committer_data, + last_round_number, + last_round_state, + last_finalized, + )) + } + VoterSetState::Paused(_, _) => None, + }; - let voters = (*env.voters).clone(); + // needs to be combined with another future otherwise it can deadlock. + let poll_voter = future::poll_fn(move || match maybe_voter { + Some(ref mut voter) => voter.poll(), + None => Ok(Async::NotReady), + }); - let voter = voter::Voter::new( - env, - voters, - committer_data, - last_round_number, - last_state, - last_finalized, - ); let client = client.clone(); let config = config.clone(); let network = network.clone(); let authority_set = authority_set.clone(); let consensus_changes = consensus_changes.clone(); - let trigger_authority_set_change = |new: NewAuthoritySet<_, _>, authority_set_change| { - let env = Arc::new(Environment { - inner: client, - config, - voters: Arc::new(new.authorities.into_iter().collect()), - set_id: new.set_id, - network, - authority_set, - consensus_changes, - }); - - // start the new authority set using the block where the - // set changed (not where the signal happened!) as the base. - Ok(FutureLoop::Continue(( - env, - 0, // always start at round 0 when changing sets. - RoundState::genesis((new.canon_hash, new.canon_number)), - authority_set_change, - ))) + let handle_voter_command = move |command: VoterCommand<_, _>, voter_commands_rx| { + match command { + VoterCommand::ChangeAuthorities(new) => { + let voters: Vec = new.authorities.iter().map(move |(a, _)| { + format!("{}", a) + }).collect(); + telemetry!(CONSENSUS_INFO; "afg.voter_command_change_authorities"; + "number" => ?new.canon_number, + "hash" => ?new.canon_hash, + "voters" => ?voters, + "set_id" => ?new.set_id, + ); + + // start the new authority set using the block where the + // set changed (not where the signal happened!) as the base. + let genesis_state = RoundState::genesis((new.canon_hash, new.canon_number)); + let env = Arc::new(Environment { + inner: client, + config, + voters: Arc::new(new.authorities.into_iter().collect()), + set_id: new.set_id, + network, + authority_set, + consensus_changes, + last_completed: environment::LastCompletedRound::new( + (0, genesis_state.clone()) + ), + }); + + + let set_state = VoterSetState::Live( + 0, // always start at round 0 when changing sets. + genesis_state, + ); + + Ok(FutureLoop::Continue((env, set_state, voter_commands_rx))) + } + VoterCommand::Pause(reason) => { + info!(target: "afg", "Pausing old validator set: {}", reason); + + // not racing because old voter is shut down. + let (last_round_number, last_round_state) = env.last_completed.read(); + let set_state = VoterSetState::Paused( + last_round_number, + last_round_state, + ); + + aux_schema::write_voter_set_state(&**client.backend(), &set_state)?; + + Ok(FutureLoop::Continue((env, set_state, voter_commands_rx))) + }, + } }; - future::Either::A(voter.select2(authority_set_change).then(move |res| match res { + future::Either::A(poll_voter.select2(voter_commands_rx).then(move |res| match res { Ok(future::Either::A(((), _))) => { // voters don't conclude naturally; this could reasonably be an error. Ok(FutureLoop::Break(())) }, Err(future::Either::B(_)) => { - // the `authority_set_change` stream should not fail. + // the `voter_commands_rx` stream should not fail. Ok(FutureLoop::Break(())) }, Ok(future::Either::B(((None, _), _))) => { - // the `authority_set_change` stream should never conclude since it's never closed. + // the `voter_commands_rx` stream should never conclude since it's never closed. Ok(FutureLoop::Break(())) }, - Err(future::Either::A((ExitOrError::Error(e), _))) => { + Err(future::Either::A((CommandOrError::Error(e), _))) => { // return inner voter error Err(e) } - Ok(future::Either::B(((Some(new), authority_set_change), _))) => { - // authority set change triggered externally through the channel - trigger_authority_set_change(new, authority_set_change.into_future()) + Ok(future::Either::B(((Some(command), voter_commands_rx), _))) => { + // some command issued externally. + handle_voter_command(command, voter_commands_rx.into_future()) } - Err(future::Either::A((ExitOrError::AuthoritiesChanged(new), authority_set_change))) => { - // authority set change triggered internally by finalizing a change block - trigger_authority_set_change(new, authority_set_change) + Err(future::Either::A((CommandOrError::VoterCommand(command), voter_commands_rx))) => { + // some command issued internally. + handle_voter_command(command, voter_commands_rx) }, })) }); @@ -790,7 +964,10 @@ pub fn run_grandpa, N, RA>( let voter_work = voter_work .join(broadcast_worker) .map(|((), ())| ()) - .map_err(|e| warn!("GRANDPA Voter failed: {:?}", e)); + .map_err(|e| { + warn!("GRANDPA Voter failed: {:?}", e); + telemetry!(CONSENSUS_WARN; "afg.voter_failed"; "e" => ?e); + }); Ok(voter_work.select(on_exit).then(|_| Ok(()))) } diff --git a/core/finality-grandpa/src/service_integration.rs b/core/finality-grandpa/src/service_integration.rs index 1986c5c0a491d4e2818e72bfc3ee84a9cd7a9fa3..3eee1dd9408d490f7275532fff3a8ea27ac7b73d 100644 --- a/core/finality-grandpa/src/service_integration.rs +++ b/core/finality-grandpa/src/service_integration.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/finality-grandpa/src/tests.rs b/core/finality-grandpa/src/tests.rs index 029e517943ad5dcb7ef452d7d1892886dfd354c0..7e0537ed7b09a1c534d356f6ec2459550ad2ee9a 100644 --- a/core/finality-grandpa/src/tests.rs +++ b/core/finality-grandpa/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -17,29 +17,28 @@ //! Tests and test helpers for GRANDPA. use super::*; -use network::test::{Block, Hash, TestNetFactory, Peer, PeersClient}; +use network::test::{Block, DummySpecialization, Hash, TestNetFactory, Peer, PeersClient}; use network::test::{PassThroughVerifier}; use network::config::{ProtocolConfig, Roles}; use parking_lot::Mutex; use tokio::runtime::current_thread; -use keyring::Keyring; +use keyring::AuthorityKeyring; use client::{ BlockchainEvents, error::Result, blockchain::Backend as BlockchainBackend, runtime_api::{Core, RuntimeVersion, ApiExt}, }; use test_client::{self, runtime::BlockNumber}; -use parity_codec::Decode; -use consensus_common::{BlockOrigin, ForkChoiceStrategy, ImportBlock, ImportResult}; +use consensus_common::{BlockOrigin, ForkChoiceStrategy, ImportedAux, ImportBlock, ImportResult}; use consensus_common::import_queue::{SharedBlockImport, SharedJustificationImport}; use std::collections::{HashMap, HashSet}; use std::result; use runtime_primitives::traits::{ApiRef, ProvideRuntimeApi}; use runtime_primitives::generic::BlockId; -use runtime_primitives::ExecutionContext; -use substrate_primitives::NativeOrEncoded; +use substrate_primitives::{NativeOrEncoded, ExecutionContext}; use authorities::AuthoritySet; +use consensus_changes::ConsensusChanges; type PeerData = Mutex< @@ -52,12 +51,12 @@ type PeerData = > > >; -type GrandpaPeer = Peer; +type GrandpaPeer = Peer; struct GrandpaTestNet { peers: Vec>, test_config: TestApi, - started: bool + started: bool, } impl GrandpaTestNet { @@ -68,16 +67,15 @@ impl GrandpaTestNet { test_config, }; let config = Self::default_config(); - for _ in 0..n_peers { net.add_peer(&config); } - net } } impl TestNetFactory for GrandpaTestNet { + type Specialization = DummySpecialization; type Verifier = PassThroughVerifier; type PeerData = PeerData; @@ -86,7 +84,7 @@ impl TestNetFactory for GrandpaTestNet { GrandpaTestNet { peers: Vec::new(), test_config: Default::default(), - started: false + started: false, } } @@ -122,7 +120,7 @@ impl TestNetFactory for GrandpaTestNet { &self.peers } - fn mut_peers>)>(&mut self, closure: F) { + fn mut_peers>)>(&mut self, closure: F) { closure(&mut self.peers); } @@ -182,7 +180,10 @@ impl Network for MessageRouting { self.validator.note_round(round, set_id); let inner = self.inner.lock(); let peer = inner.peer(self.peer_id); - let messages = peer.consensus_gossip_messages_for(make_topic(round, set_id)); + let messages = peer.consensus_gossip_messages_for( + GRANDPA_ENGINE_ID, + make_topic(round, set_id), + ); let messages = messages.map_err( move |_| panic!("Messages for round {} dropped too early", round) @@ -191,9 +192,10 @@ impl Network for MessageRouting { Box::new(messages) } - fn send_message(&self, round: u64, set_id: u64, message: Vec) { + fn send_message(&self, round: u64, set_id: u64, message: Vec, force: bool) { let inner = self.inner.lock(); - inner.peer(self.peer_id).gossip_message(make_topic(round, set_id), GRANDPA_ENGINE_ID, message); + inner.peer(self.peer_id) + .gossip_message(make_topic(round, set_id), GRANDPA_ENGINE_ID, message, force); } fn drop_round_messages(&self, round: u64, set_id: u64) { @@ -212,7 +214,10 @@ impl Network for MessageRouting { self.validator.note_set(set_id); let inner = self.inner.lock(); let peer = inner.peer(self.peer_id); - let messages = peer.consensus_gossip_messages_for(make_commit_topic(set_id)); + let messages = peer.consensus_gossip_messages_for( + GRANDPA_ENGINE_ID, + make_commit_topic(set_id), + ); let messages = messages.map_err( move |_| panic!("Commit messages for set {} dropped too early", set_id) @@ -221,9 +226,10 @@ impl Network for MessageRouting { Box::new(messages) } - fn send_commit(&self, _round: u64, set_id: u64, message: Vec) { + fn send_commit(&self, _round: u64, set_id: u64, message: Vec, force: bool) { let inner = self.inner.lock(); - inner.peer(self.peer_id).gossip_message(make_commit_topic(set_id), GRANDPA_ENGINE_ID, message); + inner.peer(self.peer_id) + .gossip_message(make_commit_topic(set_id), GRANDPA_ENGINE_ID, message, force); } fn announce(&self, _round: u64, _set_id: u64, _block: H256) { @@ -233,15 +239,17 @@ impl Network for MessageRouting { #[derive(Default, Clone)] struct TestApi { - genesis_authorities: Vec<(Ed25519AuthorityId, u64)>, + genesis_authorities: Vec<(AuthorityId, u64)>, scheduled_changes: Arc>>>, + forced_changes: Arc)>>>, } impl TestApi { - fn new(genesis_authorities: Vec<(Ed25519AuthorityId, u64)>) -> Self { + fn new(genesis_authorities: Vec<(AuthorityId, u64)>) -> Self { TestApi { genesis_authorities, scheduled_changes: Arc::new(Mutex::new(HashMap::new())), + forced_changes: Arc::new(Mutex::new(HashMap::new())), } } } @@ -275,7 +283,7 @@ impl Core for RuntimeApi { _: ExecutionContext, _: Option<()>, _: Vec, - ) -> Result>> { + ) -> Result>> { unimplemented!("Not required for testing!") } @@ -320,7 +328,7 @@ impl GrandpaApi for RuntimeApi { _: ExecutionContext, _: Option<()>, _: Vec, - ) -> Result>> { + ) -> Result>> { if at == &BlockId::Number(0) { Ok(self.inner.genesis_authorities.clone()).map(NativeOrEncoded::Native) } else { @@ -344,19 +352,44 @@ impl GrandpaApi for RuntimeApi { // extrinsics. Ok(self.inner.scheduled_changes.lock().get(&parent_hash).map(|c| c.clone())).map(NativeOrEncoded::Native) } + + fn grandpa_forced_change_runtime_api_impl( + &self, + at: &BlockId, + _: ExecutionContext, + _: Option<(&DigestFor)>, + _: Vec, + ) + -> Result, ScheduledChange>)>>> { + let parent_hash = match at { + &BlockId::Hash(at) => at, + _ => panic!("not requested by block hash!!"), + }; + + // we take only scheduled changes at given block number where there are no + // extrinsics. + Ok(self.inner.forced_changes.lock().get(&parent_hash).map(|c| c.clone())).map(NativeOrEncoded::Native) + } } const TEST_GOSSIP_DURATION: Duration = Duration::from_millis(500); const TEST_ROUTING_INTERVAL: Duration = Duration::from_millis(50); -fn make_ids(keys: &[Keyring]) -> Vec<(Ed25519AuthorityId, u64)> { +fn make_ids(keys: &[AuthorityKeyring]) -> Vec<(AuthorityId, u64)> { keys.iter() - .map(|key| Ed25519AuthorityId(key.to_raw_public())) + .map(|key| AuthorityId(key.to_raw_public())) .map(|id| (id, 1)) .collect() } -fn run_to_completion(blocks: u64, net: Arc>, peers: &[Keyring]) -> u64 { +// 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( + blocks: u64, + net: Arc>, + peers: &[AuthorityKeyring], + before_waiting: F, +) -> u64 { use parking_lot::RwLock; let mut finality_notifications = Vec::new(); @@ -397,6 +430,7 @@ fn run_to_completion(blocks: u64, net: Arc>, peers: &[Keyr }, link, MessageRouting::new(net.clone(), peer_id), + InherentDataProviders::new(), futures::empty(), ).expect("all in order with client and network"); @@ -420,6 +454,8 @@ fn run_to_completion(blocks: u64, net: Arc>, peers: &[Keyr .map(|_| ()) .map_err(|_| ()); + (before_waiting)(); + runtime.block_on(wait_for.select(drive_to_completion).map_err(|_| ())).unwrap(); let highest_finalized = *highest_finalized.read(); @@ -427,9 +463,14 @@ fn run_to_completion(blocks: u64, net: Arc>, peers: &[Keyr highest_finalized } +fn run_to_completion(blocks: u64, net: Arc>, peers: &[AuthorityKeyring]) -> u64 { + run_to_completion_with(blocks, net, peers, || {}) +} + #[test] fn finalize_3_voters_no_observers() { - let peers = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie]; + let _ = env_logger::try_init(); + let peers = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie]; let voters = make_ids(peers); let mut net = GrandpaTestNet::new(TestApi::new(voters), 3); @@ -451,7 +492,7 @@ fn finalize_3_voters_no_observers() { #[test] fn finalize_3_voters_1_observer() { - let peers = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie]; + let peers = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie]; let voters = make_ids(peers); let mut net = GrandpaTestNet::new(TestApi::new(voters), 4); @@ -490,6 +531,7 @@ fn finalize_3_voters_1_observer() { }, link, MessageRouting::new(net.clone(), peer_id), + InherentDataProviders::new(), futures::empty(), ).expect("all in order with client and network"); @@ -513,24 +555,24 @@ fn finalize_3_voters_1_observer() { fn transition_3_voters_twice_1_observer() { let _ = env_logger::try_init(); let peers_a = &[ - Keyring::Alice, - Keyring::Bob, - Keyring::Charlie, + AuthorityKeyring::Alice, + AuthorityKeyring::Bob, + AuthorityKeyring::Charlie, ]; let peers_b = &[ - Keyring::Dave, - Keyring::Eve, - Keyring::Ferdie, + AuthorityKeyring::Dave, + AuthorityKeyring::Eve, + AuthorityKeyring::Ferdie, ]; let peers_c = &[ - Keyring::Alice, - Keyring::Eve, - Keyring::Two, + AuthorityKeyring::Alice, + AuthorityKeyring::Eve, + AuthorityKeyring::Two, ]; - let observer = &[Keyring::One]; + let observer = &[AuthorityKeyring::One]; let genesis_voters = make_ids(peers_a); @@ -547,8 +589,9 @@ fn transition_3_voters_twice_1_observer() { assert_eq!(peer.client().info().unwrap().chain.best_number, 1, "Peer #{} failed to sync", i); - let set_raw = peer.client().backend().get_aux(crate::AUTHORITY_SET_KEY).unwrap().unwrap(); - let set = AuthoritySet::::decode(&mut &set_raw[..]).unwrap(); + let set: AuthoritySet = crate::aux_schema::load_authorities( + &**peer.client().backend() + ).unwrap(); assert_eq!(set.current(), (0, make_ids(peers_a).as_slice())); assert_eq!(set.pending_changes().count(), 0); @@ -633,8 +676,9 @@ fn transition_3_voters_twice_1_observer() { .take_while(|n| Ok(n.header.number() < &30)) .for_each(move |_| Ok(())) .map(move |()| { - let set_raw = client.backend().get_aux(crate::AUTHORITY_SET_KEY).unwrap().unwrap(); - let set = AuthoritySet::::decode(&mut &set_raw[..]).unwrap(); + let set: AuthoritySet = crate::aux_schema::load_authorities( + &**client.backend() + ).unwrap(); assert_eq!(set.current(), (2, make_ids(peers_c).as_slice())); assert_eq!(set.pending_changes().count(), 0); @@ -649,6 +693,7 @@ fn transition_3_voters_twice_1_observer() { }, link, MessageRouting::new(net.clone(), peer_id), + InherentDataProviders::new(), futures::empty(), ).expect("all in order with client and network"); @@ -675,11 +720,11 @@ fn transition_3_voters_twice_1_observer() { #[test] fn justification_is_emitted_when_consensus_data_changes() { - let peers = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie]; + 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![Ed25519AuthorityId::from([42; 32])]; + let new_authorities = vec![AuthorityId::from_raw([42; 32])]; net.peer(0).push_authorities_change_block(new_authorities); net.sync(); let net = Arc::new(Mutex::new(net)); @@ -692,7 +737,7 @@ fn justification_is_emitted_when_consensus_data_changes() { #[test] fn justification_is_generated_periodically() { - let peers = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie]; + let peers = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie]; let voters = make_ids(peers); let mut net = GrandpaTestNet::new(TestApi::new(voters), 3); @@ -731,8 +776,8 @@ fn consensus_changes_works() { #[test] fn sync_justifications_on_change_blocks() { - let peers_a = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie]; - let peers_b = &[Keyring::Alice, Keyring::Bob]; + let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie]; + let peers_b = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob]; let voters = make_ids(peers_b); // 4 peers, 3 of them are authorities and participate in grandpa @@ -779,15 +824,15 @@ fn sync_justifications_on_change_blocks() { #[test] fn finalizes_multiple_pending_changes_in_order() { - env_logger::init(); + let _ = env_logger::try_init(); - let peers_a = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie]; - let peers_b = &[Keyring::Dave, Keyring::Eve, Keyring::Ferdie]; - let peers_c = &[Keyring::Dave, Keyring::Alice, Keyring::Bob]; + let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie]; + let peers_b = &[AuthorityKeyring::Dave, AuthorityKeyring::Eve, AuthorityKeyring::Ferdie]; + let peers_c = &[AuthorityKeyring::Dave, AuthorityKeyring::Alice, AuthorityKeyring::Bob]; let all_peers = &[ - Keyring::Alice, Keyring::Bob, Keyring::Charlie, - Keyring::Dave, Keyring::Eve, Keyring::Ferdie, + AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie, + AuthorityKeyring::Dave, AuthorityKeyring::Eve, AuthorityKeyring::Ferdie, ]; let genesis_voters = make_ids(peers_a); @@ -839,7 +884,7 @@ fn finalizes_multiple_pending_changes_in_order() { #[test] fn doesnt_vote_on_the_tip_of_the_chain() { - let peers_a = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie]; + let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie]; let voters = make_ids(peers_a); let api = TestApi::new(voters); let mut net = GrandpaTestNet::new(api, 3); @@ -860,10 +905,64 @@ fn doesnt_vote_on_the_tip_of_the_chain() { assert_eq!(highest, 75); } +#[test] +fn force_change_to_new_set() { + // 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]; + let api = TestApi::new(make_ids(genesis_authorities)); + + let voters = make_ids(peers_a); + let normal_transitions = api.scheduled_changes.clone(); + let forced_transitions = api.forced_changes.clone(); + 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().unwrap().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(25, false); + net.lock().sync(); + + for (i, peer) in net.lock().peers().iter().enumerate() { + assert_eq!(peer.client().info().unwrap().chain.best_number, 26, + "Peer #{} failed to sync", i); + + let set: AuthoritySet = crate::aux_schema::load_authorities( + &**peer.client().backend() + ).unwrap(); + + 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); +} + #[test] fn allows_reimporting_change_blocks() { - let peers_a = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie]; - let peers_b = &[Keyring::Alice, Keyring::Bob]; + let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie]; + 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); @@ -894,7 +993,50 @@ fn allows_reimporting_change_blocks() { assert_eq!( block_import.import_block(block(), None).unwrap(), - ImportResult::NeedsJustification + ImportResult::Imported(ImportedAux { needs_justification: true, clear_justification_requests: false, bad_justification: false }), + ); + + assert_eq!( + block_import.import_block(block(), None).unwrap(), + ImportResult::AlreadyInChain + ); +} + +#[test] +fn test_bad_justification() { + let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie]; + 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 client = net.peer(0).client().clone(); + let (block_import, ..) = net.make_block_import(client.clone()); + + let builder = client.new_block_at(&BlockId::Number(0)).unwrap(); + let block = builder.bake().unwrap(); + api.scheduled_changes.lock().insert(*block.header.parent_hash(), ScheduledChange { + next_authorities: make_ids(peers_b), + delay: 0, + }); + + let block = || { + let block = block.clone(); + ImportBlock { + origin: BlockOrigin::File, + header: block.header, + justification: Some(Vec::new()), + post_digests: Vec::new(), + body: Some(block.extrinsics), + finalized: false, + auxiliary: Vec::new(), + fork_choice: ForkChoiceStrategy::LongestChain, + } + }; + + assert_eq!( + block_import.import_block(block(), None).unwrap(), + ImportResult::Imported(ImportedAux { needs_justification: true, clear_justification_requests: false, bad_justification: true }), ); assert_eq!( diff --git a/core/finality-grandpa/src/until_imported.rs b/core/finality-grandpa/src/until_imported.rs index 3d68e8cd848166c2db17bf7185648fbbb0e2dcd1..4b867c18c8e2bea8f0ca2e02db34a2fd5eaf75a2 100644 --- a/core/finality-grandpa/src/until_imported.rs +++ b/core/finality-grandpa/src/until_imported.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -28,7 +28,7 @@ use futures::prelude::*; use futures::stream::Fuse; use parking_lot::Mutex; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, NumberFor}; -use substrate_primitives::Ed25519AuthorityId; +use substrate_primitives::ed25519::Public as AuthorityId; use tokio::timer::Interval; use std::collections::{HashMap, VecDeque}; @@ -199,7 +199,7 @@ impl Stream for UntilImported } } -fn warn_authority_wrong_target(hash: H, id: Ed25519AuthorityId) { +fn warn_authority_wrong_target(hash: H, id: AuthorityId) { warn!( target: "afg", "Authority {:?} signed GRANDPA message with \ diff --git a/core/inherents/Cargo.toml b/core/inherents/Cargo.toml index 8ba1f10ca6b7d07b19242bf55c3a22e9efa1f65f..d3292095cc5f405a388ab1aab179cf8057030057 100644 --- a/core/inherents/Cargo.toml +++ b/core/inherents/Cargo.toml @@ -7,8 +7,7 @@ edition = "2018" [dependencies] parking_lot = { version = "0.7", optional = true } rstd = { package = "sr-std", path = "../sr-std", default-features = false } -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", 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 becd99e48167f91b000ddc868f9a01b32a76a74e..7d2324bc933cdaeb5ab6d0b3f6a8d7579ec385b4 100644 --- a/core/inherents/src/lib.rs +++ b/core/inherents/src/lib.rs @@ -31,9 +31,10 @@ //! information on how that is done. #![cfg_attr(not(feature = "std"), no_std)] +#![warn(missing_docs)] use parity_codec as codec; -use parity_codec_derive::{Encode, Decode}; +use codec::{Encode, Decode}; use rstd::{collections::btree_map::{BTreeMap, IntoIter, Entry}, vec::Vec}; @@ -43,6 +44,9 @@ use parking_lot::RwLock; #[cfg(feature = "std")] use std::{sync::Arc, format}; +#[cfg(feature = "std")] +pub mod pool; + pub use runtime_primitives::RuntimeString; /// An identifier for an inherent. @@ -399,7 +403,7 @@ pub trait ProvideInherent { fn create_inherent(data: &InherentData) -> Option; /// Check the given inherent if it is valid. - /// Checking the inherent is optional and can be ommitted. + /// Checking the inherent is optional and can be omitted. fn check_inherent(_: &Self::Call, _: &InherentData) -> Result<(), Self::Error> { Ok(()) } diff --git a/core/inherents/src/pool.rs b/core/inherents/src/pool.rs new file mode 100644 index 0000000000000000000000000000000000000000..2c7e953696a55ab9d134615a2371bbc48f902628 --- /dev/null +++ b/core/inherents/src/pool.rs @@ -0,0 +1,75 @@ +// 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 . + +//! Inherents Pool + +use std::{fmt, mem, vec}; +use parking_lot::Mutex; + +/// Inherents Pool +/// +/// The pool is responsible to collect inherents asynchronously generated +/// by some other parts of the code and make them ready for the next block production. +pub struct InherentsPool { + data: Mutex>, +} + +impl Default for InherentsPool { + fn default() -> Self { + InherentsPool { + data: Default::default(), + } + } +} + +impl fmt::Debug for InherentsPool { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut builder = fmt.debug_struct("InherentsPool"); + if let Some(data) = self.data.try_lock() { + builder.field("data", &*data); + } + builder.finish() + } +} + +impl InherentsPool { + /// Add inherent extrinsic to the pool. + /// + /// This inherent will be appended to the next produced block. + pub fn add(&self, extrinsic: T) { + self.data.lock().push(extrinsic); + } + + /// Drain all currently queued inherents. + pub fn drain(&self) -> Vec { + mem::replace(&mut *self.data.lock(), vec![]) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn should_drain_inherents_to_given_data() { + let pool = InherentsPool::default(); + pool.add(5); + pool.add(7); + + assert_eq!(pool.drain(), vec![5, 7]); + assert_eq!(pool.drain(), vec![]); + } +} diff --git a/core/keyring/Cargo.toml b/core/keyring/Cargo.toml index e3203742473e4a3c2cf66d8ccbcd00d88f00d1dc..db480744b74faa0fc306095a8a0d0223900d25a1 100644 --- a/core/keyring/Cargo.toml +++ b/core/keyring/Cargo.toml @@ -8,3 +8,5 @@ edition = "2018" substrate-primitives = { path = "../primitives" } hex-literal = { version = "0.1.0" } lazy_static = { version = "1.0" } +strum = "0.14.0" +strum_macros = "0.14.0" diff --git a/core/keyring/src/ed25519.rs b/core/keyring/src/ed25519.rs index 267da3995cdaf2263328e249681ee11feeb8502c..f36d8fd4853e97b7ac541f7acb1acf5fcc6adca6 100644 --- a/core/keyring/src/ed25519.rs +++ b/core/keyring/src/ed25519.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -16,15 +16,13 @@ //! Support code for the runtime. A set of test accounts. -use std::collections::HashMap; -use std::ops::Deref; +use std::{collections::HashMap, ops::Deref}; use lazy_static::lazy_static; -use hex_literal::{hex, hex_impl}; -use substrate_primitives::ed25519::{Pair, Public, Signature}; +use substrate_primitives::{ed25519::{Pair, Public, Signature}, Pair as PairT, H256}; pub use substrate_primitives::ed25519; /// Set of test accounts. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum_macros::Display, strum_macros::EnumIter)] pub enum Keyring { Alice, Bob, @@ -37,7 +35,7 @@ pub enum Keyring { } impl Keyring { - pub fn from_public(who: Public) -> Option { + pub fn from_public(who: &Public) -> Option { [ Keyring::Alice, Keyring::Bob, @@ -49,17 +47,25 @@ impl Keyring { Keyring::Two, ].iter() .map(|i| *i) - .find(|&k| Public::from(k) == who) + .find(|&k| &Public::from(k) == who) } pub fn from_raw_public(who: [u8; 32]) -> Option { - Self::from_public(Public::from_raw(who)) + Self::from_public(&Public::from_raw(who)) } pub fn to_raw_public(self) -> [u8; 32] { *Public::from(self).as_array_ref() } + pub fn from_h256_public(who: H256) -> Option { + Self::from_public(&Public::from_raw(who.into())) + } + + pub fn to_h256_public(self) -> H256 { + Public::from(self).as_array_ref().into() + } + pub fn to_raw_public_vec(self) -> Vec { Public::from(self).to_raw_vec() } @@ -69,16 +75,13 @@ impl Keyring { } pub fn pair(self) -> Pair { - match self { - Keyring::Alice => Pair::from_seed(b"Alice "), - Keyring::Bob => Pair::from_seed(b"Bob "), - Keyring::Charlie => Pair::from_seed(b"Charlie "), - Keyring::Dave => Pair::from_seed(b"Dave "), - Keyring::Eve => Pair::from_seed(b"Eve "), - Keyring::Ferdie => Pair::from_seed(b"Ferdie "), - Keyring::One => Pair::from_seed(b"12345678901234567890123456789012"), - Keyring::Two => Pair::from_seed(&hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")), - } + Pair::from_string(&format!("//{}", <&'static str>::from(self)), None) + .expect("static values are known good; qed") + } + + /// Returns an interator over all test accounts. + pub fn iter() -> impl Iterator { + ::iter() } } @@ -91,24 +94,15 @@ impl From for &'static str { Keyring::Dave => "Dave", Keyring::Eve => "Eve", Keyring::Ferdie => "Ferdie", - Keyring::One => "one", - Keyring::Two => "two", + Keyring::One => "One", + Keyring::Two => "Two", } } } lazy_static! { static ref PRIVATE_KEYS: HashMap = { - [ - Keyring::Alice, - Keyring::Bob, - Keyring::Charlie, - Keyring::Dave, - Keyring::Eve, - Keyring::Ferdie, - Keyring::One, - Keyring::Two, - ].iter().map(|&i| (i, i.pair())).collect() + Keyring::iter().map(|i| (i, i.pair())).collect() }; static ref PUBLIC_KEYS: HashMap = { @@ -134,6 +128,12 @@ impl From for [u8; 32] { } } +impl From for H256 { + fn from(k: Keyring) -> Self { + (*PUBLIC_KEYS).get(&k).unwrap().as_array_ref().into() + } +} + impl From for &'static [u8; 32] { fn from(k: Keyring) -> Self { (*PUBLIC_KEYS).get(&k).unwrap().as_array_ref() @@ -162,12 +162,12 @@ impl Deref for Keyring { #[cfg(test)] mod tests { use super::*; - use ed25519::Verifiable; + use substrate_primitives::{ed25519::Pair, Pair as PairT}; #[test] fn should_work() { - assert!(Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", Keyring::Alice)); - assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Bob!", Keyring::Alice)); - assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", Keyring::Bob)); + assert!(Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Alice!", Keyring::Alice)); + assert!(!Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Bob!", Keyring::Alice)); + assert!(!Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Alice!", Keyring::Bob)); } } diff --git a/core/keyring/src/lib.rs b/core/keyring/src/lib.rs index aa271d81891ba744c3119e86197f645bdfa0e907..5cf38401d0823f84a80054e9ccb9eb2d9bb8eba0 100644 --- a/core/keyring/src/lib.rs +++ b/core/keyring/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -22,7 +22,15 @@ pub mod sr25519; /// Test account crypto for ed25519. pub mod ed25519; -/// The Ed25519 keyring. -/// -/// This is deprecated: use `ed25519::Keyring` instead. -pub use ed25519::Keyring; +/// Convenience export: Sr25519's Keyring is exposed as `AccountKeyring`, +/// since it tends to be used for accounts. +pub use sr25519::Keyring as AccountKeyring; + +/// Convenience export: Ed25519's Keyring is exposed as `AuthorityKeyring`, +/// since it tends to be used for authorities (session keys &c.). +pub use ed25519::Keyring as AuthorityKeyring; + +pub mod test { + /// The keyring for use with accounts when using the test runtime. + pub use super::ed25519::Keyring as AccountKeyring; +} diff --git a/core/keyring/src/sr25519.rs b/core/keyring/src/sr25519.rs index 0142ab56f2232c6b2b34d68f04d8dc30d579f7a9..1d3342d86d1c4bc34fbda9c00802915b5a45eedf 100644 --- a/core/keyring/src/sr25519.rs +++ b/core/keyring/src/sr25519.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -19,8 +19,7 @@ use std::collections::HashMap; use std::ops::Deref; use lazy_static::lazy_static; -use hex_literal::{hex, hex_impl}; -use substrate_primitives::sr25519::{Pair, Public, Signature}; +use substrate_primitives::{sr25519::{Pair, Public, Signature}, Pair as PairT, H256}; pub use substrate_primitives::sr25519; /// Set of test accounts. @@ -37,7 +36,7 @@ pub enum Keyring { } impl Keyring { - pub fn from_public(who: Public) -> Option { + pub fn from_public(who: &Public) -> Option { [ Keyring::Alice, Keyring::Bob, @@ -49,17 +48,25 @@ impl Keyring { Keyring::Two, ].iter() .map(|i| *i) - .find(|&k| Public::from(k) == who) + .find(|&k| &Public::from(k) == who) } pub fn from_raw_public(who: [u8; 32]) -> Option { - Self::from_public(Public::from_raw(who)) + Self::from_public(&Public::from_raw(who)) } pub fn to_raw_public(self) -> [u8; 32] { *Public::from(self).as_array_ref() } + pub fn from_h256_public(who: H256) -> Option { + Self::from_public(&Public::from_raw(who.into())) + } + + pub fn to_h256_public(self) -> H256 { + Public::from(self).as_array_ref().into() + } + pub fn to_raw_public_vec(self) -> Vec { Public::from(self).to_raw_vec() } @@ -69,16 +76,8 @@ impl Keyring { } pub fn pair(self) -> Pair { - match self { - Keyring::Alice => Pair::from_seed(b"Alice "), - Keyring::Bob => Pair::from_seed(b"Bob "), - Keyring::Charlie => Pair::from_seed(b"Charlie "), - Keyring::Dave => Pair::from_seed(b"Dave "), - Keyring::Eve => Pair::from_seed(b"Eve "), - Keyring::Ferdie => Pair::from_seed(b"Ferdie "), - Keyring::One => Pair::from_seed(b"12345678901234567890123456789012"), - Keyring::Two => Pair::from_seed(&hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")), - } + Pair::from_string(&format!("//{}", <&'static str>::from(self)), None) + .expect("static values are known good; qed") } } @@ -91,8 +90,8 @@ impl From for &'static str { Keyring::Dave => "Dave", Keyring::Eve => "Eve", Keyring::Ferdie => "Ferdie", - Keyring::One => "one", - Keyring::Two => "two", + Keyring::One => "One", + Keyring::Two => "Two", } } } @@ -134,6 +133,12 @@ impl From for [u8; 32] { } } +impl From for H256 { + fn from(k: Keyring) -> Self { + (*PUBLIC_KEYS).get(&k).unwrap().as_array_ref().into() + } +} + impl From for &'static [u8; 32] { fn from(k: Keyring) -> Self { (*PUBLIC_KEYS).get(&k).unwrap().as_array_ref() @@ -162,12 +167,12 @@ impl Deref for Keyring { #[cfg(test)] mod tests { use super::*; - use sr25519::Verifiable; + use substrate_primitives::{sr25519::Pair, Pair as PairT}; #[test] fn should_work() { - assert!(Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", Keyring::Alice)); - assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Bob!", Keyring::Alice)); - assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", Keyring::Bob)); + assert!(Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Alice!", Keyring::Alice)); + assert!(!Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Bob!", Keyring::Alice)); + assert!(!Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Alice!", Keyring::Bob)); } } diff --git a/core/keystore/src/lib.rs b/core/keystore/src/lib.rs index 98bddb70742a89bca439be7a4243f3737985a8d7..59c1a65cfb1cd14317ab08dc41bfa5aec0ee300d 100644 --- a/core/keystore/src/lib.rs +++ b/core/keystore/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -24,13 +24,11 @@ use std::collections::HashMap; use std::path::PathBuf; use std::fs::{self, File}; use std::io::{self, Write}; -use std::num::NonZeroU32; -use serde_derive::{Serialize, Deserialize}; -use error_chain::{error_chain, error_chain_processing, impl_error_chain_processed, +use error_chain::{bail, error_chain, error_chain_processing, impl_error_chain_processed, impl_extract_backtrace, impl_error_chain_kind}; -use substrate_primitives::{hashing::blake2_256, ed25519::{Pair, Public, PKCS_LEN}}; +use substrate_primitives::{ed25519::{Pair, Public}, Pair as PairT}; pub use crypto::KEY_ITERATIONS; @@ -45,99 +43,21 @@ error_chain! { description("Invalid password"), display("Invalid password"), } - InvalidPKCS8 { - description("Invalid PKCS#8 data"), - display("Invalid PKCS#8 data"), + InvalidPhrase { + description("Invalid recovery phrase (BIP39) data"), + display("Invalid recovery phrase (BIP39) data"), } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct InvalidPassword; - -#[derive(Serialize, Deserialize)] -struct EncryptedKey { - mac: [u8; 32], - salt: [u8; 32], - ciphertext: Vec, // FIXME: switch to fixed-size when serde supports - iv: [u8; 16], - iterations: NonZeroU32, -} - -impl EncryptedKey { - fn encrypt(plain: &[u8; PKCS_LEN], password: &str, iterations: NonZeroU32) -> Self { - use rand::{Rng, rngs::OsRng}; - - let mut rng = OsRng::new().expect("OS Randomness available on all supported platforms; qed"); - - let salt: [u8; 32] = rng.gen(); - let iv: [u8; 16] = rng.gen(); - - // two parts of derived key - // DK = [ DK[0..15] DK[16..31] ] = [derived_left_bits, derived_right_bits] - let (derived_left_bits, derived_right_bits) = crypto::derive_key_iterations(password.as_bytes(), &salt, iterations); - - // preallocated (on-stack in case of `Secret`) buffer to hold cipher - // length = length(plain) as we are using CTR-approach - let mut ciphertext = vec![0; PKCS_LEN]; - - // aes-128-ctr with initial vector of iv - crypto::aes::encrypt_128_ctr(&derived_left_bits, &iv, plain, &mut *ciphertext) - .expect("input lengths of key and iv are both 16; qed"); - - // Blake2_256(DK[16..31] ++ ), where DK[16..31] - derived_right_bits - let mac = blake2_256(&crypto::derive_mac(&derived_right_bits, &*ciphertext)); - - EncryptedKey { - salt, - iv, - mac, - iterations, - ciphertext, - } - } - - fn decrypt(&self, password: &str) -> Result<[u8; PKCS_LEN]> { - let (derived_left_bits, derived_right_bits) = - crypto::derive_key_iterations(password.as_bytes(), &self.salt, self.iterations); - - let mac = blake2_256(&crypto::derive_mac(&derived_right_bits, &self.ciphertext)); - - if subtle::ConstantTimeEq::ct_eq(&mac[..], &self.mac[..]).unwrap_u8() != 1 { - return Err(ErrorKind::InvalidPassword.into()); + InvalidSeed { + description("Invalid seed"), + display("Invalid seed"), } - - let mut plain = [0; PKCS_LEN]; - crypto::aes::decrypt_128_ctr(&derived_left_bits, &self.iv, &self.ciphertext, &mut plain[..]) - .expect("input lengths of key and iv are both 16; qed"); - Ok(plain) } } -type Seed = [u8; 32]; - /// Key store. pub struct Store { path: PathBuf, - additional: HashMap, -} - -pub fn pad_seed(seed: &str) -> Seed { - let mut s: [u8; 32] = [' ' as u8; 32]; - - let was_hex = if seed.len() == 66 && &seed[0..2] == "0x" { - if let Ok(d) = hex::decode(&seed[2..]) { - s.copy_from_slice(&d); - true - } else { false } - } else { false }; - - if !was_hex { - let len = ::std::cmp::min(32, seed.len()); - &mut s[..len].copy_from_slice(&seed.as_bytes()[..len]); - } - - s + additional: HashMap, } impl Store { @@ -149,44 +69,36 @@ impl Store { /// Generate a new key, placing it into the store. pub fn generate(&self, password: &str) -> Result { - let (pair, pkcs_bytes) = Pair::generate_with_pkcs8(); - let key_file = EncryptedKey::encrypt( - &pkcs_bytes, - password, - NonZeroU32::new(KEY_ITERATIONS as u32).expect("KEY_ITERATIONS is not zero; QED") - ); - + let (pair, phrase) = Pair::generate_with_phrase(Some(password)); let mut file = File::create(self.key_file_path(&pair.public()))?; - ::serde_json::to_writer(&file, &key_file)?; - + ::serde_json::to_writer(&file, &phrase)?; file.flush()?; - Ok(pair) } /// Create a new key from seed. Do not place it into the store. - /// Only the first 32 bytes of the sead are used. This is meant to be used for testing only. - // FIXME: remove this - https://github.com/paritytech/substrate/issues/1063 pub fn generate_from_seed(&mut self, seed: &str) -> Result { - let padded_seed = pad_seed(seed); - let pair = Pair::from_seed(&padded_seed); - self.additional.insert(pair.public(), padded_seed); + let pair = Pair::from_string(seed, None) + .map_err(|_| Error::from(ErrorKind::InvalidSeed))?; + self.additional.insert(pair.public(), pair.clone()); Ok(pair) } /// Load a key file with given public key. pub fn load(&self, public: &Public, password: &str) -> Result { - if let Some(ref seed) = self.additional.get(public) { - let pair = Pair::from_seed(seed); - return Ok(pair); + if let Some(pair) = self.additional.get(public) { + return Ok(pair.clone()); } let path = self.key_file_path(public); let file = File::open(path)?; - let encrypted_key: EncryptedKey = ::serde_json::from_reader(&file)?; - let pkcs_bytes = encrypted_key.decrypt(password)?; - - Pair::from_pkcs8(&pkcs_bytes[..]).map_err(|_| ErrorKind::InvalidPKCS8.into()) + let phrase: String = ::serde_json::from_reader(&file)?; + let pair = Pair::from_phrase(&phrase, Some(password)) + .map_err(|_| Error::from(ErrorKind::InvalidPhrase))?; + if &pair.public() != public { + bail!(ErrorKind::InvalidPassword); + } + Ok(pair) } /// Get public keys of all stored keys. @@ -227,42 +139,6 @@ mod tests { use super::*; use tempdir::TempDir; - #[test] - fn encrypt_and_decrypt() { - let plain = [1; PKCS_LEN]; - let encrypted_key = EncryptedKey::encrypt(&plain, "thepassword", NonZeroU32::new(KEY_ITERATIONS as u32).expect("KEY_ITERATIONS is not zero; QED")); - - let decrypted_key = encrypted_key.decrypt("thepassword").unwrap(); - - assert_eq!(&plain[..], &decrypted_key[..]); - } - - #[test] - fn decrypt_wrong_password_fails() { - let plain = [1; PKCS_LEN]; - let encrypted_key = EncryptedKey::encrypt( - &plain, - "thepassword", - NonZeroU32::new(KEY_ITERATIONS as u32).expect("KEY_ITERATIONS is not zero; QED") - ); - - assert!(encrypted_key.decrypt("thepassword2").is_err()); - } - - #[test] - fn decrypt_wrong_iterations_fails() { - let plain = [1; PKCS_LEN]; - let mut encrypted_key = EncryptedKey::encrypt( - &plain, - "thepassword", - NonZeroU32::new(KEY_ITERATIONS as u32).expect("KEY_ITERATIONS is not zero; QED") - ); - - encrypted_key.iterations = NonZeroU32::new(encrypted_key.iterations.get() - 64).unwrap(); - - assert!(encrypted_key.decrypt("thepassword").is_err()); - } - #[test] fn basic_store() { let temp_dir = TempDir::new("keystore").unwrap(); @@ -285,16 +161,7 @@ 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("0x1").unwrap(); - assert_eq!("5GqhgbUd2S9uc5Tm7hWhw29Tw2jBnuHshmTV1fDF4V1w3G2z", pair.public().to_ss58check()); - let pair = store.generate_from_seed("0x3d97c819d68f9bafa7d6e79cb991eebcd77d966c5334c0b94d9e1fa7ad0869dc").unwrap(); assert_eq!("5DKUrgFqCPV8iAXx9sjy1nyBygQCeiUYRFWurZGhnrn3HBL8", pair.public().to_ss58check()); - - let pair = store.generate_from_seed("12345678901234567890123456789022").unwrap(); - assert_eq!("5DscZvfjnM5im7oKRXXP9xtCG1SEwfMb8J5eGLmw5EHhoHR3", pair.public().to_ss58check()); - - let pair = store.generate_from_seed("1").unwrap(); - assert_eq!("5DYnksEZFc7kgtfyNM1xK2eBtW142gZ3Ho3NQubrF2S6B2fq", pair.public().to_ss58check()); } } diff --git a/core/network-libp2p/Cargo.toml b/core/network-libp2p/Cargo.toml index ab784ac9783fc8bdd2bad8d52203c5a9c252304c..78bda5b193d6fbc77294b75597bce6f9d62bc647 100644 --- a/core/network-libp2p/Cargo.toml +++ b/core/network-libp2p/Cargo.toml @@ -13,7 +13,7 @@ bytes = "0.4" error-chain = { version = "0.12", default-features = false } fnv = "1.0" futures = "0.1" -libp2p = { version = "0.4.0", default-features = false, features = ["secio-secp256k1", "libp2p-websocket"] } +libp2p = { git = "https://github.com/tomaka/libp2p-rs", branch = "substrate-tmp-2019-03-20", default-features = false, features = ["secio-secp256k1", "libp2p-websocket"] } parking_lot = "0.7.1" lazy_static = "1.2" log = "0.4" @@ -22,8 +22,13 @@ serde = "1.0.70" serde_derive = "1.0.70" serde_json = "1.0.24" smallvec = "0.6" +substrate-peerset = { path = "../peerset" } tokio = "0.1" tokio-io = "0.1" tokio-timer = "0.2" unsigned-varint = { version = "0.2.1", features = ["codec"] } void = "1.0" + +[dev-dependencies] +tempdir = "0.3" + diff --git a/core/network-libp2p/src/behaviour.rs b/core/network-libp2p/src/behaviour.rs index da1282b88cfc6bbd51665042944e16dbae2981c9..c1d175bb1687da2876f0b558f1d7f278025726c2 100644 --- a/core/network-libp2p/src/behaviour.rs +++ b/core/network-libp2p/src/behaviour.rs @@ -14,18 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use crate::custom_proto::{CustomProtos, CustomProtosOut, RegisteredProtocols}; -use crate::{NetworkConfiguration, ProtocolId}; +use crate::custom_proto::{CustomProto, CustomProtoOut, RegisteredProtocol}; use futures::prelude::*; use libp2p::NetworkBehaviour; use libp2p::core::{Multiaddr, PeerId, ProtocolsHandler, PublicKey}; use libp2p::core::swarm::{ConnectedPoint, NetworkBehaviour, NetworkBehaviourAction}; use libp2p::core::swarm::{NetworkBehaviourEventProcess, PollParameters}; use libp2p::identify::{Identify, IdentifyEvent, protocol::IdentifyInfo}; -use libp2p::kad::{Kademlia, KademliaOut, KadConnectionType}; +use libp2p::kad::{Kademlia, KademliaOut}; use libp2p::ping::{Ping, PingEvent}; use log::{debug, trace, warn}; -use std::{cmp, io, time::Duration, time::Instant}; +use std::{cmp, io, fmt, time::Duration, time::Instant}; use tokio_io::{AsyncRead, AsyncWrite}; use tokio_timer::Delay; use void; @@ -37,7 +36,7 @@ pub struct Behaviour { /// Periodically ping nodes, and close the connection if it's unresponsive. ping: Ping, /// Custom protocols (dot, bbq, sub, etc.). - custom_protocols: CustomProtos, + custom_protocols: CustomProto, /// Discovers nodes of the network. Defined below. discovery: DiscoveryBehaviour, /// Periodically identifies the remote and responds to incoming requests. @@ -50,83 +49,71 @@ pub struct Behaviour { impl Behaviour { /// Builds a new `Behaviour`. - // TODO: redundancy between config and local_public_key (https://github.com/libp2p/rust-libp2p/issues/745) - pub fn new(config: &NetworkConfiguration, local_public_key: PublicKey, protocols: RegisteredProtocols) -> Self { + pub fn new( + user_agent: String, + local_public_key: PublicKey, + protocol: RegisteredProtocol, + known_addresses: Vec<(PeerId, Multiaddr)>, + peerset: substrate_peerset::PeersetMut, + ) -> Self { let identify = { let proto_version = "/substrate/1.0".to_string(); - let user_agent = format!("{} ({})", config.client_version, config.node_name); Identify::new(proto_version, user_agent, local_public_key.clone()) }; - let local_peer_id = local_public_key.into_peer_id(); - let custom_protocols = CustomProtos::new(config, &local_peer_id, protocols); + let custom_protocols = CustomProto::new(protocol, peerset); + + let mut kademlia = Kademlia::without_init(local_public_key.into_peer_id()); + for (peer_id, addr) in &known_addresses { + kademlia.add_connected_address(peer_id, addr.clone()); + } + kademlia.initialize(); Behaviour { ping: Ping::new(), custom_protocols, - discovery: DiscoveryBehaviour::new(local_peer_id), + discovery: DiscoveryBehaviour { + user_defined: known_addresses, + kademlia, + next_kad_random_query: Delay::new(Instant::now()), + duration_to_next_kad: Duration::from_secs(10), + }, identify, events: Vec::new(), } } - /// Sends a message to a peer using the given custom protocol. + /// Sends a message to a peer. /// /// Has no effect if the custom protocol is not open with the given peer. /// /// Also note that even we have a valid open substream, it may in fact be already closed /// without us knowing, in which case the packet will not be received. #[inline] - pub fn send_custom_message(&mut self, target: &PeerId, protocol_id: ProtocolId, data: TMessage) { - self.custom_protocols.send_packet(target, protocol_id, data) - } - - /// Returns the number of peers in the topology. - pub fn num_topology_peers(&self) -> usize { - self.custom_protocols.num_topology_peers() - } - - /// Flushes the topology to the disk. - pub fn flush_topology(&mut self) -> Result<(), io::Error> { - self.custom_protocols.flush_topology() - } - - /// Perform a cleanup pass, removing all obsolete addresses and peers. - /// - /// This should be done from time to time. - pub fn cleanup(&mut self) { - self.custom_protocols.cleanup(); - } - - /// Try to add a reserved peer. - pub fn add_reserved_peer(&mut self, peer_id: PeerId, addr: Multiaddr) { - self.custom_protocols.add_reserved_peer(peer_id, addr) + pub fn send_custom_message(&mut self, target: &PeerId, data: TMessage) { + self.custom_protocols.send_packet(target, data) } - /// Try to remove a reserved peer. - /// - /// If we are in reserved mode and we were connected to a node with this peer ID, then this - /// method will disconnect it and return its index. - pub fn remove_reserved_peer(&mut self, peer_id: PeerId) { - self.custom_protocols.remove_reserved_peer(peer_id) + /// Returns the list of nodes that we know exist in the network. + pub fn known_peers(&self) -> impl Iterator { + self.discovery.kademlia.kbuckets_entries() } - /// Start accepting all peers again if we weren't. - pub fn accept_unreserved_peers(&mut self) { - self.custom_protocols.accept_unreserved_peers() + /// Returns true if we try to open protocols with the given peer. + pub fn is_enabled(&self, peer_id: &PeerId) -> bool { + self.custom_protocols.is_enabled(peer_id) } - /// Start refusing non-reserved nodes. Returns the list of nodes that have been disconnected. - pub fn deny_unreserved_peers(&mut self) { - self.custom_protocols.deny_unreserved_peers() + /// Returns true if we have an open protocol with the given peer. + pub fn is_open(&self, peer_id: &PeerId) -> bool { + self.custom_protocols.is_open(peer_id) } - /// Disconnects a peer and bans it for a little while. - /// - /// Same as `drop_node`, except that the same peer will not be able to reconnect later. - #[inline] - pub fn ban_node(&mut self, peer_id: PeerId) { - self.custom_protocols.ban_peer(peer_id) + /// Adds a hard-coded address for the given peer, that never expires. + pub fn add_known_address(&mut self, peer_id: PeerId, addr: Multiaddr) { + if self.discovery.user_defined.iter().all(|(p, a)| *p != peer_id && *a != addr) { + self.discovery.user_defined.push((peer_id, addr)); + } } /// Disconnects the custom protocols from a peer. @@ -142,6 +129,11 @@ impl Behaviour { pub fn drop_node(&mut self, peer_id: &PeerId) { self.custom_protocols.disconnect_peer(peer_id) } + + /// Returns the state of the peerset manager, for debugging purposes. + pub fn peerset_debug_info(&self) -> serde_json::Value { + self.custom_protocols.peerset_debug_info() + } } /// Event that can be emitted by the behaviour. @@ -149,8 +141,6 @@ impl Behaviour { pub enum BehaviourOut { /// Opened a custom protocol with the remote. CustomProtocolOpen { - /// Identifier of the protocol. - protocol_id: ProtocolId, /// Version of the protocol that has been opened. version: u8, /// Id of the node we have opened a connection with. @@ -163,8 +153,6 @@ pub enum BehaviourOut { CustomProtocolClosed { /// Id of the peer we were connected to. peer_id: PeerId, - /// Identifier of the protocol. - protocol_id: ProtocolId, /// Reason why the substream closed. If `Ok`, then it's a graceful exit (EOF). result: io::Result<()>, }, @@ -173,8 +161,6 @@ pub enum BehaviourOut { CustomMessage { /// Id of the peer the message came from. peer_id: PeerId, - /// Protocol which generated the message. - protocol_id: ProtocolId, /// Message that has been received. message: TMessage, }, @@ -183,8 +169,6 @@ pub enum BehaviourOut { Clogged { /// Id of the peer the message came from. peer_id: PeerId, - /// Protocol which generated the message. - protocol_id: ProtocolId, /// Copy of the messages that are within the buffer, for further diagnostic. messages: Vec, }, @@ -196,22 +180,30 @@ pub enum BehaviourOut { /// Information about the peer. info: IdentifyInfo, }, + + /// We have successfully pinged a peer. + PingSuccess { + /// Id of the peer that has been pinged. + peer_id: PeerId, + /// Time it took for the ping to come back. + ping_time: Duration, + }, } -impl From> for BehaviourOut { - fn from(other: CustomProtosOut) -> BehaviourOut { +impl From> for BehaviourOut { + fn from(other: CustomProtoOut) -> BehaviourOut { match other { - CustomProtosOut::CustomProtocolOpen { protocol_id, version, peer_id, endpoint } => { - BehaviourOut::CustomProtocolOpen { protocol_id, version, peer_id, endpoint } + CustomProtoOut::CustomProtocolOpen { version, peer_id, endpoint } => { + BehaviourOut::CustomProtocolOpen { version, peer_id, endpoint } } - CustomProtosOut::CustomProtocolClosed { protocol_id, peer_id, result } => { - BehaviourOut::CustomProtocolClosed { protocol_id, peer_id, result } + CustomProtoOut::CustomProtocolClosed { peer_id, result } => { + BehaviourOut::CustomProtocolClosed { peer_id, result } } - CustomProtosOut::CustomMessage { protocol_id, peer_id, message } => { - BehaviourOut::CustomMessage { protocol_id, peer_id, message } + CustomProtoOut::CustomMessage { peer_id, message } => { + BehaviourOut::CustomMessage { peer_id, message } } - CustomProtosOut::Clogged { protocol_id, peer_id, messages } => { - BehaviourOut::Clogged { protocol_id, peer_id, messages } + CustomProtoOut::Clogged { peer_id, messages } => { + BehaviourOut::Clogged { peer_id, messages } } } } @@ -223,8 +215,8 @@ impl NetworkBehaviourEventProcess for Behaviou } } -impl NetworkBehaviourEventProcess> for Behaviour { - fn inject_event(&mut self, event: CustomProtosOut) { +impl NetworkBehaviourEventProcess> for Behaviour { + fn inject_event(&mut self, event: CustomProtoOut) { self.events.push(event.into()); } } @@ -248,10 +240,7 @@ impl NetworkBehaviourEventProcess for Behav for addr in &info.listen_addrs { self.discovery.kademlia.add_connected_address(&peer_id, addr.clone()); } - self.custom_protocols.add_discovered_addrs( - &peer_id, - info.listen_addrs.iter().map(|addr| (addr.clone(), true)) - ); + self.custom_protocols.add_discovered_node(&peer_id); self.events.push(BehaviourOut::Identified { peer_id, info }); } IdentifyEvent::Error { .. } => {} @@ -266,17 +255,16 @@ impl NetworkBehaviourEventProcess for Behav impl NetworkBehaviourEventProcess for Behaviour { fn inject_event(&mut self, out: KademliaOut) { match out { - KademliaOut::Discovered { peer_id, addresses, ty } => { - self.custom_protocols.add_discovered_addrs( - &peer_id, - addresses.into_iter().map(|addr| (addr, ty == KadConnectionType::Connected)) - ); + KademliaOut::Discovered { .. } => {} + KademliaOut::KBucketAdded { peer_id, .. } => { + self.custom_protocols.add_discovered_node(&peer_id); } KademliaOut::FindNodeResult { key, closer_peers } => { - trace!(target: "sub-libp2p", "Kademlia query for {:?} yielded {:?} results", + trace!(target: "sub-libp2p", "Libp2p => Query for {:?} yielded {:?} results", key, closer_peers.len()); if closer_peers.is_empty() { - warn!(target: "sub-libp2p", "Kademlia random query has yielded empty results"); + warn!(target: "sub-libp2p", "Libp2p => Random Kademlia query has yielded empty \ + results"); } } // We never start any GET_PROVIDERS query. @@ -290,6 +278,7 @@ impl NetworkBehaviourEventProcess for Behaviour match event { PingEvent::PingSuccess { peer, time } => { trace!(target: "sub-libp2p", "Ping time with {:?}: {:?}", peer, time); + self.events.push(BehaviourOut::PingSuccess { peer_id: peer, ping_time: time }); } } } @@ -307,6 +296,9 @@ impl Behaviour { /// Implementation of `NetworkBehaviour` that discovers the nodes on the network. pub struct DiscoveryBehaviour { + /// User-defined list of nodes and their addresses. Typically includes bootstrap nodes and + /// reserved nodes. + user_defined: Vec<(PeerId, Multiaddr)>, /// Kademlia requests and answers. kademlia: Kademlia, /// Stream that fires when we need to perform the next random Kademlia query. @@ -315,16 +307,6 @@ pub struct DiscoveryBehaviour { duration_to_next_kad: Duration, } -impl DiscoveryBehaviour { - fn new(local_peer_id: PeerId) -> Self { - DiscoveryBehaviour { - kademlia: Kademlia::without_init(local_peer_id), - next_kad_random_query: Delay::new(Instant::now()), - duration_to_next_kad: Duration::from_secs(1), - } - } -} - impl NetworkBehaviour for DiscoveryBehaviour where TSubstream: AsyncRead + AsyncWrite, @@ -337,7 +319,21 @@ where } fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec { - self.kademlia.addresses_of_peer(peer_id) + let mut list = self.user_defined.iter() + .filter_map(|(p, a)| if p == peer_id { Some(a.clone()) } else { None }) + .collect::>(); + list.extend(self.kademlia.addresses_of_peer(peer_id)); + trace!(target: "sub-libp2p", "Addresses of {:?} are {:?}", peer_id, list); + if list.is_empty() { + if self.kademlia.kbuckets_entries().any(|p| p == peer_id) { + debug!(target: "sub-libp2p", "Requested dialing to {:?} (peer in k-buckets), \ + and no address was found", peer_id); + } else { + debug!(target: "sub-libp2p", "Requested dialing to {:?} (peer not in k-buckets), \ + and no address was found", peer_id); + } + } + list } fn inject_connected(&mut self, peer_id: PeerId, endpoint: ConnectedPoint) { @@ -381,8 +377,8 @@ where Ok(Async::NotReady) => break, Ok(Async::Ready(_)) => { let random_peer_id = PeerId::random(); - debug!(target: "sub-libp2p", "Starting random Kademlia request for {:?}", - random_peer_id); + debug!(target: "sub-libp2p", "Libp2p <= Starting random Kademlia request for \ + {:?}", random_peer_id); self.kademlia.find_node(random_peer_id); // Reset the `Delay` to the next random. @@ -391,7 +387,7 @@ where Duration::from_secs(60)); }, Err(err) => { - warn!(target: "sub-libp2p", "Kad query timer errored: {:?}", err); + warn!(target: "sub-libp2p", "Kademlia query timer errored: {:?}", err); break } } @@ -401,3 +397,26 @@ where } } +/// The severity of misbehaviour of a peer that is reported. +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Severity { + /// Peer is timing out. Could be bad connectivity of overload of work on either of our sides. + Timeout, + /// Peer has been notably useless. E.g. unable to answer a request that we might reasonably consider + /// it could answer. + Useless(String), + /// Peer has behaved in an invalid manner. This doesn't necessarily need to be Byzantine, but peer + /// must have taken concrete action in order to behave in such a way which is wantanly invalid. + Bad(String), +} + +impl fmt::Display for Severity { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self { + Severity::Timeout => write!(fmt, "Timeout"), + Severity::Useless(r) => write!(fmt, "Useless ({})", r), + Severity::Bad(r) => write!(fmt, "Bad ({})", r), + } + } +} + diff --git a/core/network-libp2p/src/config.rs b/core/network-libp2p/src/config.rs new file mode 100644 index 0000000000000000000000000000000000000000..61fae1a3987e66819b90140d332ebade54112910 --- /dev/null +++ b/core/network-libp2p/src/config.rs @@ -0,0 +1,286 @@ +// Copyright 2015-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 . + +//! Libp2p network configuration. + +use libp2p::identity::{Keypair, secp256k1, ed25519}; +use libp2p::{Multiaddr, multiaddr::Protocol}; +use std::error::Error; +use std::{io::{self, Write}, iter, fs, net::Ipv4Addr, path::{Path, PathBuf}}; + +/// Network service configuration. +#[derive(Clone)] +pub struct NetworkConfiguration { + /// Directory path to store general network configuration. None means nothing will be saved. + pub config_path: Option, + /// Directory path to store network-specific configuration. None means nothing will be saved. + pub net_config_path: Option, + /// Multiaddresses to listen for incoming connections. + pub listen_addresses: Vec, + /// Multiaddresses to advertise. Detected automatically if empty. + pub public_addresses: Vec, + /// List of initial node addresses + pub boot_nodes: Vec, + /// The node key configuration, which determines the node's network identity keypair. + pub node_key: NodeKeyConfig, + /// Maximum allowed number of incoming connections. + pub in_peers: u32, + /// Number of outgoing connections we're trying to maintain. + pub out_peers: u32, + /// List of reserved node addresses. + pub reserved_nodes: Vec, + /// The non-reserved peer mode. + pub non_reserved_mode: NonReservedPeerMode, + /// Client identifier. Sent over the wire for debugging purposes. + pub client_version: String, + /// Name of the node. Sent over the wire for debugging purposes. + pub node_name: String, +} + +impl Default for NetworkConfiguration { + fn default() -> Self { + NetworkConfiguration { + config_path: None, + net_config_path: None, + listen_addresses: Vec::new(), + public_addresses: Vec::new(), + boot_nodes: Vec::new(), + node_key: NodeKeyConfig::Secp256k1(Secret::New), + in_peers: 25, + out_peers: 75, + reserved_nodes: Vec::new(), + non_reserved_mode: NonReservedPeerMode::Accept, + client_version: "unknown".into(), + node_name: "unknown".into(), + } + } +} + +impl NetworkConfiguration { + /// Create a new instance of default settings. + pub fn new() -> Self { + Self::default() + } + + /// Create new default configuration for localhost-only connection with random port (useful for testing) + 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))) + .collect() + ]; + config + } +} + +/// The policy for connections to non-reserved peers. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum NonReservedPeerMode { + /// Accept them. This is the default. + Accept, + /// Deny them. + Deny, +} + +impl NonReservedPeerMode { + /// Attempt to parse the peer mode from a string. + pub fn parse(s: &str) -> Option { + match s { + "accept" => Some(NonReservedPeerMode::Accept), + "deny" => Some(NonReservedPeerMode::Deny), + _ => None, + } + } +} + +/// The configuration of a node's secret key, describing the type of key +/// and how it is obtained. A node's identity keypair is the result of +/// the evaluation of the node key configuration. +#[derive(Clone)] +pub enum NodeKeyConfig { + /// A Secp256k1 secret key configuration. + Secp256k1(Secret), + /// A Ed25519 secret key configuration. + Ed25519(Secret) +} + +/// The options for obtaining a Secp256k1 secret key. +pub type Secp256k1Secret = Secret; + +/// The options for obtaining a Ed25519 secret key. +pub type Ed25519Secret = Secret; + +/// The configuration options for obtaining a secret key `K`. +#[derive(Clone)] +pub enum Secret { + /// Use the given secret key `K`. + Input(K), + /// Read the secret key from a file. If the file does not exist, + /// it is created with a newly generated secret key `K`. The format + /// of the file is determined by `K`: + /// + /// * `secp256k1::SecretKey`: An unencoded 32 bytes Secp256k1 secret key. + /// * `ed25519::SecretKey`: An unencoded 32 bytes Ed25519 secret key. + File(PathBuf), + /// Always generate a new secret key `K`. + New +} + +impl NodeKeyConfig { + /// Evaluate a `NodeKeyConfig` to obtain an identity `Keypair`: + /// + /// * If the secret is configured as input, the corresponding keypair is returned. + /// + /// * If the secret is configured as a file, it is read from that file, if it exists. + /// Otherwise a new secret is generated and stored. In either case, the + /// keypair obtained from the secret is returned. + /// + /// * If the secret is configured to be new, it is generated and the corresponding + /// keypair is returned. + pub fn into_keypair(self) -> io::Result { + use NodeKeyConfig::*; + match self { + Secp256k1(Secret::New) => + Ok(Keypair::generate_secp256k1()), + + Secp256k1(Secret::Input(k)) => + Ok(Keypair::Secp256k1(k.into())), + + Secp256k1(Secret::File(f)) => + get_secret(f, + |mut b| secp256k1::SecretKey::from_bytes(&mut b), + secp256k1::SecretKey::generate) + .map(secp256k1::Keypair::from) + .map(Keypair::Secp256k1), + + Ed25519(Secret::New) => + Ok(Keypair::generate_ed25519()), + + Ed25519(Secret::Input(k)) => + Ok(Keypair::Ed25519(k.into())), + + Ed25519(Secret::File(f)) => + get_secret(f, + |mut b| ed25519::SecretKey::from_bytes(&mut b), + ed25519::SecretKey::generate) + .map(ed25519::Keypair::from) + .map(Keypair::Ed25519), + } + } +} + +/// Load a secret key from a file, if it exists, or generate a +/// new secret key and write it to that file. In either case, +/// the secret key is returned. +fn get_secret(file: P, parse: F, generate: G) -> io::Result +where + P: AsRef, + F: for<'r> FnOnce(&'r mut [u8]) -> Result, + G: FnOnce() -> K, + E: Error + Send + Sync + 'static, + K: AsRef<[u8]> +{ + std::fs::read(&file) + .and_then(|mut sk_bytes| + parse(&mut sk_bytes) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))) + .or_else(|e| { + if e.kind() == io::ErrorKind::NotFound { + file.as_ref().parent().map_or(Ok(()), fs::create_dir_all)?; + let sk = generate(); + write_secret_file(file, sk.as_ref())?; + Ok(sk) + } else { + Err(e) + } + }) +} + +/// Write secret bytes to a file. +fn write_secret_file

(path: P, sk_bytes: &[u8]) -> io::Result<()> +where + P: AsRef +{ + let mut file = open_secret_file(&path)?; + file.write_all(sk_bytes) +} + +/// Opens a file containing a secret key in write mode. +#[cfg(unix)] +fn open_secret_file

(path: P) -> io::Result +where + P: AsRef +{ + use std::os::unix::fs::OpenOptionsExt; + fs::OpenOptions::new() + .write(true) + .create_new(true) + .mode(0o600) + .open(path) +} + +/// Opens a file containing a secret key in write mode. +#[cfg(not(unix))] +fn open_secret_file

(path: P) -> Result +where + P: AsRef +{ + fs::OpenOptions::new() + .write(true) + .create_new(true) + .open(path) +} + +#[cfg(test)] +mod tests { + use super::*; + use tempdir::TempDir; + + fn secret_bytes(kp: &Keypair) -> Vec { + match kp { + Keypair::Ed25519(p) => p.secret().as_ref().iter().cloned().collect(), + Keypair::Secp256k1(p) => p.secret().as_ref().iter().cloned().collect(), + _ => panic!("Unexpected keypair.") + } + } + + #[test] + fn test_secret_file() { + let tmp = TempDir::new("x").unwrap(); + std::fs::remove_dir(tmp.path()).unwrap(); // should be recreated + let file = tmp.path().join("x").to_path_buf(); + let kp1 = NodeKeyConfig::Ed25519(Secret::File(file.clone())).into_keypair().unwrap(); + let kp2 = NodeKeyConfig::Ed25519(Secret::File(file.clone())).into_keypair().unwrap(); + assert!(file.is_file() && secret_bytes(&kp1) == secret_bytes(&kp2)) + } + + #[test] + fn test_secret_input() { + let sk = secp256k1::SecretKey::generate(); + let kp1 = NodeKeyConfig::Secp256k1(Secret::Input(sk.clone())).into_keypair().unwrap(); + let kp2 = NodeKeyConfig::Secp256k1(Secret::Input(sk)).into_keypair().unwrap(); + assert!(secret_bytes(&kp1) == secret_bytes(&kp2)); + } + + #[test] + fn test_secret_new() { + let kp1 = NodeKeyConfig::Ed25519(Secret::New).into_keypair().unwrap(); + let kp2 = NodeKeyConfig::Ed25519(Secret::New).into_keypair().unwrap(); + assert!(secret_bytes(&kp1) != secret_bytes(&kp2)); + } +} + diff --git a/core/network-libp2p/src/custom_proto/behaviour.rs b/core/network-libp2p/src/custom_proto/behaviour.rs index d946fe700e1b5b3b45ef1e7faf6dab5f0fbb2dce..eb60bb9ba4df9ae384959067f1335913ed3c4beb 100644 --- a/core/network-libp2p/src/custom_proto/behaviour.rs +++ b/core/network-libp2p/src/custom_proto/behaviour.rs @@ -14,81 +14,129 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use crate::custom_proto::handler::{CustomProtosHandler, CustomProtosHandlerOut, CustomProtosHandlerIn}; -use crate::custom_proto::topology::NetTopology; -use crate::custom_proto::upgrade::{CustomMessage, RegisteredProtocols}; -use crate::{NetworkConfiguration, NonReservedPeerMode, ProtocolId}; -use crate::parse_str_addr; -use fnv::{FnvHashMap, FnvHashSet}; +use crate::custom_proto::handler::{CustomProtoHandlerProto, CustomProtoHandlerOut, CustomProtoHandlerIn}; +use crate::custom_proto::upgrade::{CustomMessage, RegisteredProtocol}; +use fnv::FnvHashMap; use futures::prelude::*; use libp2p::core::swarm::{ConnectedPoint, NetworkBehaviour, NetworkBehaviourAction, PollParameters}; -use libp2p::core::{protocols_handler::ProtocolsHandler, Endpoint, Multiaddr, PeerId}; -use log::{debug, trace, warn}; +use libp2p::core::{Multiaddr, PeerId}; +use log::{debug, error, trace, warn}; use smallvec::SmallVec; -use std::{cmp, error, io, marker::PhantomData, path::Path, time::Duration, time::Instant}; +use std::{collections::hash_map::Entry, cmp, error, io, marker::PhantomData, mem, time::Duration, time::Instant}; use tokio_io::{AsyncRead, AsyncWrite}; -use tokio_timer::Delay; - -// File where the network topology is stored. -const NODES_FILE: &str = "nodes.json"; -// Duration during which a peer is disabled. -const PEER_DISABLE_DURATION: Duration = Duration::from_secs(5 * 60); /// Network behaviour that handles opening substreams for custom protocols with other nodes. -pub struct CustomProtos { +pub struct CustomProto { /// List of protocols to open with peers. Never modified. - registered_protocols: RegisteredProtocols, + protocol: RegisteredProtocol, - /// Topology of the network. - topology: NetTopology, + /// Receiver for instructions about who to connect to or disconnect from. + peerset: substrate_peerset::PeersetMut, - /// List of custom protocols that we have open with remotes. - open_protocols: Vec<(PeerId, ProtocolId)>, + /// List of peers in our state. + peers: FnvHashMap, - /// List of peer handlers that were enabled, and whether we're dialing or listening. - /// - /// Note that it is possible for a peer to be in the shutdown process, in which case it will - /// not be in this list but will be present in `open_protocols`. - /// It is also possible that we have *just* enabled a peer, in which case it will be in this - /// list but not in `open_protocols`. - enabled_peers: FnvHashMap, + /// List of incoming messages we have sent to the peer set manager and that are waiting for an + /// answer. + incoming: SmallVec<[IncomingPeer; 6]>, - /// Maximum number of incoming non-reserved connections, taken from the config. Never modified. - max_incoming_connections: usize, + /// We generate indices to identify incoming connections. This is the next value for the index + /// to use when a connection is incoming. + next_incoming_index: substrate_peerset::IncomingIndex, - /// Maximum number of outgoing non-reserved connections, taken from the config. Never modified. - max_outgoing_connections: usize, + /// Events to produce from `poll()`. + events: SmallVec<[NetworkBehaviourAction, CustomProtoOut>; 4]>, - /// If true, only reserved peers can connect. - reserved_only: bool, + /// Marker to pin the generics. + marker: PhantomData, +} - /// List of the IDs of the peers we are connected to. - connected_peers: FnvHashSet, +/// State of a peer we're connected to. +#[derive(Debug)] +enum PeerState { + /// State is poisoned. This is a temporary state for a peer and we should always switch back + /// to it later. If it is found in the wild, that means there was either a panic or a bug in + /// the state machine code. + Poisoned, + + /// The peer misbehaved. If the PSM wants us to connect to this node, we will add an artificial + /// delay to the connection. + Banned { + /// Until when the node is banned. + until: Instant, + }, - /// List of the IDs of the reserved peers. We always try to maintain a connection these peers. - reserved_peers: FnvHashSet, + /// The peerset requested that we connect to this peer. We are not connected to this node. + PendingRequest { + /// When to actually start dialing. + timer: tokio_timer::Delay, + }, - /// List of the IDs of peers that are forbidden, and the moment their ban expires. - banned_peers: Vec<(PeerId, Instant)>, + /// The peerset requested that we connect to this peer. We are currently dialing this peer. + Requested, + + /// We are connected to this peer but the peerset refused it. This peer can still perform + /// Kademlia queries and such, but should get disconnected in a few seconds. + Disabled { + /// How we are connected to this peer. + connected_point: ConnectedPoint, + /// If true, we still have a custom protocol open with it. It will likely get closed in + /// a short amount of time, but we need to keep the information in order to not have a + /// state mismatch. + open: bool, + /// If `Some`, the node is banned until the given `Instant`. + banned_until: Option, + }, - /// When this delay expires, we need to synchronize our active connectons with the - /// network topology. - next_connect_to_nodes: Delay, + /// We are connected to this peer but we are not opening any Substrate substream. The handler + /// will be enabled when `timer` fires. This peer can still perform Kademlia queries and such, + /// but should get disconnected in a few seconds. + DisabledPendingEnable { + /// How we are connected to this peer. + connected_point: ConnectedPoint, + /// If true, we still have a custom protocol open with it. It will likely get closed in + /// a short amount of time, but we need to keep the information in order to not have a + /// state mismatch. + open: bool, + /// When to enable this remote. + timer: tokio_timer::Delay, + }, - /// Events to produce from `poll()`. - events: SmallVec<[NetworkBehaviourAction, CustomProtosOut>; 4]>, + /// We are connected to this peer and the peerset has accepted it. The handler is in the + /// enabled state. + Enabled { + /// How we are connected to this peer. + connected_point: ConnectedPoint, + /// If true, we have a custom protocol open with this peer. + open: bool, + }, - /// Marker to pin the generics. - marker: PhantomData, + /// We are connected to this peer, and we sent an incoming message to the peerset. The handler + /// is in initialization mode. We are waiting for the Accept or Reject from the peerset. There + /// is a corresponding entry in `incoming`. + Incoming { + /// How we are connected to this peer. + connected_point: ConnectedPoint, + }, } -/// Event that can be emitted by the `CustomProtos`. +/// State of an "incoming" message sent to the peer set manager. #[derive(Debug)] -pub enum CustomProtosOut { +struct IncomingPeer { + /// Id of the node that is concerned. + peer_id: PeerId, + /// If true, this "incoming" still corresponds to an actual connection. If false, then the + /// connection corresponding to it has been closed or replaced already. + alive: bool, + /// Id that the we sent to the peerset. + incoming_id: substrate_peerset::IncomingIndex, +} + +/// Event that can be emitted by the `CustomProto`. +#[derive(Debug)] +pub enum CustomProtoOut { /// Opened a custom protocol with the remote. CustomProtocolOpen { - /// Identifier of the protocol. - protocol_id: ProtocolId, /// Version of the protocol that has been opened. version: u8, /// Id of the node we have opened a connection with. @@ -101,8 +149,6 @@ pub enum CustomProtosOut { CustomProtocolClosed { /// Id of the peer we were connected to. peer_id: PeerId, - /// Identifier of the protocol. - protocol_id: ProtocolId, /// Reason why the substream closed. If `Ok`, then it's a graceful exit (EOF). result: io::Result<()>, }, @@ -111,8 +157,6 @@ pub enum CustomProtosOut { CustomMessage { /// Id of the peer the message came from. peer_id: PeerId, - /// Protocol which generated the message. - protocol_id: ProtocolId, /// Message that has been received. message: TMessage, }, @@ -122,501 +166,747 @@ pub enum CustomProtosOut { Clogged { /// Id of the peer which is clogged. peer_id: PeerId, - /// Protocol which has a problem. - protocol_id: ProtocolId, /// Copy of the messages that are within the buffer, for further diagnostic. messages: Vec, }, } -impl CustomProtos { +impl CustomProto { /// Creates a `CustomProtos`. - pub fn new(config: &NetworkConfiguration, local_peer_id: &PeerId, registered_protocols: RegisteredProtocols) -> Self { - // Initialize the topology of the network. - let mut topology = if let Some(ref path) = config.net_config_path { - let path = Path::new(path).join(NODES_FILE); - debug!(target: "sub-libp2p", "Initializing peer store for JSON file {:?}", path); - NetTopology::from_file(local_peer_id.clone(), path) - } else { - debug!(target: "sub-libp2p", "No peers file configured ; peers won't be saved"); - NetTopology::memory(local_peer_id.clone()) - }; - - // Add the bootstrap nodes to the topology. - for bootnode in config.boot_nodes.iter() { - if let Ok((peer_id, addr)) = parse_str_addr(bootnode) { - topology.add_bootstrap_addr(&peer_id, addr.clone()); - } - } - - let max_incoming_connections = config.in_peers as usize; - let max_outgoing_connections = config.out_peers as usize; - - // Expected maximum number of connections. - let connec_cap = max_incoming_connections - .saturating_add(max_outgoing_connections) - .saturating_add(4); // We add an arbitrary number for reserved peers slots - - // Expected maximum number of substreams. - let open_protos_cap = connec_cap.saturating_mul(registered_protocols.len()); - - CustomProtos { - registered_protocols, - topology, - max_incoming_connections, - max_outgoing_connections, - reserved_only: config.non_reserved_mode == NonReservedPeerMode::Deny, - connected_peers: Default::default(), - reserved_peers: Default::default(), - banned_peers: Vec::new(), - open_protocols: Vec::with_capacity(open_protos_cap), - enabled_peers: FnvHashMap::with_capacity_and_hasher(connec_cap, Default::default()), - next_connect_to_nodes: Delay::new(Instant::now()), + pub fn new( + protocol: RegisteredProtocol, + peerset: substrate_peerset::PeersetMut, + ) -> Self { + CustomProto { + protocol, + peerset, + peers: FnvHashMap::default(), + incoming: SmallVec::new(), + next_incoming_index: substrate_peerset::IncomingIndex(0), events: SmallVec::new(), marker: PhantomData, } } - /// Adds a reserved peer. - pub fn add_reserved_peer(&mut self, peer_id: PeerId, addr: Multiaddr) { - self.topology.add_bootstrap_addr(&peer_id, addr); - self.reserved_peers.insert(peer_id); - - // Trigger a `connect_to_nodes` round. - self.next_connect_to_nodes = Delay::new(Instant::now()); - } - - /// Removes a reserved peer. - /// - /// If we are in reserved mode and we were connected to a node with this peer ID, then this - /// method will disconnect it and return its index. - pub fn remove_reserved_peer(&mut self, peer_id: PeerId) { - self.reserved_peers.remove(&peer_id); + /// Disconnects the given peer if we are connected to it. + pub fn disconnect_peer(&mut self, peer_id: &PeerId) { + debug!(target: "sub-libp2p", "Disconnecting {:?} by request from the external API", peer_id); + self.disconnect_peer_inner(peer_id, None); } - /// Start accepting all peers again if we weren't. - pub fn accept_unreserved_peers(&mut self) { - if !self.reserved_only { + /// Inner implementation of `disconnect_peer`. If `ban` is `Some`, we ban the node for the + /// specific duration. + fn disconnect_peer_inner(&mut self, peer_id: &PeerId, ban: Option) { + let mut entry = if let Entry::Occupied(entry) = self.peers.entry(peer_id.clone()) { + entry + } else { return - } + }; - self.reserved_only = false; - // Trigger a `connect_to_nodes` round. - self.next_connect_to_nodes = Delay::new(Instant::now()); - } + match mem::replace(entry.get_mut(), PeerState::Poisoned) { + // We're not connected anyway. + st @ PeerState::Disabled { .. } => *entry.into_mut() = st, + st @ PeerState::Requested => *entry.into_mut() = st, + st @ PeerState::PendingRequest { .. } => *entry.into_mut() = st, + st @ PeerState::Banned { .. } => *entry.into_mut() = st, + + // DisabledPendingEnable => Disabled. + PeerState::DisabledPendingEnable { open, connected_point, timer } => { + debug!(target: "sub-libp2p", "PSM <= Dropped({:?})", peer_id); + self.peerset.dropped(peer_id); + let banned_until = Some(if let Some(ban) = ban { + cmp::max(timer.deadline(), Instant::now() + ban) + } else { + timer.deadline() + }); + *entry.into_mut() = PeerState::Disabled { open, connected_point, banned_until } + }, + + // Enabled => Disabled. + PeerState::Enabled { open, connected_point } => { + debug!(target: "sub-libp2p", "PSM <= Dropped({:?})", peer_id); + self.peerset.dropped(peer_id); + debug!(target: "sub-libp2p", "Handler({:?}) <= Disable", peer_id); + self.events.push(NetworkBehaviourAction::SendEvent { + peer_id: peer_id.clone(), + event: CustomProtoHandlerIn::Disable, + }); + let banned_until = ban.map(|dur| Instant::now() + dur); + *entry.into_mut() = PeerState::Disabled { open, connected_point, banned_until } + }, + + // Incoming => Disabled. + PeerState::Incoming { connected_point, .. } => { + let inc = if let Some(inc) = self.incoming.iter_mut() + .find(|i| i.peer_id == *entry.key() && i.alive) { + inc + } else { + error!(target: "sub-libp2p", "State mismatch in libp2p: no entry in \ + incoming for incoming peer"); + return + }; - /// Start refusing non-reserved nodes. - pub fn deny_unreserved_peers(&mut self) { - if self.reserved_only { - return + inc.alive = false; + debug!(target: "sub-libp2p", "Handler({:?}) <= Disable", peer_id); + self.events.push(NetworkBehaviourAction::SendEvent { + peer_id: peer_id.clone(), + event: CustomProtoHandlerIn::Disable, + }); + let banned_until = ban.map(|dur| Instant::now() + dur); + *entry.into_mut() = PeerState::Disabled { open: false, connected_point, banned_until } + }, + + PeerState::Poisoned => + error!(target: "sub-libp2p", "State of {:?} is poisoned", peer_id), } - - self.reserved_only = true; - - // Disconnecting nodes that are connected to us and that aren't reserved - let reserved_peers = &mut self.reserved_peers; - let events = &mut self.events; - self.enabled_peers.retain(move |peer_id, _| { - if reserved_peers.contains(peer_id) { - return true - } - events.push(NetworkBehaviourAction::SendEvent { - peer_id: peer_id.clone(), - event: CustomProtosHandlerIn::Disable, - }); - false - }) } - /// Disconnects the given peer if we are connected to it. - pub fn disconnect_peer(&mut self, peer: &PeerId) { - if self.enabled_peers.remove(peer).is_some() { - self.events.push(NetworkBehaviourAction::SendEvent { - peer_id: peer.clone(), - event: CustomProtosHandlerIn::Disable, - }); + /// Returns true if we try to open protocols with the given peer. + pub fn is_enabled(&self, peer_id: &PeerId) -> bool { + match self.peers.get(peer_id) { + None => false, + Some(PeerState::Disabled { .. }) => false, + Some(PeerState::DisabledPendingEnable { .. }) => false, + Some(PeerState::Enabled { .. }) => true, + Some(PeerState::Incoming { .. }) => false, + Some(PeerState::Requested) => false, + Some(PeerState::PendingRequest { .. }) => false, + Some(PeerState::Banned { .. }) => false, + Some(PeerState::Poisoned) => false, } } - /// Disconnects the given peer if we are connected to it and disables it for a little while. - pub fn ban_peer(&mut self, peer_id: PeerId) { - // Peer is already banned - if let Some(pos) = self.banned_peers.iter().position(|(p, _)| p == &peer_id) { - if self.banned_peers[pos].1 > Instant::now() { - return - } else { - self.banned_peers.remove(pos); - } - } - - self.banned_peers.push((peer_id.clone(), Instant::now() + PEER_DISABLE_DURATION)); - if self.enabled_peers.remove(&peer_id).is_some() { - self.events.push(NetworkBehaviourAction::SendEvent { - peer_id, - event: CustomProtosHandlerIn::Disable, - }); + /// Returns true if we have opened a protocol with the given peer. + pub fn is_open(&self, peer_id: &PeerId) -> bool { + match self.peers.get(peer_id) { + None => false, + Some(PeerState::Disabled { open, .. }) => *open, + Some(PeerState::DisabledPendingEnable { open, .. }) => *open, + Some(PeerState::Enabled { open, .. }) => *open, + Some(PeerState::Incoming { .. }) => false, + Some(PeerState::Requested) => false, + Some(PeerState::PendingRequest { .. }) => false, + Some(PeerState::Banned { .. }) => false, + Some(PeerState::Poisoned) => false, } } - /// Sends a message to a peer using the given custom protocol. + /// Sends a message to a peer. /// /// Has no effect if the custom protocol is not open with the given peer. /// /// Also note that even we have a valid open substream, it may in fact be already closed /// without us knowing, in which case the packet will not be received. - pub fn send_packet(&mut self, target: &PeerId, protocol_id: ProtocolId, message: TMessage) { + pub fn send_packet(&mut self, target: &PeerId, message: TMessage) { + if !self.is_open(target) { + return; + } + + trace!(target: "sub-libp2p", "Handler({:?}) <= Packet", target); self.events.push(NetworkBehaviourAction::SendEvent { peer_id: target.clone(), - event: CustomProtosHandlerIn::SendCustomMessage { - protocol: protocol_id, + event: CustomProtoHandlerIn::SendCustomMessage { message, } }); } - /// Indicates to the topology that we have discovered new addresses for a given node. - pub fn add_discovered_addrs( - &mut self, - peer_id: &PeerId, - addrs: I, - ) where I: Iterator { - if self.topology.add_discovered_addrs(peer_id, addrs) { - // Trigger a `connect_to_nodes` round. - self.next_connect_to_nodes = Delay::new(Instant::now()); - } + /// Indicates to the peerset that we have discovered new addresses for a given node. + pub fn add_discovered_node(&mut self, peer_id: &PeerId) { + debug!(target: "sub-libp2p", "PSM <= Discovered({:?})", peer_id); + self.peerset.discovered(peer_id.clone()) } - /// Returns the number of peers in the topology. - pub fn num_topology_peers(&self) -> usize { - self.topology.num_peers() + /// Returns the state of the peerset manager, for debugging purposes. + pub fn peerset_debug_info(&self) -> serde_json::Value { + self.peerset.debug_info() } - /// Flushes the topology to the disk. - pub fn flush_topology(&mut self) -> Result<(), io::Error> { - self.topology.flush_to_disk() - } + /// Function that is called when the peerset wants us to connect to a node. + fn peerset_report_connect(&mut self, peer_id: PeerId) { + let mut occ_entry = match self.peers.entry(peer_id) { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => { + // If there's no entry in `self.peers`, start dialing. + debug!(target: "sub-libp2p", "PSM => Connect({:?}): Starting to connect", entry.key()); + debug!(target: "sub-libp2p", "Libp2p <= Dial {:?}", entry.key()); + self.events.push(NetworkBehaviourAction::DialPeer { peer_id: entry.key().clone() }); + entry.insert(PeerState::Requested); + return; + } + }; - /// Perform a cleanup pass, removing all obsolete addresses and peers. - /// - /// This should be done from time to time. - pub fn cleanup(&mut self) { - self.topology.cleanup(); + match mem::replace(occ_entry.get_mut(), PeerState::Poisoned) { + PeerState::Banned { ref until } if *until > Instant::now() => { + debug!(target: "sub-libp2p", "PSM => Connect({:?}): Will start to connect at \ + until {:?}", occ_entry.key(), until); + *occ_entry.into_mut() = PeerState::PendingRequest { + timer: tokio_timer::Delay::new(until.clone()), + }; + }, + + PeerState::Banned { .. } => { + debug!(target: "sub-libp2p", "PSM => Connect({:?}): Starting to connect", occ_entry.key()); + debug!(target: "sub-libp2p", "Libp2p <= Dial {:?}", occ_entry.key()); + self.events.push(NetworkBehaviourAction::DialPeer { peer_id: occ_entry.key().clone() }); + *occ_entry.into_mut() = PeerState::Requested; + }, + + PeerState::Disabled { open, ref connected_point, banned_until: Some(ref banned) } + if *banned > Instant::now() => { + debug!(target: "sub-libp2p", "PSM => Connect({:?}): Has idle connection through \ + {:?} but node is banned until {:?}", occ_entry.key(), connected_point, banned); + *occ_entry.into_mut() = PeerState::DisabledPendingEnable { + connected_point: connected_point.clone(), + open, + timer: tokio_timer::Delay::new(banned.clone()), + }; + }, + + PeerState::Disabled { open, connected_point, banned_until: _ } => { + debug!(target: "sub-libp2p", "PSM => Connect({:?}): Enabling previously-idle \ + connection through {:?}", occ_entry.key(), connected_point); + debug!(target: "sub-libp2p", "Handler({:?}) <= Enable", occ_entry.key()); + self.events.push(NetworkBehaviourAction::SendEvent { + peer_id: occ_entry.key().clone(), + event: CustomProtoHandlerIn::Enable(connected_point.clone().into()), + }); + *occ_entry.into_mut() = PeerState::Enabled { connected_point, open }; + }, + + PeerState::Incoming { connected_point, .. } => { + debug!(target: "sub-libp2p", "PSM => Connect({:?}): Enabling incoming \ + connection through {:?}", occ_entry.key(), connected_point); + if let Some(inc) = self.incoming.iter_mut() + .find(|i| i.peer_id == *occ_entry.key() && i.alive) { + inc.alive = false; + } else { + error!(target: "sub-libp2p", "State mismatch in libp2p: no entry in \ + incoming for incoming peer") + } + debug!(target: "sub-libp2p", "Handler({:?}) <= Enable", occ_entry.key()); + self.events.push(NetworkBehaviourAction::SendEvent { + peer_id: occ_entry.key().clone(), + event: CustomProtoHandlerIn::Enable(connected_point.clone().into()), + }); + *occ_entry.into_mut() = PeerState::Enabled { connected_point, open: false }; + }, + + st @ PeerState::Enabled { .. } => { + warn!(target: "sub-libp2p", "PSM => Connect({:?}): Already connected to this \ + peer", occ_entry.key()); + *occ_entry.into_mut() = st; + }, + st @ PeerState::DisabledPendingEnable { .. } => { + warn!(target: "sub-libp2p", "PSM => Connect({:?}): Already have an idle \ + connection to this peer and waiting to enable it", occ_entry.key()); + *occ_entry.into_mut() = st; + }, + st @ PeerState::Requested { .. } | st @ PeerState::PendingRequest { .. } => { + warn!(target: "sub-libp2p", "PSM => Connect({:?}): Received a previous \ + request for that peer", occ_entry.key()); + *occ_entry.into_mut() = st; + }, + + PeerState::Poisoned => + error!(target: "sub-libp2p", "State of {:?} is poisoned", occ_entry.key()), + } } - /// Updates the attempted connections to nodes. - /// - /// Also updates `next_connect_to_nodes` with the earliest known moment when we need to - /// update connections again. - fn connect_to_nodes(&mut self, params: &mut PollParameters) { - // Make sure we are connected or connecting to all the reserved nodes. - for reserved in self.reserved_peers.iter() { - // TODO: don't generate an event if we're already in a pending connection (https://github.com/libp2p/rust-libp2p/issues/697) - if !self.enabled_peers.contains_key(&reserved) { - self.events.push(NetworkBehaviourAction::DialPeer { peer_id: reserved.clone() }); + /// Function that is called when the peerset wants us to disconnect from a node. + fn peerset_report_disconnect(&mut self, peer_id: PeerId) { + let mut entry = match self.peers.entry(peer_id) { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => { + debug!(target: "sub-libp2p", "PSM => Drop({:?}): Node already disabled", entry.key()); + return } + }; + + match mem::replace(entry.get_mut(), PeerState::Poisoned) { + st @ PeerState::Disabled { .. } | st @ PeerState::Banned { .. } => { + debug!(target: "sub-libp2p", "PSM => Drop({:?}): Node already disabled", entry.key()); + *entry.into_mut() = st; + }, + + PeerState::DisabledPendingEnable { open, connected_point, timer } => { + debug!(target: "sub-libp2p", "PSM => Drop({:?}): Interrupting pending \ + enable", entry.key()); + *entry.into_mut() = PeerState::Disabled { + open, + connected_point, + banned_until: Some(timer.deadline()), + }; + }, + + PeerState::Enabled { open, connected_point } => { + debug!(target: "sub-libp2p", "PSM => Drop({:?}): Disabling connection", entry.key()); + debug!(target: "sub-libp2p", "Handler({:?}) <= Disable", entry.key()); + self.events.push(NetworkBehaviourAction::SendEvent { + peer_id: entry.key().clone(), + event: CustomProtoHandlerIn::Disable, + }); + *entry.into_mut() = PeerState::Disabled { open, connected_point, banned_until: None } + }, + st @ PeerState::Incoming { .. } => { + error!(target: "sub-libp2p", "PSM => Drop({:?}): Was in incoming mode", + entry.key()); + *entry.into_mut() = st; + }, + PeerState::Requested => { + // We don't cancel dialing. Libp2p doesn't expose that on purpose, as other + // sub-systems (such as the discovery mechanism) may require dialing this node as + // well at the same time. + debug!(target: "sub-libp2p", "PSM => Drop({:?}): Was not yet connected", entry.key()); + entry.remove(); + }, + PeerState::PendingRequest { timer } => { + debug!(target: "sub-libp2p", "PSM => Drop({:?}): Was not yet connected", entry.key()); + *entry.into_mut() = PeerState::Banned { until: timer.deadline() } + }, + + PeerState::Poisoned => + error!(target: "sub-libp2p", "State of {:?} is poisoned", entry.key()), } + } - // We're done with reserved node; return early if there's nothing more to do. - if self.reserved_only { - // We set a timeout to 60 seconds for trying to connect again, however in practice - // a round will happen as soon as we fail to dial, disconnect from a node, allow - // unreserved nodes, and so on. - self.next_connect_to_nodes.reset(Instant::now() + Duration::from_secs(60)); + /// Function that is called when the peerset wants us to accept an incoming node. + fn peerset_report_accept(&mut self, index: substrate_peerset::IncomingIndex) { + let incoming = if let Some(pos) = self.incoming.iter().position(|i| i.incoming_id == index) { + self.incoming.remove(pos) + } else { + error!(target: "sub-libp2p", "PSM => Accept({:?}): Invalid index", index); + return + }; + + if !incoming.alive { + debug!(target: "sub-libp2p", "PSM => Accept({:?}, {:?}): Obsolete incoming, + sending back dropped", index, incoming.peer_id); + debug!(target: "sub-libp2p", "PSM <= Dropped({:?})", incoming.peer_id); + self.peerset.dropped(&incoming.peer_id); return } - // Counter of number of connections to open, decreased when we open one. - let mut num_to_open = { - let num_outgoing_connections = self.enabled_peers - .iter() - .filter(|(_, endpoint)| endpoint.is_dialer()) - .filter(|(p, _)| !self.reserved_peers.contains(p)) - .count(); - self.max_outgoing_connections - num_outgoing_connections + let state = if let Some(state) = self.peers.get_mut(&incoming.peer_id) { + state + } else { + error!(target: "sub-libp2p", "State mismatch in libp2p: no entry in peers \ + corresponding to an alive incoming"); + return }; - trace!(target: "sub-libp2p", "Connect-to-nodes round; attempting to fill {:?} slots", - num_to_open); - - let local_peer_id = params.local_peer_id().clone(); - let (to_try, will_change) = self.topology.addrs_to_attempt(); - for (peer_id, _) in to_try { - if num_to_open == 0 { - break - } + let connected_point = if let PeerState::Incoming { connected_point } = state { + connected_point.clone() + } else { + error!(target: "sub-libp2p", "State mismatch in libp2p: entry in peers corresponding \ + to an alive incoming is not in incoming state"); + return + }; - if peer_id == &local_peer_id { - continue - } + debug!(target: "sub-libp2p", "PSM => Accept({:?}, {:?}): Enabling connection \ + through {:?}", index, incoming.peer_id, connected_point); + debug!(target: "sub-libp2p", "Handler({:?}) <= Enable", incoming.peer_id); + self.events.push(NetworkBehaviourAction::SendEvent { + peer_id: incoming.peer_id, + event: CustomProtoHandlerIn::Enable(connected_point.clone().into()), + }); - if self.connected_peers.contains(&peer_id) { - continue - } + *state = PeerState::Enabled { open: false, connected_point }; + } - if let Some((_, ban_end)) = self.banned_peers.iter().find(|(p, _)| p == peer_id) { - if *ban_end > Instant::now() { - continue - } - } + /// Function that is called when the peerset wants us to reject an incoming node. + fn peerset_report_reject(&mut self, index: substrate_peerset::IncomingIndex) { + let incoming = if let Some(pos) = self.incoming.iter().position(|i| i.incoming_id == index) { + self.incoming.remove(pos) + } else { + error!(target: "sub-libp2p", "PSM => Reject({:?}): Invalid index", index); + return + }; - num_to_open -= 1; - self.events.push(NetworkBehaviourAction::DialPeer { peer_id: peer_id.clone() }); + if !incoming.alive { + error!(target: "sub-libp2p", "PSM => Reject({:?}, {:?}): Obsolete incoming, \ + ignoring", index, incoming.peer_id); + return } - // Next round is when we expect the topology will change. - self.next_connect_to_nodes.reset(cmp::min(will_change, Instant::now() + Duration::from_secs(60))); + let state = if let Some(state) = self.peers.get_mut(&incoming.peer_id) { + state + } else { + error!(target: "sub-libp2p", "State mismatch in libp2p: no entry in peers \ + corresponding to an alive incoming"); + return + }; + + let connected_point = if let PeerState::Incoming { connected_point } = state { + connected_point.clone() + } else { + error!(target: "sub-libp2p", "State mismatch in libp2p: entry in peers corresponding \ + to an alive incoming is not in incoming state"); + return + }; + + debug!(target: "sub-libp2p", "PSM => Reject({:?}, {:?}): Rejecting connection through \ + {:?}", index, incoming.peer_id, connected_point); + debug!(target: "sub-libp2p", "Handler({:?}) <= Disable", incoming.peer_id); + self.events.push(NetworkBehaviourAction::SendEvent { + peer_id: incoming.peer_id, + event: CustomProtoHandlerIn::Disable, + }); + *state = PeerState::Disabled { open: false, connected_point, banned_until: None }; } } -impl NetworkBehaviour for CustomProtos +impl NetworkBehaviour for CustomProto where TSubstream: AsyncRead + AsyncWrite, TMessage: CustomMessage, { - type ProtocolsHandler = CustomProtosHandler; - type OutEvent = CustomProtosOut; + type ProtocolsHandler = CustomProtoHandlerProto; + type OutEvent = CustomProtoOut; fn new_handler(&mut self) -> Self::ProtocolsHandler { - CustomProtosHandler::new(self.registered_protocols.clone()) + CustomProtoHandlerProto::new(self.protocol.clone()) } - fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec { - self.topology.addresses_of_peer(peer_id) + fn addresses_of_peer(&mut self, _: &PeerId) -> Vec { + Vec::new() } - fn inject_connected(&mut self, peer_id: PeerId, endpoint: ConnectedPoint) { - // When a peer connects, its handler is initially in the disabled state. We make sure that - // the peer is allowed, and if so we put it in the enabled state. - - self.connected_peers.insert(peer_id.clone()); + fn inject_connected(&mut self, peer_id: PeerId, connected_point: ConnectedPoint) { + match (self.peers.entry(peer_id), connected_point) { + (Entry::Occupied(mut entry), connected_point) => { + match mem::replace(entry.get_mut(), PeerState::Poisoned) { + PeerState::Requested | PeerState::PendingRequest { .. } | + PeerState::Banned { .. } => { + debug!(target: "sub-libp2p", "Libp2p => Connected({:?}): Connection \ + requested by PSM (through {:?})", entry.key(), connected_point); + debug!(target: "sub-libp2p", "Handler({:?}) <= Enable", entry.key()); + self.events.push(NetworkBehaviourAction::SendEvent { + peer_id: entry.key().clone(), + event: CustomProtoHandlerIn::Enable(connected_point.clone().into()), + }); + *entry.into_mut() = PeerState::Enabled { open: false, connected_point }; + } + st @ _ => { + // This is a serious bug either in this state machine or in libp2p. + error!(target: "sub-libp2p", "Received inject_connected for \ + already-connected node; state is {:?}", st); + *entry.into_mut() = st; + return + } + } + } - let is_reserved = self.reserved_peers.contains(&peer_id); - if self.reserved_only && !is_reserved { - debug!(target: "sub-libp2p", "Ignoring {:?} because we're in reserved mode", peer_id); - self.events.push(NetworkBehaviourAction::SendEvent { - peer_id: peer_id.clone(), - event: CustomProtosHandlerIn::Disable, - }); - return - } + (Entry::Vacant(entry), connected_point @ ConnectedPoint::Listener { .. }) => { + let incoming_id = self.next_incoming_index.clone(); + self.next_incoming_index.0 = match self.next_incoming_index.0.checked_add(1) { + Some(v) => v, + None => { + error!(target: "sub-libp2p", "Overflow in next_incoming_index"); + return + } + }; + debug!(target: "sub-libp2p", "Libp2p => Connected({:?}): Incoming connection", + entry.key()); + debug!(target: "sub-libp2p", "PSM <= Incoming({:?}, {:?}): Through {:?}", + incoming_id, entry.key(), connected_point); + self.peerset.incoming(entry.key().clone(), incoming_id); + self.incoming.push(IncomingPeer { + peer_id: entry.key().clone(), + alive: true, + incoming_id, + }); + entry.insert(PeerState::Incoming { connected_point }); + } - // Check whether peer is banned. - if !is_reserved { - if let Some((_, expire)) = self.banned_peers.iter().find(|(p, _)| p == &peer_id) { - if *expire >= Instant::now() { - debug!(target: "sub-libp2p", "Ignoring banned peer {:?}", peer_id); - self.events.push(NetworkBehaviourAction::SendEvent { - peer_id: peer_id.clone(), - event: CustomProtosHandlerIn::Disable, - }); - return - } + (Entry::Vacant(entry), connected_point) => { + debug!(target: "sub-libp2p", "Libp2p => Connected({:?}): Requested by something \ + else than PSM, disabling", entry.key()); + debug!(target: "sub-libp2p", "Handler({:?}) <= Disable", entry.key()); + self.events.push(NetworkBehaviourAction::SendEvent { + peer_id: entry.key().clone(), + event: CustomProtoHandlerIn::Disable, + }); + entry.insert(PeerState::Disabled { open: false, connected_point, banned_until: None }); } } + } - // Check the limits on the ingoing and outgoing connections. - match endpoint { - ConnectedPoint::Dialer { .. } => { - let num_outgoing = self.enabled_peers.iter() - .filter(|(_, e)| e.is_dialer()) - .filter(|(p, _)| !self.reserved_peers.contains(p)) - .count(); - - debug_assert!(num_outgoing <= self.max_outgoing_connections); - if num_outgoing == self.max_outgoing_connections { - self.events.push(NetworkBehaviourAction::SendEvent { - peer_id: peer_id.clone(), - event: CustomProtosHandlerIn::Disable, - }); - return + fn inject_disconnected(&mut self, peer_id: &PeerId, endpoint: ConnectedPoint) { + match self.peers.remove(peer_id) { + None | Some(PeerState::Requested) | Some(PeerState::PendingRequest { .. }) | + Some(PeerState::Banned { .. }) => + // This is a serious bug either in this state machine or in libp2p. + error!(target: "sub-libp2p", "Received inject_disconnected for non-connected \ + node {:?}", peer_id), + + Some(PeerState::Disabled { open, banned_until, .. }) => { + debug!(target: "sub-libp2p", "Libp2p => Disconnected({:?}): Was disabled \ + (through {:?})", peer_id, endpoint); + if let Some(until) = banned_until { + self.peers.insert(peer_id.clone(), PeerState::Banned { until }); } - } - ConnectedPoint::Listener { .. } => { - let num_ingoing = self.enabled_peers.iter() - .filter(|(_, e)| e.is_listener()) - .filter(|(p, _)| !self.reserved_peers.contains(p)) - .count(); - - debug_assert!(num_ingoing <= self.max_incoming_connections); - if num_ingoing == self.max_incoming_connections { - debug!(target: "sub-libp2p", "Ignoring incoming connection from {:?} because \ - we're full", peer_id); - self.events.push(NetworkBehaviourAction::SendEvent { + if open { + debug!(target: "sub-libp2p", "External API <= Closed({:?})", peer_id); + let event = CustomProtoOut::CustomProtocolClosed { peer_id: peer_id.clone(), - event: CustomProtosHandlerIn::Disable, - }); - return + result: Ok(()), + }; + + self.events.push(NetworkBehaviourAction::GenerateEvent(event)); } } - } - // If everything is fine, enable the node. - debug_assert!(!self.enabled_peers.contains_key(&peer_id)); - // We ask the handler to actively open substreams only if we are the dialer; otherwise - // the two nodes will race to be the first to open the unique allowed substream. - if endpoint.is_dialer() { - trace!(target: "sub-libp2p", "Enabling custom protocols with {:?} (active)", peer_id); - self.events.push(NetworkBehaviourAction::SendEvent { - peer_id: peer_id.clone(), - event: CustomProtosHandlerIn::Enable(Endpoint::Dialer), - }); - } else { - trace!(target: "sub-libp2p", "Enabling custom protocols with {:?} (passive)", peer_id); - self.events.push(NetworkBehaviourAction::SendEvent { - peer_id: peer_id.clone(), - event: CustomProtosHandlerIn::Enable(Endpoint::Listener), - }); - } + Some(PeerState::DisabledPendingEnable { open, timer, .. }) => { + debug!(target: "sub-libp2p", "Libp2p => Disconnected({:?}): Was disabled \ + (through {:?}) but pending enable", peer_id, endpoint); + debug!(target: "sub-libp2p", "PSM <= Dropped({:?})", peer_id); + self.peerset.dropped(peer_id); + self.peers.insert(peer_id.clone(), PeerState::Banned { until: timer.deadline() }); + if open { + debug!(target: "sub-libp2p", "External API <= Closed({:?})", peer_id); + let event = CustomProtoOut::CustomProtocolClosed { + peer_id: peer_id.clone(), + result: Ok(()), + }; - self.topology.set_connected(&peer_id, &endpoint); - self.enabled_peers.insert(peer_id, endpoint); - } + self.events.push(NetworkBehaviourAction::GenerateEvent(event)); + } + } - fn inject_disconnected(&mut self, peer_id: &PeerId, endpoint: ConnectedPoint) { - let was_connected = self.connected_peers.remove(&peer_id); - debug_assert!(was_connected); + Some(PeerState::Enabled { open, .. }) => { + debug!(target: "sub-libp2p", "Libp2p => Disconnected({:?}): Was enabled \ + (through {:?})", peer_id, endpoint); + debug!(target: "sub-libp2p", "PSM <= Dropped({:?})", peer_id); + self.peerset.dropped(peer_id); - self.topology.set_disconnected(peer_id, &endpoint); + if open { + debug!(target: "sub-libp2p", "External API <= Closed({:?})", peer_id); + let event = CustomProtoOut::CustomProtocolClosed { + peer_id: peer_id.clone(), + result: Ok(()), + }; - while let Some(pos) = self.open_protocols.iter().position(|(p, _)| p == peer_id) { - let (_, protocol_id) = self.open_protocols.remove(pos); + self.events.push(NetworkBehaviourAction::GenerateEvent(event)); + } + } - let event = CustomProtosOut::CustomProtocolClosed { - protocol_id, - peer_id: peer_id.clone(), - result: Ok(()), - }; + // In the incoming state, we don't report "Dropped". Instead we will just ignore the + // corresponding Accept/Reject. + Some(PeerState::Incoming { .. }) => { + if let Some(state) = self.incoming.iter_mut().find(|i| i.peer_id == *peer_id) { + debug!(target: "sub-libp2p", "Libp2p => Disconnected({:?}): Was in incoming \ + mode (id {:?}, through {:?})", peer_id, state.incoming_id, endpoint); + state.alive = false; + } else { + error!(target: "sub-libp2p", "State mismatch in libp2p: no entry in incoming \ + corresponding to an incoming state in peers") + } + } - self.events.push(NetworkBehaviourAction::GenerateEvent(event)); + Some(PeerState::Poisoned) => + error!(target: "sub-libp2p", "State of {:?} is poisoned", peer_id), } - - // Trigger a `connect_to_nodes` round. - self.next_connect_to_nodes = Delay::new(Instant::now()); - - self.enabled_peers.remove(peer_id); } - fn inject_dial_failure(&mut self, peer_id: Option<&PeerId>, addr: &Multiaddr, error: &dyn error::Error) { - if let Some(peer_id) = peer_id.as_ref() { - debug!(target: "sub-libp2p", "Failed to reach peer {:?} through {} => {:?}", peer_id, addr, error); - self.topology.set_unreachable(addr); + fn inject_addr_reach_failure(&mut self, peer_id: Option<&PeerId>, addr: &Multiaddr, error: &dyn error::Error) { + trace!(target: "sub-libp2p", "Libp2p => Reach failure for {:?} through {:?}: {:?}", peer_id, addr, error); + } - // Trigger a `connect_to_nodes` round. - self.next_connect_to_nodes = Delay::new(Instant::now()); + fn inject_dial_failure(&mut self, peer_id: &PeerId) { + if let Entry::Occupied(mut entry) = self.peers.entry(peer_id.clone()) { + match mem::replace(entry.get_mut(), PeerState::Poisoned) { + // The node is not in our list. + st @ PeerState::Banned { .. } => { + trace!(target: "sub-libp2p", "Libp2p => Dial failure for {:?}", peer_id); + *entry.into_mut() = st; + }, + + // "Basic" situation: we failed to reach a node that the peerset requested. + PeerState::Requested | PeerState::PendingRequest { .. } => { + debug!(target: "sub-libp2p", "Libp2p => Dial failure for {:?}", peer_id); + *entry.into_mut() = PeerState::Banned { + until: Instant::now() + Duration::from_secs(5) + }; + debug!(target: "sub-libp2p", "PSM <= Dropped({:?})", peer_id); + self.peerset.dropped(peer_id) + }, + + // We can still get dial failures even if we are already connected to the node, + // as an extra diagnostic for an earlier attempt. + st @ PeerState::Disabled { .. } | st @ PeerState::Enabled { .. } | + st @ PeerState::DisabledPendingEnable { .. } | st @ PeerState::Incoming { .. } => { + debug!(target: "sub-libp2p", "Libp2p => Dial failure for {:?}", peer_id); + *entry.into_mut() = st; + }, + + PeerState::Poisoned => + error!(target: "sub-libp2p", "State of {:?} is poisoned", peer_id), + } } else { - // This code path is only reached if `peer_id` is None, which means that we dialed an - // address without knowing the `PeerId` to expect. We don't currently do that, except - // in one situation: for convenience, we accept bootstrap node addresses in the format - // `IP:PORT`. - // There is no reason this trigger a `connect_to_nodes` round in that situation. - debug!(target: "sub-libp2p", "Failed to reach {} => {:?}", addr, error); - self.topology.set_unreachable(addr); + // The node is not in our list. + trace!(target: "sub-libp2p", "Libp2p => Dial failure for {:?}", peer_id); } } fn inject_node_event( &mut self, source: PeerId, - event: ::OutEvent, + event: CustomProtoHandlerOut, ) { match event { - CustomProtosHandlerOut::CustomProtocolClosed { protocol_id, result } => { - let pos = self.open_protocols.iter().position(|(s, p)| - s == &source && p == &protocol_id - ); - - if let Some(pos) = pos { - self.open_protocols.remove(pos); - } else { - debug_assert!(false, "Couldn't find protocol in open_protocols"); + CustomProtoHandlerOut::CustomProtocolClosed { result } => { + debug!(target: "sub-libp2p", "Handler({:?}) => Closed({:?})", source, result); + match self.peers.get_mut(&source) { + Some(PeerState::Enabled { ref mut open, .. }) if *open => + *open = false, + Some(PeerState::Disabled { ref mut open, .. }) if *open => + *open = false, + Some(PeerState::DisabledPendingEnable { ref mut open, .. }) if *open => + *open = false, + _ => error!(target: "sub-libp2p", "State mismatch in the custom protos handler"), } - let event = CustomProtosOut::CustomProtocolClosed { - protocol_id, + debug!(target: "sub-libp2p", "External API <= Closed({:?})", source); + let event = CustomProtoOut::CustomProtocolClosed { result, peer_id: source, }; self.events.push(NetworkBehaviourAction::GenerateEvent(event)); } - CustomProtosHandlerOut::CustomProtocolOpen { protocol_id, version } => { - debug_assert!(!self.open_protocols.iter().any(|(s, p)| - s == &source && p == &protocol_id - )); - self.open_protocols.push((source.clone(), protocol_id)); - - if let Some(address) = self.enabled_peers.get(&source) { - let event = CustomProtosOut::CustomProtocolOpen { - protocol_id, - version, - peer_id: source, - endpoint: address.clone() - }; - self.events.push(NetworkBehaviourAction::GenerateEvent(event)); - } + CustomProtoHandlerOut::CustomProtocolOpen { version } => { + debug!(target: "sub-libp2p", "Handler({:?}) => Open: version {:?}", source, version); + let endpoint = match self.peers.get_mut(&source) { + Some(PeerState::Enabled { ref mut open, ref connected_point }) | + Some(PeerState::DisabledPendingEnable { ref mut open, ref connected_point, .. }) | + Some(PeerState::Disabled { ref mut open, ref connected_point, .. }) if !*open => { + *open = true; + connected_point.clone() + } + _ => { + error!(target: "sub-libp2p", "State mismatch in the custom protos handler"); + return + } + }; + + debug!(target: "sub-libp2p", "External API <= Open({:?})", source); + let event = CustomProtoOut::CustomProtocolOpen { + version, + peer_id: source, + endpoint, + }; + + self.events.push(NetworkBehaviourAction::GenerateEvent(event)); } - CustomProtosHandlerOut::CustomMessage { protocol_id, message } => { - debug_assert!(self.open_protocols.iter().any(|(s, p)| - s == &source && p == &protocol_id - )); - let event = CustomProtosOut::CustomMessage { + + CustomProtoHandlerOut::CustomMessage { message } => { + debug_assert!(self.is_open(&source)); + trace!(target: "sub-libp2p", "Handler({:?}) => Message", source); + trace!(target: "sub-libp2p", "External API <= Message({:?})", source); + let event = CustomProtoOut::CustomMessage { peer_id: source, - protocol_id, message, }; self.events.push(NetworkBehaviourAction::GenerateEvent(event)); } - CustomProtosHandlerOut::Clogged { protocol_id, messages } => { - debug_assert!(self.open_protocols.iter().any(|(s, p)| - s == &source && p == &protocol_id - )); - warn!(target: "sub-libp2p", "Queue of packets to send to {:?} (protocol: {:?}) is \ - pretty large", source, protocol_id); - self.events.push(NetworkBehaviourAction::GenerateEvent(CustomProtosOut::Clogged { + + CustomProtoHandlerOut::Clogged { messages } => { + debug_assert!(self.is_open(&source)); + trace!(target: "sub-libp2p", "Handler({:?}) => Clogged", source); + trace!(target: "sub-libp2p", "External API <= Clogged({:?})", source); + warn!(target: "sub-libp2p", "Queue of packets to send to {:?} is \ + pretty large", source); + self.events.push(NetworkBehaviourAction::GenerateEvent(CustomProtoOut::Clogged { peer_id: source, - protocol_id, messages, })); } - CustomProtosHandlerOut::ProtocolError { protocol_id, error, is_severe } => { - if is_severe { - warn!(target: "sub-libp2p", "Network misbehaviour from {:?} with protocol \ - {:?}: {:?}", source, protocol_id, error); - self.ban_peer(source); - } else { - debug!(target: "sub-libp2p", "Network misbehaviour from {:?} with protocol \ - {:?}: {:?}", source, protocol_id, error); - } + + // Don't do anything for non-severe errors except report them. + CustomProtoHandlerOut::ProtocolError { is_severe, ref error } if !is_severe => { + debug!(target: "sub-libp2p", "Handler({:?}) => Benign protocol error: {:?}", + source, error) + } + + CustomProtoHandlerOut::ProtocolError { error, .. } => { + debug!(target: "sub-libp2p", "Handler({:?}) => Severe protocol error: {:?}", + source, error); + self.disconnect_peer_inner(&source, Some(Duration::from_secs(5))); } } } fn poll( &mut self, - params: &mut PollParameters, + _params: &mut PollParameters, ) -> Async< NetworkBehaviourAction< - ::InEvent, + CustomProtoHandlerIn, Self::OutEvent, >, > { + // 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.next_connect_to_nodes.poll() { - Ok(Async::Ready(())) => self.connect_to_nodes(params), + match self.peerset.poll() { + Ok(Async::Ready(Some(substrate_peerset::Message::Accept(index)))) => { + self.peerset_report_accept(index); + } + Ok(Async::Ready(Some(substrate_peerset::Message::Reject(index)))) => { + self.peerset_report_reject(index); + } + Ok(Async::Ready(Some(substrate_peerset::Message::Connect(id)))) => { + self.peerset_report_connect(id); + } + Ok(Async::Ready(Some(substrate_peerset::Message::Drop(id)))) => { + self.peerset_report_disconnect(id); + } + Ok(Async::Ready(None)) => { + error!(target: "sub-libp2p", "Peerset receiver stream has returned None"); + break; + } Ok(Async::NotReady) => break, Err(err) => { - warn!(target: "sub-libp2p", "Connect-to-nodes timer errored: {:?}", err); + error!(target: "sub-libp2p", "Peerset receiver stream has errored: {:?}", err); break } } } - // Clean up `banned_peers` - self.banned_peers.retain(|(_, end)| *end > Instant::now()); - self.banned_peers.shrink_to_fit(); + for (peer_id, peer_state) in self.peers.iter_mut() { + match mem::replace(peer_state, PeerState::Poisoned) { + PeerState::PendingRequest { mut timer } => { + if let Ok(Async::NotReady) = timer.poll() { + *peer_state = PeerState::PendingRequest { timer }; + continue; + } + + debug!(target: "sub-libp2p", "Libp2p <= Dial {:?} now that ban has expired", peer_id); + self.events.push(NetworkBehaviourAction::DialPeer { peer_id: peer_id.clone() }); + *peer_state = PeerState::Requested; + } + + PeerState::DisabledPendingEnable { mut timer, connected_point, open } => { + if let Ok(Async::NotReady) = timer.poll() { + *peer_state = PeerState::DisabledPendingEnable { timer, connected_point, open }; + continue; + } + + debug!(target: "sub-libp2p", "Handler({:?}) <= Enable now that ban has expired", peer_id); + self.events.push(NetworkBehaviourAction::SendEvent { + peer_id: peer_id.clone(), + event: CustomProtoHandlerIn::Enable(connected_point.clone().into()), + }); + *peer_state = PeerState::Enabled { connected_point, open }; + } + + st @ _ => *peer_state = st, + } + } if !self.events.is_empty() { return Async::Ready(self.events.remove(0)) diff --git a/core/network-libp2p/src/custom_proto/handler.rs b/core/network-libp2p/src/custom_proto/handler.rs index d7b8da5f742fc425e1ef3569e8417c186b5f02ca..516130602e8b047bc8cd4c958cf6beb785fa5b1b 100644 --- a/core/network-libp2p/src/custom_proto/handler.rs +++ b/core/network-libp2p/src/custom_proto/handler.rs @@ -14,27 +14,29 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use crate::ProtocolId; -use crate::custom_proto::upgrade::{CustomMessage, CustomMessageId, RegisteredProtocol, RegisteredProtocols}; +use crate::custom_proto::upgrade::{CustomMessage, CustomMessageId, RegisteredProtocol}; use crate::custom_proto::upgrade::{RegisteredProtocolEvent, RegisteredProtocolSubstream}; use futures::prelude::*; use libp2p::core::{ - Endpoint, ProtocolsHandler, ProtocolsHandlerEvent, + PeerId, Endpoint, ProtocolsHandler, ProtocolsHandlerEvent, + protocols_handler::IntoProtocolsHandler, protocols_handler::KeepAlive, protocols_handler::ProtocolsHandlerUpgrErr, upgrade::{InboundUpgrade, OutboundUpgrade} }; use log::{debug, error, warn}; use smallvec::{smallvec, SmallVec}; -use std::{error, fmt, io, mem, time::Duration, time::Instant}; +use std::{error, fmt, io, marker::PhantomData, mem, time::Duration, time::Instant}; use tokio_io::{AsyncRead, AsyncWrite}; +use tokio_timer::Delay; use void::Void; -/// Implements the `ProtocolsHandler` trait of libp2p. +/// Implements the `IntoProtocolsHandler` trait of libp2p. /// -/// Every time a connection with a remote is established, an instance of this struct is created and -/// sent to a background task dedicated to this connection. It handles all communications that are -/// specific to Substrate. +/// Every time a connection with a remote starts, an instance of this struct is created and +/// sent to a background task dedicated to this connection. Once the connection is established, +/// it is turned into a `CustomProtoHandler`. It then handles all communications that are specific +/// to Substrate on that connection. /// /// Note that there can be multiple instance of this struct simultaneously for same peer. However /// if that happens, only one main instance can communicate with the outer layers of the code. @@ -62,39 +64,88 @@ use void::Void; /// happens on one substream, we consider that we are disconnected. Re-enabling is performed by /// opening an outbound substream. /// -pub struct CustomProtosHandler { - /// Fields individual to each protocol that we support. - protocols: SmallVec<[PerProtocol; 1]>, +pub struct CustomProtoHandlerProto { + /// Configuration for the protocol upgrade to negotiate. + protocol: RegisteredProtocol, + + /// Marker to pin the generic type. + marker: PhantomData, +} + +impl CustomProtoHandlerProto +where + TSubstream: AsyncRead + AsyncWrite, + TMessage: CustomMessage, +{ + /// Builds a new `CustomProtoHandlerProto`. + pub fn new(protocol: RegisteredProtocol) -> Self { + CustomProtoHandlerProto { + protocol, + marker: PhantomData, + } + } +} + +impl IntoProtocolsHandler for CustomProtoHandlerProto +where + TSubstream: AsyncRead + AsyncWrite, + TMessage: CustomMessage, +{ + type Handler = CustomProtoHandler; + + fn into_handler(self, remote_peer_id: &PeerId) -> Self::Handler { + CustomProtoHandler { + protocol: self.protocol, + remote_peer_id: remote_peer_id.clone(), + state: ProtocolState::Init { + substreams: SmallVec::new(), + init_deadline: Delay::new(Instant::now() + Duration::from_secs(5)) + }, + events_queue: SmallVec::new(), + warm_up_end: Instant::now() + Duration::from_secs(5), + } + } +} + +/// The actual handler once the connection has been established. +pub struct CustomProtoHandler { + /// Configuration for the protocol upgrade to negotiate. + protocol: RegisteredProtocol, + + /// State of the communications with the remote. + state: ProtocolState, + + /// Identifier of the node we're talking to. Used only for logging purposes and shouldn't have + /// any influence on the behaviour. + remote_peer_id: PeerId, /// Queue of events to send to the outside. /// /// This queue must only ever be modified to insert elements at the back, or remove the first /// element. - events_queue: SmallVec<[ProtocolsHandlerEvent, ProtocolId, CustomProtosHandlerOut>; 16]>, + events_queue: SmallVec<[ProtocolsHandlerEvent, (), CustomProtoHandlerOut>; 16]>, /// We have a warm-up period after creating the handler during which we don't shut down the /// connection. warm_up_end: Instant, } -/// Fields individual to each protocol that we support. -struct PerProtocol { - /// Configuration for the protocol upgrade to negotiate. - protocol: RegisteredProtocol, - - /// State of the communications with the remote. - state: PerProtocolState, -} - -/// State of the handler for a specific protocol. -enum PerProtocolState { +/// State of the handler. +enum ProtocolState { /// Waiting for the behaviour to tell the handler whether it is enabled or disabled. - /// Contains a list of substreams opened by the remote but that haven't been processed yet. - Init(SmallVec<[RegisteredProtocolSubstream; 6]>), + Init { + /// List of substreams opened by the remote but that haven't been processed yet. + substreams: SmallVec<[RegisteredProtocolSubstream; 6]>, + /// Deadline after which the initialization is abnormally long. + init_deadline: Delay, + }, /// Handler is opening a substream in order to activate itself. /// If we are in this state, we haven't sent any `CustomProtocolOpen` yet. - Opening, + Opening { + /// Deadline after which the opening is abnormally long. + deadline: Delay, + }, /// Backwards-compatible mode. Contains the unique substream that is open. /// If we are in this state, we have sent a `CustomProtocolOpen` message to the outside. @@ -124,11 +175,6 @@ enum PerProtocolState { reenable: bool, }, - /// We are trying to shut down the connection and thus should refuse any incoming connection. - /// Contains substreams that are being closed. Once all the substreams are closed, we close - /// the connection. - ShuttingDown(SmallVec<[RegisteredProtocolSubstream; 6]>), - /// We sometimes temporarily switch to this state during processing. If we are in this state /// at the beginning of a method, that means something bad happend in the source code. Poisoned, @@ -157,290 +203,6 @@ struct PerProtocolNormalState { shutdown: SmallVec<[RegisteredProtocolSubstream; 4]>, } -impl PerProtocol -where TMessage: CustomMessage, TSubstream: AsyncRead + AsyncWrite { - /// Enables the protocol. Returns an optional event to emit. - /// Must be passed the endpoint of the connection. - #[must_use] - fn enable(&mut self, endpoint: Endpoint) - -> Option, ProtocolId, CustomProtosHandlerOut>> { - - let return_value; - - self.state = match mem::replace(&mut self.state, PerProtocolState::Poisoned) { - PerProtocolState::Poisoned => { - error!(target: "sub-libp2p", "Handler is in poisoned state"); - return_value = None; - PerProtocolState::Poisoned - } - - PerProtocolState::Init(incoming) => { - if incoming.is_empty() { - if let Endpoint::Dialer = endpoint { - return_value = Some(ProtocolsHandlerEvent::OutboundSubstreamRequest { - upgrade: self.protocol.clone(), - info: self.protocol.id(), - }); - } else { - return_value = None; - } - PerProtocolState::Opening - - } else if incoming.iter().any(|s| s.is_multiplex()) { - let event = CustomProtosHandlerOut::CustomProtocolOpen { - protocol_id: self.protocol.id(), - version: incoming[0].protocol_version() - }; - return_value = Some(ProtocolsHandlerEvent::Custom(event)); - PerProtocolState::Normal(PerProtocolNormalState { - outgoing_substream: None, - incoming_substreams: incoming.into_iter().collect(), - pending_response: SmallVec::new(), - pending_send_back: SmallVec::new(), - pending_messages: SmallVec::new(), - shutdown: SmallVec::new(), - }) - - } else { - let event = CustomProtosHandlerOut::CustomProtocolOpen { - protocol_id: self.protocol.id(), - version: incoming[0].protocol_version() - }; - return_value = Some(ProtocolsHandlerEvent::Custom(event)); - PerProtocolState::BackCompat { - substream: incoming.into_iter().next() - .expect("We have a check above that incoming isn't empty; QED"), - shutdown: SmallVec::new() - } - } - } - - st @ PerProtocolState::Opening => { return_value = None; st } - st @ PerProtocolState::BackCompat { .. } => { return_value = None; st } - st @ PerProtocolState::Normal { .. } => { return_value = None; st } - PerProtocolState::Disabled { shutdown, .. } => { - return_value = None; - PerProtocolState::Disabled { shutdown, reenable: true } - } - PerProtocolState::ShuttingDown(list) => { - return_value = None; - PerProtocolState::ShuttingDown(list) - } - }; - - return_value - } - - /// Disables the protocol. Returns `true` if the protocol was closed, `false` if it was already - /// closed or not open yet. - fn disable(&mut self) -> bool { - let mut return_value = false; - - self.state = match mem::replace(&mut self.state, PerProtocolState::Poisoned) { - PerProtocolState::Poisoned => { - error!(target: "sub-libp2p", "Handler is in poisoned state"); - PerProtocolState::Poisoned - } - - PerProtocolState::Init(mut shutdown) => { - for s in &mut shutdown { - s.shutdown(); - } - PerProtocolState::Disabled { shutdown, reenable: false } - } - - PerProtocolState::Opening => { - PerProtocolState::Disabled { shutdown: SmallVec::new(), reenable: false } - } - - PerProtocolState::BackCompat { mut substream, mut shutdown } => { - substream.shutdown(); - shutdown.push(substream); - return_value = true; - PerProtocolState::Disabled { - shutdown: shutdown.into_iter().collect(), - reenable: false - } - } - - PerProtocolState::Normal(state) => { - let mut out: SmallVec<[_; 6]> = SmallVec::new(); - out.extend(state.outgoing_substream.into_iter()); - out.extend(state.incoming_substreams.into_iter()); - out.extend(state.pending_response.into_iter().map(|(_, s)| s)); - out.extend(state.pending_send_back.into_iter().map(|(_, s)| s)); - for s in &mut out { - s.shutdown(); - } - out.extend(state.shutdown.into_iter()); - return_value = true; - PerProtocolState::Disabled { shutdown: out, reenable: false } - } - - PerProtocolState::Disabled { shutdown, .. } => - PerProtocolState::Disabled { shutdown, reenable: false }, - PerProtocolState::ShuttingDown(list) => - PerProtocolState::ShuttingDown(list), - }; - - return_value - } - - /// Shuts down all the substream. Returns `true` if the protocol was closed, `false` if it was - /// already closed or not open yet. - fn shutdown(&mut self) -> bool { - let mut return_value = false; - self.state = match mem::replace(&mut self.state, PerProtocolState::Poisoned) { - PerProtocolState::Poisoned => { - error!(target: "sub-libp2p", "Handler is in poisoned state"); - PerProtocolState::Poisoned - } - - PerProtocolState::Init(mut list) => { - for s in &mut list { s.shutdown(); } - PerProtocolState::ShuttingDown(list) - } - - PerProtocolState::Opening => { - PerProtocolState::ShuttingDown(SmallVec::new()) - } - - PerProtocolState::BackCompat { mut substream, mut shutdown } => { - substream.shutdown(); - shutdown.push(substream); - return_value = true; - PerProtocolState::ShuttingDown(shutdown.into_iter().collect()) - } - - PerProtocolState::Normal(state) => { - let mut out: SmallVec<[_; 6]> = SmallVec::new(); - out.extend(state.outgoing_substream.into_iter()); - out.extend(state.incoming_substreams.into_iter()); - out.extend(state.pending_response.into_iter().map(|(_, s)| s)); - out.extend(state.pending_send_back.into_iter().map(|(_, s)| s)); - for s in &mut out { - s.shutdown(); - } - out.extend(state.shutdown.into_iter()); - return_value = true; - PerProtocolState::ShuttingDown(out) - } - - PerProtocolState::Disabled { shutdown, .. } => - PerProtocolState::ShuttingDown(shutdown), - PerProtocolState::ShuttingDown(list) => - PerProtocolState::ShuttingDown(list), - }; - return_value - } - - /// Polls the state for events. Optionally returns an event to produce. - #[must_use] - fn poll(&mut self) - -> Option, ProtocolId, CustomProtosHandlerOut>> { - - let return_value; - self.state = match mem::replace(&mut self.state, PerProtocolState::Poisoned) { - PerProtocolState::Poisoned => { - error!(target: "sub-libp2p", "Handler is in poisoned state; shutting down"); - return_value = Some(ProtocolsHandlerEvent::Shutdown); - PerProtocolState::Poisoned - } - - st @ PerProtocolState::Init(_) => { - return_value = None; - st - } - - st @ PerProtocolState::Opening { .. } => { - return_value = None; - st - } - - PerProtocolState::BackCompat { mut substream, shutdown } => { - match substream.poll() { - Ok(Async::Ready(Some(RegisteredProtocolEvent::Message(message)))) => { - let event = CustomProtosHandlerOut::CustomMessage { - protocol_id: substream.protocol_id(), - message - }; - return_value = Some(ProtocolsHandlerEvent::Custom(event)); - PerProtocolState::BackCompat { substream, shutdown } - }, - Ok(Async::Ready(Some(RegisteredProtocolEvent::Clogged { messages }))) => { - let event = CustomProtosHandlerOut::Clogged { - protocol_id: substream.protocol_id(), - messages, - }; - return_value = Some(ProtocolsHandlerEvent::Custom(event)); - PerProtocolState::BackCompat { substream, shutdown } - } - Ok(Async::NotReady) => { - return_value = None; - PerProtocolState::BackCompat { substream, shutdown } - } - Ok(Async::Ready(None)) => { - let event = CustomProtosHandlerOut::CustomProtocolClosed { - protocol_id: substream.protocol_id(), - result: Ok(()) - }; - return_value = Some(ProtocolsHandlerEvent::Custom(event)); - PerProtocolState::Disabled { - shutdown: shutdown.into_iter().collect(), - reenable: false - } - } - Err(err) => { - let event = CustomProtosHandlerOut::CustomProtocolClosed { - protocol_id: substream.protocol_id(), - result: Err(err), - }; - return_value = Some(ProtocolsHandlerEvent::Custom(event)); - PerProtocolState::Disabled { - shutdown: shutdown.into_iter().collect(), - reenable: false - } - } - } - } - - PerProtocolState::Normal(mut norm_state) => { - if let Some(event) = norm_state.poll(self.protocol.id()) { - return_value = Some(ProtocolsHandlerEvent::Custom(event)); - } else { - return_value = None; - } - - PerProtocolState::Normal(norm_state) - } - - PerProtocolState::Disabled { mut shutdown, reenable } => { - shutdown_list(&mut shutdown); - // If `reenable` is `true`, that means we should open the substreams system again - // after all the substreams are closed. - if reenable && shutdown.is_empty() { - return_value = Some(ProtocolsHandlerEvent::OutboundSubstreamRequest { - upgrade: self.protocol.clone(), - info: self.protocol.id(), - }); - PerProtocolState::Opening - } else { - return_value = None; - PerProtocolState::Disabled { shutdown, reenable } - } - } - - PerProtocolState::ShuttingDown(mut list) => { - shutdown_list(&mut list); - return_value = None; - PerProtocolState::ShuttingDown(list) - } - }; - - return_value - } -} - impl PerProtocolNormalState where TMessage: CustomMessage, TSubstream: AsyncRead + AsyncWrite { /// Polls for things that are new. Same API constraints as `Future::poll()`. @@ -449,22 +211,20 @@ where TMessage: CustomMessage, TSubstream: AsyncRead + AsyncWrite { /// API note: Ideally we wouldn't need to be passed a `ProtocolId`, and we would return a /// different enum that doesn't contain any `protocol_id`, and the caller would inject /// the ID itself, but that's a ton of code for not much gain. - fn poll(&mut self, protocol_id: ProtocolId) -> Option> { + fn poll(&mut self) -> Option> { for n in (0..self.pending_response.len()).rev() { let (request_id, mut substream) = self.pending_response.swap_remove(n); match substream.poll() { Ok(Async::Ready(Some(RegisteredProtocolEvent::Message(message)))) => { if message.request_id() == CustomMessageId::Response(request_id) { - let event = CustomProtosHandlerOut::CustomMessage { - protocol_id: substream.protocol_id(), + let event = CustomProtoHandlerOut::CustomMessage { message }; self.shutdown.push(substream); return Some(event); } else { self.shutdown.push(substream); - let event = CustomProtosHandlerOut::ProtocolError { - protocol_id, + let event = CustomProtoHandlerOut::ProtocolError { is_severe: true, error: format!("Request ID doesn't match substream: expected {:?}, \ got {:?}", request_id, message.request_id()).into(), @@ -478,8 +238,7 @@ where TMessage: CustomMessage, TSubstream: AsyncRead + AsyncWrite { self.pending_response.push((request_id, substream)), Ok(Async::Ready(None)) => { self.shutdown.push(substream); - let event = CustomProtosHandlerOut::ProtocolError { - protocol_id, + let event = CustomProtoHandlerOut::ProtocolError { is_severe: false, error: format!("Request ID {:?} didn't receive an answer", request_id).into(), }; @@ -487,8 +246,7 @@ where TMessage: CustomMessage, TSubstream: AsyncRead + AsyncWrite { } Err(err) => { self.shutdown.push(substream); - let event = CustomProtosHandlerOut::ProtocolError { - protocol_id, + let event = CustomProtoHandlerOut::ProtocolError { is_severe: false, error: format!("Error while waiting for an answer for {:?}: {}", request_id, err).into(), @@ -502,26 +260,26 @@ where TMessage: CustomMessage, TSubstream: AsyncRead + AsyncWrite { let mut substream = self.incoming_substreams.swap_remove(n); match substream.poll() { Ok(Async::Ready(Some(RegisteredProtocolEvent::Message(message)))) => { - let protocol_id = substream.protocol_id(); - if let CustomMessageId::Request(id) = message.request_id() { - self.pending_send_back.push((id, substream)); - return Some(CustomProtosHandlerOut::CustomMessage { - protocol_id, - message - }); - } else if let CustomMessageId::OneWay = message.request_id() { - self.shutdown.push(substream); - return Some(CustomProtosHandlerOut::CustomMessage { - protocol_id, - message - }); - } else { - self.shutdown.push(substream); - return Some(CustomProtosHandlerOut::ProtocolError { - protocol_id, - is_severe: true, - error: format!("Received response in new substream").into(), - }); + return match message.request_id() { + CustomMessageId::Request(id) => { + self.pending_send_back.push((id, substream)); + Some(CustomProtoHandlerOut::CustomMessage { + message + }) + } + CustomMessageId::OneWay => { + self.shutdown.push(substream); + Some(CustomProtoHandlerOut::CustomMessage { + message + }) + } + _ => { + self.shutdown.push(substream); + Some(CustomProtoHandlerOut::ProtocolError { + is_severe: true, + error: format!("Received response in new substream").into(), + }) + } } }, Ok(Async::Ready(Some(RegisteredProtocolEvent::Clogged { .. }))) => @@ -531,8 +289,7 @@ where TMessage: CustomMessage, TSubstream: AsyncRead + AsyncWrite { Ok(Async::Ready(None)) => {} Err(err) => { self.shutdown.push(substream); - return Some(CustomProtosHandlerOut::ProtocolError { - protocol_id, + return Some(CustomProtoHandlerOut::ProtocolError { is_severe: false, error: format!("Error in incoming substream: {}", err).into(), }); @@ -545,9 +302,9 @@ where TMessage: CustomMessage, TSubstream: AsyncRead + AsyncWrite { } } -/// Event that can be received by a `CustomProtosHandler`. +/// Event that can be received by a `CustomProtoHandler`. #[derive(Debug)] -pub enum CustomProtosHandlerIn { +pub enum CustomProtoHandlerIn { /// The node should start using custom protocols. Contains whether we are the dialer or the /// listener of the connection. Enable(Endpoint), @@ -557,36 +314,28 @@ pub enum CustomProtosHandlerIn { /// Sends a message through a custom protocol substream. SendCustomMessage { - /// The protocol to use. - protocol: ProtocolId, /// The message to send. message: TMessage, }, } -/// Event that can be emitted by a `CustomProtosHandler`. +/// Event that can be emitted by a `CustomProtoHandler`. #[derive(Debug)] -pub enum CustomProtosHandlerOut { +pub enum CustomProtoHandlerOut { /// Opened a custom protocol with the remote. CustomProtocolOpen { - /// Identifier of the protocol. - protocol_id: ProtocolId, /// Version of the protocol that has been opened. version: u8, }, /// Closed a custom protocol with the remote. CustomProtocolClosed { - /// Identifier of the protocol. - protocol_id: ProtocolId, /// Reason why the substream closed. If `Ok`, then it's a graceful exit (EOF). result: io::Result<()>, }, /// Receives a message on a custom protocol substream. CustomMessage { - /// Protocol which generated the message. - protocol_id: ProtocolId, /// Message that has been received. message: TMessage, }, @@ -594,16 +343,12 @@ pub enum CustomProtosHandlerOut { /// A substream to the remote is clogged. The send buffer is very large, and we should print /// a diagnostic message and/or avoid sending more data. Clogged { - /// Protocol which is clogged. - protocol_id: ProtocolId, /// Copy of the messages that are within the buffer, for further diagnostic. messages: Vec, }, /// An error has happened on the protocol level with this node. ProtocolError { - /// Protocol for which the error happened. - protocol_id: ProtocolId, /// If true the error is severe, such as a protocol violation. is_severe: bool, /// The error that happened. @@ -611,45 +356,248 @@ pub enum CustomProtosHandlerOut { }, } -impl CustomProtosHandler +impl CustomProtoHandler where TSubstream: AsyncRead + AsyncWrite, TMessage: CustomMessage, { - /// Builds a new `CustomProtosHandler`. - pub fn new(protocols: RegisteredProtocols) -> Self { - CustomProtosHandler { - protocols: protocols.0.into_iter().map(|protocol| { - PerProtocol { - protocol, - state: PerProtocolState::Init(SmallVec::new()), + /// Enables the handler. + fn enable(&mut self, endpoint: Endpoint) { + self.state = match mem::replace(&mut self.state, ProtocolState::Poisoned) { + ProtocolState::Poisoned => { + error!(target: "sub-libp2p", "Handler with {:?} is in poisoned state", + self.remote_peer_id); + ProtocolState::Poisoned + } + + ProtocolState::Init { substreams: incoming, .. } => { + if incoming.is_empty() { + if let Endpoint::Dialer = endpoint { + self.events_queue.push(ProtocolsHandlerEvent::OutboundSubstreamRequest { + upgrade: self.protocol.clone(), + info: (), + }); + } + ProtocolState::Opening { + deadline: Delay::new(Instant::now() + Duration::from_secs(60)) + } + + } else if incoming.iter().any(|s| s.is_multiplex()) { + let event = CustomProtoHandlerOut::CustomProtocolOpen { + version: incoming[0].protocol_version() + }; + self.events_queue.push(ProtocolsHandlerEvent::Custom(event)); + ProtocolState::Normal(PerProtocolNormalState { + outgoing_substream: None, + incoming_substreams: incoming.into_iter().collect(), + pending_response: SmallVec::new(), + pending_send_back: SmallVec::new(), + pending_messages: SmallVec::new(), + shutdown: SmallVec::new(), + }) + + } else { + let event = CustomProtoHandlerOut::CustomProtocolOpen { + version: incoming[0].protocol_version() + }; + self.events_queue.push(ProtocolsHandlerEvent::Custom(event)); + ProtocolState::BackCompat { + substream: incoming.into_iter().next() + .expect("We have a check above that incoming isn't empty; QED"), + shutdown: SmallVec::new() + } } - }).collect(), - events_queue: SmallVec::new(), - warm_up_end: Instant::now() + Duration::from_secs(5), - } - } + } - /// Enables the handler for all protocols. - fn enable(&mut self, endpoint: Endpoint) { - for protocol in &mut self.protocols { - if let Some(message) = protocol.enable(endpoint) { - self.events_queue.push(message); + st @ ProtocolState::Opening { .. } => st, + st @ ProtocolState::BackCompat { .. } => st, + st @ ProtocolState::Normal { .. } => st, + ProtocolState::Disabled { shutdown, .. } => { + ProtocolState::Disabled { shutdown, reenable: true } } } } - /// Disables the handler for all protocols. + /// Disables the handler. fn disable(&mut self) { - for protocol in &mut self.protocols { - if protocol.disable() { - let event = CustomProtosHandlerOut::CustomProtocolClosed { - protocol_id: protocol.protocol.id(), + self.state = match mem::replace(&mut self.state, ProtocolState::Poisoned) { + ProtocolState::Poisoned => { + error!(target: "sub-libp2p", "Handler with {:?} is in poisoned state", + self.remote_peer_id); + ProtocolState::Poisoned + } + + ProtocolState::Init { substreams: mut shutdown, .. } => { + for s in &mut shutdown { + s.shutdown(); + } + ProtocolState::Disabled { shutdown, reenable: false } + } + + ProtocolState::Opening { .. } => { + ProtocolState::Disabled { shutdown: SmallVec::new(), reenable: false } + } + + ProtocolState::BackCompat { mut substream, mut shutdown } => { + substream.shutdown(); + shutdown.push(substream); + let event = CustomProtoHandlerOut::CustomProtocolClosed { + result: Ok(()) + }; + self.events_queue.push(ProtocolsHandlerEvent::Custom(event)); + ProtocolState::Disabled { + shutdown: shutdown.into_iter().collect(), + reenable: false + } + } + + ProtocolState::Normal(state) => { + let mut out: SmallVec<[_; 6]> = SmallVec::new(); + out.extend(state.outgoing_substream.into_iter()); + out.extend(state.incoming_substreams.into_iter()); + out.extend(state.pending_response.into_iter().map(|(_, s)| s)); + out.extend(state.pending_send_back.into_iter().map(|(_, s)| s)); + for s in &mut out { + s.shutdown(); + } + out.extend(state.shutdown.into_iter()); + let event = CustomProtoHandlerOut::CustomProtocolClosed { result: Ok(()) }; self.events_queue.push(ProtocolsHandlerEvent::Custom(event)); + ProtocolState::Disabled { shutdown: out, reenable: false } } - } + + ProtocolState::Disabled { shutdown, .. } => + ProtocolState::Disabled { shutdown, reenable: false }, + }; + } + + /// Polls the state for events. Optionally returns an event to produce. + #[must_use] + fn poll_state(&mut self) + -> Option, (), CustomProtoHandlerOut>> { + let return_value; + self.state = match mem::replace(&mut self.state, ProtocolState::Poisoned) { + ProtocolState::Poisoned => { + error!(target: "sub-libp2p", "Handler with {:?} is in poisoned state", + self.remote_peer_id); + return_value = None; + ProtocolState::Poisoned + } + + ProtocolState::Init { substreams, mut init_deadline } => { + match init_deadline.poll() { + Ok(Async::Ready(())) => { + init_deadline.reset(Instant::now() + Duration::from_secs(60)); + error!(target: "sub-libp2p", "Handler initialization process is too long \ + with {:?}", self.remote_peer_id) + }, + Ok(Async::NotReady) => {} + Err(_) => error!(target: "sub-libp2p", "Tokio timer has errored") + } + + return_value = None; + ProtocolState::Init { substreams, init_deadline } + } + + ProtocolState::Opening { mut deadline } => { + match deadline.poll() { + Ok(Async::Ready(())) => { + deadline.reset(Instant::now() + Duration::from_secs(60)); + let event = CustomProtoHandlerOut::ProtocolError { + is_severe: false, + error: "Timeout when opening protocol".to_string().into(), + }; + return_value = Some(ProtocolsHandlerEvent::Custom(event)); + ProtocolState::Opening { deadline } + }, + Ok(Async::NotReady) => { + return_value = None; + ProtocolState::Opening { deadline } + }, + Err(_) => { + error!(target: "sub-libp2p", "Tokio timer has errored"); + deadline.reset(Instant::now() + Duration::from_secs(60)); + return_value = None; + ProtocolState::Opening { deadline } + }, + } + } + + ProtocolState::BackCompat { mut substream, shutdown } => { + match substream.poll() { + Ok(Async::Ready(Some(RegisteredProtocolEvent::Message(message)))) => { + let event = CustomProtoHandlerOut::CustomMessage { + message + }; + return_value = Some(ProtocolsHandlerEvent::Custom(event)); + ProtocolState::BackCompat { substream, shutdown } + }, + Ok(Async::Ready(Some(RegisteredProtocolEvent::Clogged { messages }))) => { + let event = CustomProtoHandlerOut::Clogged { + messages, + }; + return_value = Some(ProtocolsHandlerEvent::Custom(event)); + ProtocolState::BackCompat { substream, shutdown } + } + Ok(Async::NotReady) => { + return_value = None; + ProtocolState::BackCompat { substream, shutdown } + } + Ok(Async::Ready(None)) => { + let event = CustomProtoHandlerOut::CustomProtocolClosed { + result: Ok(()) + }; + return_value = Some(ProtocolsHandlerEvent::Custom(event)); + ProtocolState::Disabled { + shutdown: shutdown.into_iter().collect(), + reenable: false + } + } + Err(err) => { + let event = CustomProtoHandlerOut::CustomProtocolClosed { + result: Err(err), + }; + return_value = Some(ProtocolsHandlerEvent::Custom(event)); + ProtocolState::Disabled { + shutdown: shutdown.into_iter().collect(), + reenable: false + } + } + } + } + + ProtocolState::Normal(mut norm_state) => { + if let Some(event) = norm_state.poll() { + return_value = Some(ProtocolsHandlerEvent::Custom(event)); + } else { + return_value = None; + } + + ProtocolState::Normal(norm_state) + } + + ProtocolState::Disabled { mut shutdown, reenable } => { + shutdown_list(&mut shutdown); + // If `reenable` is `true`, that means we should open the substreams system again + // after all the substreams are closed. + if reenable && shutdown.is_empty() { + return_value = Some(ProtocolsHandlerEvent::OutboundSubstreamRequest { + upgrade: self.protocol.clone(), + info: (), + }); + ProtocolState::Opening { + deadline: Delay::new(Instant::now() + Duration::from_secs(60)) + } + } else { + return_value = None; + ProtocolState::Disabled { shutdown, reenable } + } + } + }; + + return_value } /// Called by `inject_fully_negotiated_inbound` and `inject_fully_negotiated_outbound`. @@ -657,39 +605,31 @@ where &mut self, mut substream: RegisteredProtocolSubstream ) { - let state = match self.protocols.iter_mut().find(|p| p.protocol.id() == substream.protocol_id()) { - Some(p) => &mut p.state, - None => { - error!(target: "sub-libp2p", "Found unknown protocol ID {:?}", - substream.protocol_id()); - return - }, - }; - - *state = match mem::replace(state, PerProtocolState::Poisoned) { - PerProtocolState::Poisoned => { - error!(target: "sub-libp2p", "Handler is in poisoned state"); - PerProtocolState::Poisoned + self.state = match mem::replace(&mut self.state, ProtocolState::Poisoned) { + ProtocolState::Poisoned => { + error!(target: "sub-libp2p", "Handler with {:?} is in poisoned state", + self.remote_peer_id); + ProtocolState::Poisoned } - PerProtocolState::Init(mut incoming) => { + ProtocolState::Init { mut substreams, init_deadline } => { if substream.endpoint() == Endpoint::Dialer { - error!(target: "sub-libp2p", "Opened dialing substream before initialization"); + error!(target: "sub-libp2p", "Opened dialing substream with {:?} before \ + initialization", self.remote_peer_id); } - incoming.push(substream); - PerProtocolState::Init(incoming) + substreams.push(substream); + ProtocolState::Init { substreams, init_deadline } } - PerProtocolState::Opening => { - let event = CustomProtosHandlerOut::CustomProtocolOpen { - protocol_id: substream.protocol_id(), + ProtocolState::Opening { .. } => { + let event = CustomProtoHandlerOut::CustomProtocolOpen { version: substream.protocol_version() }; self.events_queue.push(ProtocolsHandlerEvent::Custom(event)); match (substream.endpoint(), substream.is_multiplex()) { (Endpoint::Dialer, true) => { - PerProtocolState::Normal(PerProtocolNormalState { + ProtocolState::Normal(PerProtocolNormalState { outgoing_substream: Some(substream), incoming_substreams: SmallVec::new(), pending_response: SmallVec::new(), @@ -699,7 +639,7 @@ where }) }, (Endpoint::Listener, true) => { - PerProtocolState::Normal(PerProtocolNormalState { + ProtocolState::Normal(PerProtocolNormalState { outgoing_substream: None, incoming_substreams: smallvec![substream], pending_response: SmallVec::new(), @@ -709,7 +649,7 @@ where }) }, (_, false) => { - PerProtocolState::BackCompat { + ProtocolState::BackCompat { substream, shutdown: SmallVec::new() } @@ -717,15 +657,15 @@ where } } - PerProtocolState::BackCompat { substream: existing, mut shutdown } => { + ProtocolState::BackCompat { substream: existing, mut shutdown } => { warn!(target: "sub-libp2p", "Received extra substream after having already one \ - open in backwards-compatibility mode"); + open in backwards-compatibility mode with {:?}", self.remote_peer_id); substream.shutdown(); shutdown.push(substream); - PerProtocolState::BackCompat { substream: existing, shutdown } + ProtocolState::BackCompat { substream: existing, shutdown } } - PerProtocolState::Normal(mut state) => { + ProtocolState::Normal(mut state) => { if substream.endpoint() == Endpoint::Listener { state.incoming_substreams.push(substream); } else if !state.pending_messages.is_empty() { @@ -738,60 +678,45 @@ where state.shutdown.push(substream); } } else { - debug!(target: "sub-libp2p", "Opened spurious outbound substream"); + debug!(target: "sub-libp2p", "Opened spurious outbound substream with {:?}", + self.remote_peer_id); substream.shutdown(); state.shutdown.push(substream); } - PerProtocolState::Normal(state) + ProtocolState::Normal(state) } - PerProtocolState::Disabled { mut shutdown, .. } => { + ProtocolState::Disabled { mut shutdown, .. } => { substream.shutdown(); shutdown.push(substream); - PerProtocolState::Disabled { shutdown, reenable: false } - } - - PerProtocolState::ShuttingDown(mut list) => { - substream.shutdown(); - list.push(substream); - PerProtocolState::ShuttingDown(list) + ProtocolState::Disabled { shutdown, reenable: false } } }; } /// Sends a message to the remote. - fn send_message(&mut self, protocol: ProtocolId, message: TMessage) { - let (protocol, state) = match self.protocols.iter_mut().find(|p| p.protocol.id() == protocol) { - Some(p) => (&mut p.protocol, &mut p.state), - None => { - error!(target: "sub-libp2p", "Tried to send message over unknown protocol ID {:?}", - protocol); - return - }, - }; - - match *state { - PerProtocolState::BackCompat { ref mut substream, .. } => + fn send_message(&mut self, message: TMessage) { + match self.state { + ProtocolState::BackCompat { ref mut substream, .. } => substream.send_message(message), - PerProtocolState::Normal(ref mut state) => { + ProtocolState::Normal(ref mut state) => { if let CustomMessageId::Request(request_id) = message.request_id() { if let Some(mut outgoing_substream) = state.outgoing_substream.take() { outgoing_substream.send_message(message); state.pending_response.push((request_id, outgoing_substream)); } else { if state.pending_messages.len() >= 2048 { - let event = CustomProtosHandlerOut::Clogged { + let event = CustomProtoHandlerOut::Clogged { messages: Vec::new(), - protocol_id: protocol.id() }; self.events_queue.push(ProtocolsHandlerEvent::Custom(event)); } state.pending_messages.push(message); self.events_queue.push(ProtocolsHandlerEvent::OutboundSubstreamRequest { - upgrade: protocol.clone(), - info: protocol.id() + upgrade: self.protocol.clone(), + info: () }); } } else if let CustomMessageId::Response(request_id) = message.request_id() { @@ -801,45 +726,44 @@ where state.shutdown.push(substream); } else { warn!(target: "sub-libp2p", "Libp2p layer received response to a \ - non-existing request ID {:?}", request_id); + non-existing request ID {:?} with {:?}", request_id, self.remote_peer_id); } } else if let Some(mut outgoing_substream) = state.outgoing_substream.take() { outgoing_substream.send_message(message); state.shutdown.push(outgoing_substream); } else { if state.pending_messages.len() >= 2048 { - let event = CustomProtosHandlerOut::Clogged { + let event = CustomProtoHandlerOut::Clogged { messages: Vec::new(), - protocol_id: protocol.id() }; self.events_queue.push(ProtocolsHandlerEvent::Custom(event)); } state.pending_messages.push(message); self.events_queue.push(ProtocolsHandlerEvent::OutboundSubstreamRequest { - upgrade: protocol.clone(), - info: protocol.id() + upgrade: self.protocol.clone(), + info: () }); } } - _ => debug!(target: "sub-libp2p", "Tried to send message over closed protocol") + _ => debug!(target: "sub-libp2p", "Tried to send message over closed protocol \ + with {:?}", self.remote_peer_id) } } } -impl ProtocolsHandler for CustomProtosHandler +impl ProtocolsHandler for CustomProtoHandler where TSubstream: AsyncRead + AsyncWrite, TMessage: CustomMessage { - type InEvent = CustomProtosHandlerIn; - type OutEvent = CustomProtosHandlerOut; + type InEvent = CustomProtoHandlerIn; + type OutEvent = CustomProtoHandlerOut; type Substream = TSubstream; type Error = Void; - type InboundProtocol = RegisteredProtocols; + type InboundProtocol = RegisteredProtocol; type OutboundProtocol = RegisteredProtocol; - type OutboundOpenInfo = ProtocolId; + type OutboundOpenInfo = (); - #[inline] fn listen_protocol(&self) -> Self::InboundProtocol { - RegisteredProtocols(self.protocols.iter().map(|p| p.protocol.clone()).collect()) + self.protocol.clone() } fn inject_fully_negotiated_inbound( @@ -849,7 +773,6 @@ where TSubstream: AsyncRead + AsyncWrite, TMessage: CustomMessage { self.inject_fully_negotiated(proto); } - #[inline] fn inject_fully_negotiated_outbound( &mut self, proto: >::Output, @@ -858,34 +781,26 @@ where TSubstream: AsyncRead + AsyncWrite, TMessage: CustomMessage { self.inject_fully_negotiated(proto); } - fn inject_event(&mut self, message: CustomProtosHandlerIn) { + fn inject_event(&mut self, message: CustomProtoHandlerIn) { match message { - CustomProtosHandlerIn::Disable => self.disable(), - CustomProtosHandlerIn::Enable(endpoint) => self.enable(endpoint), - CustomProtosHandlerIn::SendCustomMessage { protocol, message } => - self.send_message(protocol, message), + CustomProtoHandlerIn::Disable => self.disable(), + CustomProtoHandlerIn::Enable(endpoint) => self.enable(endpoint), + CustomProtoHandlerIn::SendCustomMessage { message } => + self.send_message(message), } } #[inline] - fn inject_inbound_closed(&mut self) {} - - #[inline] - fn inject_dial_upgrade_error(&mut self, protocol_id: Self::OutboundOpenInfo, err: ProtocolsHandlerUpgrErr) { + fn inject_dial_upgrade_error(&mut self, _: (), err: ProtocolsHandlerUpgrErr) { let is_severe = match err { ProtocolsHandlerUpgrErr::Upgrade(_) => true, _ => false, }; - self.events_queue.push(ProtocolsHandlerEvent::Custom(CustomProtosHandlerOut::ProtocolError { - protocol_id, + self.events_queue.push(ProtocolsHandlerEvent::Custom(CustomProtoHandlerOut::ProtocolError { is_severe, error: Box::new(err), })); - - // If we failed to open a substream, there is little chance that we manage to open any - // other substream ever again on this connection, and thus we disable the handler. - self.disable(); } fn connection_keep_alive(&self) -> KeepAlive { @@ -893,26 +808,19 @@ where TSubstream: AsyncRead + AsyncWrite, TMessage: CustomMessage { return KeepAlive::Until(self.warm_up_end) } - for protocol in self.protocols.iter() { - match protocol.state { - PerProtocolState::Disabled { .. } | PerProtocolState::ShuttingDown(_) | - PerProtocolState::Poisoned => return KeepAlive::Now, - _ => {} - } - } + let mut keep_forever = false; - KeepAlive::Forever - } + match self.state { + ProtocolState::Init { .. } | ProtocolState::Opening { .. } => {} + ProtocolState::BackCompat { .. } | ProtocolState::Normal { .. } => + keep_forever = true, + ProtocolState::Disabled { .. } | ProtocolState::Poisoned => return KeepAlive::Now, + } - fn shutdown(&mut self) { - for protocol in &mut self.protocols { - if protocol.shutdown() { - let event = CustomProtosHandlerOut::CustomProtocolClosed { - protocol_id: protocol.protocol.id(), - result: Ok(()) - }; - self.events_queue.push(ProtocolsHandlerEvent::Custom(event)); - } + if keep_forever { + KeepAlive::Forever + } else { + KeepAlive::Now } } @@ -929,32 +837,20 @@ where TSubstream: AsyncRead + AsyncWrite, TMessage: CustomMessage { } // Process all the substreams. - for protocol in self.protocols.iter_mut() { - if let Some(event) = protocol.poll() { - return Ok(Async::Ready(event)) - } - } - - // Shut down the node if everything is closed. - let can_shut_down = self.protocols.iter().all(|p| - match p.state { - PerProtocolState::ShuttingDown(ref list) if list.is_empty() => true, - _ => false - }); - if can_shut_down { - return Ok(Async::Ready(ProtocolsHandlerEvent::Shutdown)) + if let Some(event) = self.poll_state() { + return Ok(Async::Ready(event)) } Ok(Async::NotReady) } } -impl fmt::Debug for CustomProtosHandler +impl fmt::Debug for CustomProtoHandler where TSubstream: AsyncRead + AsyncWrite, { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - f.debug_struct("CustomProtosHandler") + f.debug_struct("CustomProtoHandler") .finish() } } diff --git a/core/network-libp2p/src/custom_proto/mod.rs b/core/network-libp2p/src/custom_proto/mod.rs index 073ce8360aeea9137ec356108fea24f6a6b654c1..cf2bf57153cc3ec0dfec5ffa2df713907b071a55 100644 --- a/core/network-libp2p/src/custom_proto/mod.rs +++ b/core/network-libp2p/src/custom_proto/mod.rs @@ -14,10 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -pub use self::behaviour::{CustomProtos, CustomProtosOut}; -pub use self::upgrade::{CustomMessage, CustomMessageId, RegisteredProtocol, RegisteredProtocols}; +pub use self::behaviour::{CustomProto, CustomProtoOut}; +pub use self::upgrade::{CustomMessage, CustomMessageId, RegisteredProtocol}; mod behaviour; mod handler; -mod topology; mod upgrade; diff --git a/core/network-libp2p/src/custom_proto/topology.rs b/core/network-libp2p/src/custom_proto/topology.rs deleted file mode 100644 index 4ad0e8d1459efdd7bbfd018291f80febfe7fb8fd..0000000000000000000000000000000000000000 --- a/core/network-libp2p/src/custom_proto/topology.rs +++ /dev/null @@ -1,721 +0,0 @@ -// Copyright 2018 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 fnv::FnvHashMap; -use libp2p::{core::swarm::ConnectedPoint, Multiaddr, PeerId}; -use log::{debug, info, trace, warn}; -use serde_derive::{Serialize, Deserialize}; -use std::{cmp, fs}; -use std::io::{Read, Cursor, Error as IoError, ErrorKind as IoErrorKind, Write, BufReader, BufWriter}; -use std::path::{Path, PathBuf}; -use std::time::{Duration, Instant, SystemTime}; - -/// For each address we're connected to, a period of this duration increases the score by 1. -const CONNEC_DURATION_PER_SCORE: Duration = Duration::from_secs(10); -/// Maximum number of addresses for a given peer. If there are more than this number of addresses, -/// the ones with a lower score will be removed. -const MAX_ADDRESSES_PER_PEER: usize = 10; -/// Maximum value for the score. -const MAX_SCORE: u32 = 100; -/// When we successfully connect to a node, raises its score to the given minimum value. -const CONNECTED_MINIMUM_SCORE: u32 = 20; -/// Initial score that a node discovered through Kademlia receives, where we have a hint that the -/// node is reachable. -const DISCOVERY_INITIAL_SCORE_CONNECTABLE: u32 = 15; -/// Initial score that a node discovered through Kademlia receives, without any hint. -const DISCOVERY_INITIAL_SCORE: u32 = 10; -/// Score adjustement when we fail to connect to an address. -const SCORE_DIFF_ON_FAILED_TO_CONNECT: i32 = -1; -/// Default time-to-live for addresses discovered through Kademlia. -/// After this time has elapsed and no connection has succeeded, the address will be removed. -const KADEMLIA_DISCOVERY_EXPIRATION: Duration = Duration::from_secs(2 * 3600); -/// After a successful connection, the TTL is set to a minimum at this amount. -const EXPIRATION_PUSH_BACK_CONNEC: Duration = Duration::from_secs(2 * 3600); -/// Initial score that a bootstrap node receives when registered. -const BOOTSTRAP_NODE_SCORE: u32 = 100; -/// Time to live of a boostrap node. This only applies if you start the node later *without* -/// that bootstrap node configured anymore. -const BOOTSTRAP_NODE_EXPIRATION: Duration = Duration::from_secs(24 * 3600); -/// The first time we fail to connect to an address, wait this duration before trying again. -const FIRST_CONNECT_FAIL_BACKOFF: Duration = Duration::from_secs(2); -/// Every time we fail to connect to an address, multiply the backoff by this constant. -const FAIL_BACKOFF_MULTIPLIER: u32 = 2; -/// We need a maximum value for the backoff, overwise we risk an overflow. -const MAX_BACKOFF: Duration = Duration::from_secs(30 * 60); - -/// Stores information about the topology of the network. -#[derive(Debug)] -pub struct NetTopology { - /// The actual storage. Never contains a key for `local_peer_id`. - store: FnvHashMap, - /// Optional path to the file that caches the serialized version of `store`. - cache_path: Option, - /// PeerId of the local node. - local_peer_id: PeerId, -} - -impl NetTopology { - /// Initializes a new `NetTopology` that isn't tied to any file. - /// - /// `flush_to_disk()` will be a no-op. - #[inline] - pub fn memory(local_peer_id: PeerId) -> NetTopology { - NetTopology { - store: Default::default(), - cache_path: None, - local_peer_id, - } - } - - /// Builds a `NetTopology` that will use `path` as a cache. - /// - /// This function tries to load a known topology from the file. If the file doesn't exist - /// or contains garbage data, the execution still continues. - /// - /// Calling `flush_to_disk()` in the future writes to the given path. - pub fn from_file>(local_peer_id: PeerId, path: P) -> NetTopology { - let path = path.as_ref(); - debug!(target: "sub-libp2p", "Initializing peer store for JSON file {:?}", path); - let store = try_load(path, &local_peer_id); - NetTopology { - store, - cache_path: Some(path.to_owned()), - local_peer_id, - } - } - - /// Writes the topology into the path passed to `from_file`. - /// - /// No-op if the object was created with `memory()`. - pub fn flush_to_disk(&mut self) -> Result<(), IoError> { - let path = match self.cache_path { - Some(ref p) => p, - None => return Ok(()) - }; - - let file = fs::File::create(path)?; - // TODO: the capacity of the BufWriter is kind of arbitrary ; decide better - serialize(BufWriter::with_capacity(1024 * 1024, file), &mut self.store) - } - - /// Returns the number of peers in the topology, excluding the local peer. - #[inline] - pub fn num_peers(&self) -> usize { - self.store.len() - } - - /// Perform a cleanup pass, removing all obsolete addresses and peers. - /// - /// This should be done from time to time. - pub fn cleanup(&mut self) { - let now_systime = SystemTime::now(); - self.store.retain(|_, peer| { - let new_addrs = peer.addrs - .drain(..) - .filter(|a| a.expires > now_systime || a.is_connected()) - .collect(); - peer.addrs = new_addrs; - !peer.addrs.is_empty() - }); - } - - /// Returns a list of all the known addresses of peers, ordered by the - /// order in which we should attempt to connect to them. - /// - /// Because of expiration and back-off mechanisms, this list can grow - /// by itself over time. The `Instant` that is returned corresponds to - /// the earlier known time when a new entry will be added automatically to - /// the list. - pub fn addrs_to_attempt(&mut self) -> (impl Iterator, Instant) { - // TODO: optimize - let now = Instant::now(); - let now_systime = SystemTime::now(); - let mut instant = now + Duration::from_secs(3600); - let mut addrs_out = Vec::new(); - - let mut peer_addrs = Vec::new(); - - 'peer_loop: for (peer, info) in &mut self.store { - peer_addrs.clear(); - - for addr in &mut info.addrs { - let (score, is_connected) = addr.score_and_is_connected(); - if is_connected { - continue 'peer_loop - } - if score == 0 || addr.expires < now_systime { - continue - } - if addr.back_off_until > now { - instant = cmp::min(instant, addr.back_off_until); - continue - } - - peer_addrs.push(((peer, &addr.addr), score)); - } - - for val in peer_addrs.drain(..) { - addrs_out.push(val); - } - } - - addrs_out.sort_by(|a, b| b.1.cmp(&a.1)); - (addrs_out.into_iter().map(|a| a.0), instant) - } - - /// Adds an address corresponding to a boostrap node. - /// - /// We assume that the address is valid, so its score starts very high. - pub fn add_bootstrap_addr(&mut self, peer: &PeerId, addr: Multiaddr) { - if *peer == self.local_peer_id { - return - } - - let now_systime = SystemTime::now(); - let now = Instant::now(); - - let peer = peer_access(&mut self.store, peer); - - let mut found = false; - let new_addrs = peer.addrs - .drain(..) - .filter_map(|a| { - if a.expires < now_systime && !a.is_connected() { - return None - } - if a.addr == addr { - found = true; - } - Some(a) - }) - .collect(); - peer.addrs = new_addrs; - - if !found { - peer.addrs.push(Addr { - addr, - expires: now_systime + BOOTSTRAP_NODE_EXPIRATION, - back_off_until: now, - next_back_off: FIRST_CONNECT_FAIL_BACKOFF, - score: AddrScore { - connected_since: None, - score: BOOTSTRAP_NODE_SCORE, - latest_score_update: now, - }, - }); - } - } - - /// Indicates the topology that we have discovered new addresses for a given node. - /// - /// Returns `true` if the topology has changed in some way. Returns `false` if calling this - /// method was a no-op. - pub fn add_discovered_addrs( - &mut self, - peer_id: &PeerId, - addrs: I, - ) -> bool - where I: Iterator { - if *peer_id == self.local_peer_id { - return false - } - - let mut addrs: Vec<_> = addrs.collect(); - - if addrs.len() > 40 { - warn!(target: "sub-libp2p", "Attempt to add more than 40 addresses for {:?}", peer_id); - addrs.truncate(40); - } - - let now_systime = SystemTime::now(); - let now = Instant::now(); - - let peer = peer_access(&mut self.store, peer_id); - - let new_addrs = peer.addrs - .drain(..) - .filter(|a| { - if a.expires < now_systime && !a.is_connected() { - return false - } - addrs.retain(|(addr, _)| *addr != a.addr); - true - }) - .collect(); - peer.addrs = new_addrs; - - let mut anything_changed = false; - - if !addrs.is_empty() { - anything_changed = true; - trace!( - target: "sub-libp2p", - "Peer store: adding addresses {:?} for {:?}", - addrs, - peer_id, - ); - } - - 'addrs_inserter: for (addr, connectable) in addrs { - let initial_score = if connectable { - DISCOVERY_INITIAL_SCORE_CONNECTABLE - } else { - DISCOVERY_INITIAL_SCORE - }; - - // Enforce `MAX_ADDRESSES_PER_PEER` before inserting, or skip this entry. - while peer.addrs.len() >= MAX_ADDRESSES_PER_PEER { - let pos = peer.addrs.iter_mut().position(|addr| addr.score() <= initial_score); - if let Some(pos) = pos { - let _ = peer.addrs.remove(pos); - } else { - continue 'addrs_inserter; - } - } - - // `addrs` can contain duplicates, therefore we would insert the same address twice. - if peer.addrs.iter().any(|a| a.addr == addr) { - continue; - } - - peer.addrs.push(Addr { - addr, - expires: now_systime + KADEMLIA_DISCOVERY_EXPIRATION, - back_off_until: now, - next_back_off: FIRST_CONNECT_FAIL_BACKOFF, - score: AddrScore { - connected_since: None, - score: initial_score, - latest_score_update: now, - }, - }); - } - - anything_changed - } - - /// Returns the addresses stored for a specific peer. - #[inline] - pub fn addresses_of_peer(&mut self, peer: &PeerId) -> Vec { - let peer = if let Some(peer) = self.store.get_mut(peer) { - peer - } else { - return Vec::new() - }; - - let now_st = SystemTime::now(); - let now_is = Instant::now(); - - let mut list = peer.addrs.iter_mut().filter_map(move |addr| { - let (score, connected) = addr.score_and_is_connected(); - if (addr.expires >= now_st && score > 0 && addr.back_off_until < now_is) || connected { - Some((score, &addr.addr)) - } else { - None - } - }).collect::>(); - list.sort_by(|a, b| a.0.cmp(&b.0)); - // TODO: meh, optimize - list.into_iter().map(|(_, addr)| addr.clone()).collect::>() - } - - /// Marks the given peer as connected through the given endpoint. - pub fn set_connected(&mut self, peer: &PeerId, endpoint: &ConnectedPoint) { - if *peer == self.local_peer_id { - return - } - - let addr = match endpoint { - ConnectedPoint::Dialer { address } => address, - ConnectedPoint::Listener { .. } => return - }; - - let now = Instant::now(); - - // Just making sure that we have an entry for this peer in `store`, but don't use it. - let _ = peer_access(&mut self.store, peer); - - for (peer_in_store, info_in_store) in self.store.iter_mut() { - if peer == peer_in_store { - if let Some(addr) = info_in_store.addrs.iter_mut().find(|a| &a.addr == addr) { - addr.connected_now(CONNECTED_MINIMUM_SCORE); - addr.back_off_until = now; - addr.next_back_off = FIRST_CONNECT_FAIL_BACKOFF; - continue - } - - info_in_store.addrs.push(Addr { - addr: addr.clone(), - expires: SystemTime::now() + EXPIRATION_PUSH_BACK_CONNEC, - back_off_until: now, - next_back_off: FIRST_CONNECT_FAIL_BACKOFF, - score: AddrScore { - connected_since: Some(now), - latest_score_update: now, - score: CONNECTED_MINIMUM_SCORE, - }, - }); - - } else { - // Set the score to 0 for any address that matches the one we connected to. - for addr_in_store in &mut info_in_store.addrs { - if &addr_in_store.addr == addr { - addr_in_store.adjust_score(-(MAX_SCORE as i32)); - } - } - } - } - } - - /// Marks the given peer as disconnected. The endpoint is the one we were connected to. - pub fn set_disconnected(&mut self, _: &PeerId, endpoint: &ConnectedPoint) { - let addr = match endpoint { - ConnectedPoint::Dialer { address } => address, - ConnectedPoint::Listener { .. } => return - }; - - // Note that we used to have different score values here in the past, but there really - // isn't much point in doing so in practice. - let score_diff = -3; - - for info in self.store.values_mut() { - for a in info.addrs.iter_mut() { - if &a.addr == addr { - a.disconnected_now(score_diff); - a.back_off_until = Instant::now() + a.next_back_off; - a.next_back_off = cmp::min(a.next_back_off * FAIL_BACKOFF_MULTIPLIER, MAX_BACKOFF); - let expires_push_back = SystemTime::now() + EXPIRATION_PUSH_BACK_CONNEC; - if a.expires < expires_push_back { - a.expires = expires_push_back; - } - return - } - } - } - } - - /// Indicates to the topology that we failed to reach a node when dialing the given address. - pub fn set_unreachable(&mut self, addr: &Multiaddr) { - for info in self.store.values_mut() { - for a in info.addrs.iter_mut() { - if &a.addr != addr { - continue - } - - // It is possible that we are connected to this address, and that the dial failure - // concerns another peer. - if a.is_connected() { - continue - } - - a.adjust_score(SCORE_DIFF_ON_FAILED_TO_CONNECT); - trace!(target: "sub-libp2p", "Back off for {} = {:?}", addr, a.next_back_off); - a.back_off_until = Instant::now() + a.next_back_off; - a.next_back_off = cmp::min(a.next_back_off * FAIL_BACKOFF_MULTIPLIER, MAX_BACKOFF); - } - } - } -} - -fn peer_access<'a>(store: &'a mut FnvHashMap, peer: &PeerId) -> &'a mut PeerInfo { - // TODO: should be optimizable if HashMap gets a better API - store.entry(peer.clone()).or_insert_with(Default::default) -} - -#[derive(Debug, Clone, Default)] -struct PeerInfo { - /// Addresses of that peer. - addrs: Vec, -} - -#[derive(Debug)] -struct Addr { - /// The multiaddress. - addr: Multiaddr, - /// When the address expires. - expires: SystemTime, - next_back_off: Duration, - /// Don't try to connect to this node until `Instant`. - back_off_until: Instant, - score: AddrScore, -} - -impl Clone for Addr { - fn clone(&self) -> Addr { - Addr { - addr: self.addr.clone(), - expires: self.expires, - next_back_off: self.next_back_off, - back_off_until: self.back_off_until, - score: self.score.clone(), - } - } -} - -#[derive(Debug, Clone)] -struct AddrScore { - /// If connected, contains the moment when we connected. `None` if we're not connected. - connected_since: Option, - /// Score of this address. Potentially needs to be updated based on `latest_score_update`. - score: u32, - /// When we last updated the score. - latest_score_update: Instant, -} - -impl Addr { - /// Sets the addr to connected. If the score is lower than the given value, raises it to this - /// value. - fn connected_now(&mut self, raise_to_min: u32) { - let now = Instant::now(); - Addr::flush(&mut self.score, now); - self.score.connected_since = Some(now); - if self.score.score < raise_to_min { - self.score.score = raise_to_min; - } - } - - /// Applies a modification to the score. - fn adjust_score(&mut self, score_diff: i32) { - Addr::flush(&mut self.score, Instant::now()); - if score_diff >= 0 { - self.score.score = cmp::min(MAX_SCORE, self.score.score + score_diff as u32); - } else { - self.score.score = self.score.score.saturating_sub(-score_diff as u32); - } - } - - /// Sets the addr to disconnected and applies a modification to the score. - fn disconnected_now(&mut self, score_diff: i32) { - Addr::flush(&mut self.score, Instant::now()); - self.score.connected_since = None; - if score_diff >= 0 { - self.score.score = cmp::min(MAX_SCORE, self.score.score + score_diff as u32); - } else { - self.score.score = self.score.score.saturating_sub(-score_diff as u32); - } - } - - /// Returns true if we are connected to this addr. - fn is_connected(&self) -> bool { - self.score.connected_since.is_some() - } - - /// Returns the score, and true if we are connected to this addr. - fn score_and_is_connected(&mut self) -> (u32, bool) { - Addr::flush(&mut self.score, Instant::now()); - let is_connected = self.score.connected_since.is_some(); - (self.score.score, is_connected) - } - - /// Updates `score` and `latest_score_update`, and returns the score. - fn score(&mut self) -> u32 { - Addr::flush(&mut self.score, Instant::now()); - self.score.score - } - - fn flush(score: &mut AddrScore, now: Instant) { - if let Some(connected_since) = score.connected_since { - let potential_score: u32 = div_dur_with_dur(now - connected_since, CONNEC_DURATION_PER_SCORE); - // We flush when we connect to an address. - debug_assert!(score.latest_score_update >= connected_since); - let effective_score: u32 = - div_dur_with_dur(score.latest_score_update - connected_since, CONNEC_DURATION_PER_SCORE); - let to_add = potential_score.saturating_sub(effective_score); - score.score = cmp::min(MAX_SCORE, score.score + to_add); - } - - score.latest_score_update = now; - } -} - -/// Divides a `Duration` with a `Duration`. This exists in the stdlib but isn't stable yet. -// TODO: remove this function once stable -fn div_dur_with_dur(a: Duration, b: Duration) -> u32 { - let a_ms = a.as_secs() * 1_000_000 + u64::from(a.subsec_micros()); - let b_ms = b.as_secs() * 1_000_000 + u64::from(b.subsec_micros()); - (a_ms / b_ms) as u32 -} - -/// Serialized version of a `PeerInfo`. Suitable for storage in the cache file. -#[derive(Debug, Clone, Serialize, Deserialize)] -struct SerializedPeerInfo { - addrs: Vec, -} - -/// Serialized version of an `Addr`. Suitable for storage in the cache file. -#[derive(Debug, Clone, Serialize, Deserialize)] -struct SerializedAddr { - addr: String, - expires: SystemTime, - score: u32, -} - -impl<'a> From<&'a mut Addr> for SerializedAddr { - fn from(addr: &'a mut Addr) -> SerializedAddr { - SerializedAddr { - addr: addr.addr.to_string(), - expires: addr.expires, - score: addr.score(), - } - } -} - -/// Attempts to load storage from a file. -/// Ignores any entry equal to `local_peer_id`. -/// Deletes the file and returns an empty map if the file doesn't exist, cannot be opened -/// or is corrupted. -fn try_load(path: impl AsRef, local_peer_id: &PeerId) -> FnvHashMap { - let path = path.as_ref(); - if !path.exists() { - debug!(target: "sub-libp2p", "Peer storage file {:?} doesn't exist", path); - return Default::default() - } - - let mut file = match fs::File::open(path) { - // TODO: the capacity of the BufReader is kind of arbitrary ; decide better - Ok(f) => BufReader::with_capacity(1024 * 1024, f), - Err(err) => { - warn!(target: "sub-libp2p", "Failed to open peer storage file: {:?}", err); - info!(target: "sub-libp2p", "Deleting peer storage file {:?}", path); - let _ = fs::remove_file(path); - return Default::default() - } - }; - - // We want to support empty files (and treat them as an empty recordset). Unfortunately - // `serde_json` will always produce an error if we do this ("unexpected EOF at line 0 - // column 0"). Therefore we start by reading one byte from the file in order to check - // for EOF. - - let mut first_byte = [0]; - let num_read = match file.read(&mut first_byte) { - Ok(f) => f, - Err(err) => { - // TODO: DRY - warn!(target: "sub-libp2p", "Failed to read peer storage file: {:?}", err); - info!(target: "sub-libp2p", "Deleting peer storage file {:?}", path); - let _ = fs::remove_file(path); - return Default::default() - } - }; - - if num_read == 0 { - // File is empty. - debug!(target: "sub-libp2p", "Peer storage file {:?} is empty", path); - Default::default() - - } else { - let data = Cursor::new(first_byte).chain(file); - match serde_json::from_reader::<_, serde_json::Value>(data) { - Ok(serde_json::Value::Null) => Default::default(), - Ok(serde_json::Value::Object(map)) => - deserialize_tolerant(map.into_iter(), local_peer_id), - Ok(_) | Err(_) => { - // The `Ok(_)` case means that the file doesn't contain a map. - let _ = fs::remove_file(path); - Default::default() - }, - } - } -} - -/// Attempts to turn a deserialized version of the storage into the final version. -/// -/// Skips entries that are invalid or equal to `local_peer_id`. -fn deserialize_tolerant( - iter: impl Iterator, - local_peer_id: &PeerId -) -> FnvHashMap { - let now = Instant::now(); - let now_systime = SystemTime::now(); - - let mut out = FnvHashMap::default(); - for (peer, info) in iter { - let peer: PeerId = match peer.parse() { - Ok(p) => p, - Err(_) => continue, - }; - - if &peer == local_peer_id { - continue - } - - let info: SerializedPeerInfo = match serde_json::from_value(info) { - Ok(i) => i, - Err(_) => continue, - }; - - let mut addrs = Vec::with_capacity(info.addrs.len()); - for addr in info.addrs { - let multiaddr = match addr.addr.parse() { - Ok(a) => a, - Err(_) => continue, - }; - - if addr.expires < now_systime { - continue - } - - addrs.push(Addr { - addr: multiaddr, - expires: addr.expires, - next_back_off: FIRST_CONNECT_FAIL_BACKOFF, - back_off_until: now, - score: AddrScore { - connected_since: None, - score: addr.score, - latest_score_update: now, - }, - }); - } - - if addrs.is_empty() { - continue - } - - out.insert(peer, PeerInfo { addrs }); - } - - out -} - -/// Attempts to turn a deserialized version of the storage into the final version. -/// -/// Skips entries that are invalid or expired. -fn serialize(out: W, map: &mut FnvHashMap) -> Result<(), IoError> { - let now = SystemTime::now(); - let array: FnvHashMap<_, _> = map.iter_mut().filter_map(|(peer, info)| { - if info.addrs.is_empty() { - return None - } - - let peer = peer.to_base58(); - let info = SerializedPeerInfo { - addrs: info.addrs.iter_mut() - .filter_map(|a| if a.expires > now || a.is_connected() { - Some(a.into()) - } else { - None - }) - .collect(), - }; - - Some((peer, info)) - }).collect(); - - serde_json::to_writer_pretty(out, &array) - .map_err(|err| IoError::new(IoErrorKind::Other, err)) -} diff --git a/core/network-libp2p/src/custom_proto/upgrade.rs b/core/network-libp2p/src/custom_proto/upgrade.rs index 292993957d5a417b656a52f9590143864ab2593d..fc9ed5bddb1b70d8149660b496b98abb4a4b2d5b 100644 --- a/core/network-libp2p/src/custom_proto/upgrade.rs +++ b/core/network-libp2p/src/custom_proto/upgrade.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ use crate::ProtocolId; use bytes::Bytes; -use libp2p::core::{Endpoint, UpgradeInfo, InboundUpgrade, OutboundUpgrade, upgrade::ProtocolName}; +use libp2p::core::{Negotiated, Endpoint, UpgradeInfo, InboundUpgrade, OutboundUpgrade, upgrade::ProtocolName}; use libp2p::tokio_codec::Framed; use log::warn; use std::{collections::VecDeque, io, iter, marker::PhantomData, vec::IntoIter as VecIntoIter}; @@ -92,7 +92,7 @@ pub struct RegisteredProtocolSubstream { /// If true, we should call `poll_complete` on the inner sink. requires_poll_complete: bool, /// The underlying substream. - inner: stream::Fuse>>>, + inner: stream::Fuse, UviBytes>>>, /// Id of the protocol. protocol_id: ProtocolId, /// Version of the protocol that was negotiated. @@ -385,10 +385,14 @@ where TSubstream: AsyncRead + AsyncWrite, fn upgrade_inbound( self, - socket: TSubstream, + socket: Negotiated, info: Self::Info, ) -> Self::Future { - let framed = Framed::new(socket, UviBytes::default()); + let framed = { + let mut codec = UviBytes::default(); + codec.set_max_len(16 * 1024 * 1024); // 16 MiB hard limit for packets. + Framed::new(socket, codec) + }; future::ok(RegisteredProtocolSubstream { is_closing: false, @@ -414,7 +418,7 @@ where TSubstream: AsyncRead + AsyncWrite, fn upgrade_outbound( self, - socket: TSubstream, + socket: Negotiated, info: Self::Info, ) -> Self::Future { let framed = Framed::new(socket, UviBytes::default()); @@ -433,99 +437,3 @@ where TSubstream: AsyncRead + AsyncWrite, }) } } - -// Connection upgrade for all the protocols contained in it. -pub struct RegisteredProtocols(pub Vec>); - -impl RegisteredProtocols { - /// Returns the number of protocols. - #[inline] - pub fn len(&self) -> usize { - self.0.len() - } -} - -impl Default for RegisteredProtocols { - fn default() -> Self { - RegisteredProtocols(Vec::new()) - } -} - -impl UpgradeInfo for RegisteredProtocols { - type Info = RegisteredProtocolsName; - type InfoIter = VecIntoIter; - - #[inline] - fn protocol_info(&self) -> Self::InfoIter { - // We concat the lists of `RegisteredProtocol::protocol_names` for - // each protocol. - self.0.iter().enumerate().flat_map(|(n, proto)| - UpgradeInfo::protocol_info(proto) - .map(move |inner| { - RegisteredProtocolsName { - inner, - index: n, - } - }) - ).collect::>().into_iter() - } -} - -impl Clone for RegisteredProtocols { - fn clone(&self) -> Self { - RegisteredProtocols(self.0.clone()) - } -} - -/// Implementation of `ProtocolName` for several custom protocols. -#[derive(Debug, Clone)] -pub struct RegisteredProtocolsName { - /// Inner registered protocol. - inner: RegisteredProtocolName, - /// Index of the protocol in the list of registered custom protocols. - index: usize, -} - -impl ProtocolName for RegisteredProtocolsName { - fn protocol_name(&self) -> &[u8] { - self.inner.protocol_name() - } -} - -impl InboundUpgrade for RegisteredProtocols -where TSubstream: AsyncRead + AsyncWrite, -{ - type Output = as InboundUpgrade>::Output; - type Future = as InboundUpgrade>::Future; - type Error = io::Error; - - #[inline] - fn upgrade_inbound( - self, - socket: TSubstream, - info: Self::Info, - ) -> Self::Future { - self.0.into_iter() - .nth(info.index) - .expect("invalid protocol index ; programmer logic error") - .upgrade_inbound(socket, info.inner) - } -} - -impl OutboundUpgrade for RegisteredProtocols -where TSubstream: AsyncRead + AsyncWrite, -{ - type Output = >::Output; - type Future = >::Future; - type Error = >::Error; - - #[inline] - fn upgrade_outbound( - self, - socket: TSubstream, - info: Self::Info, - ) -> Self::Future { - // Upgrades are symmetrical. - self.upgrade_inbound(socket, info) - } -} diff --git a/core/network-libp2p/src/error.rs b/core/network-libp2p/src/error.rs deleted file mode 100644 index 5466ce2a26966b9abba7abdd39735e229a38d1b3..0000000000000000000000000000000000000000 --- a/core/network-libp2p/src/error.rs +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2015-2018 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 error_chain::*; -use std::{io, net, fmt}; - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum DisconnectReason { - DisconnectRequested, - TCPError, - BadProtocol, - UselessPeer, - TooManyPeers, - DuplicatePeer, - IncompatibleProtocol, - NullIdentity, - ClientQuit, - UnexpectedIdentity, - LocalIdentity, - PingTimeout, - Unknown, -} - -impl DisconnectReason { - pub fn from_u8(n: u8) -> DisconnectReason { - match n { - 0 => DisconnectReason::DisconnectRequested, - 1 => DisconnectReason::TCPError, - 2 => DisconnectReason::BadProtocol, - 3 => DisconnectReason::UselessPeer, - 4 => DisconnectReason::TooManyPeers, - 5 => DisconnectReason::DuplicatePeer, - 6 => DisconnectReason::IncompatibleProtocol, - 7 => DisconnectReason::NullIdentity, - 8 => DisconnectReason::ClientQuit, - 9 => DisconnectReason::UnexpectedIdentity, - 10 => DisconnectReason::LocalIdentity, - 11 => DisconnectReason::PingTimeout, - _ => DisconnectReason::Unknown, - } - } -} - -impl fmt::Display for DisconnectReason { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::DisconnectReason::*; - - let msg = match *self { - DisconnectRequested => "disconnect requested", - TCPError => "TCP error", - BadProtocol => "bad protocol", - UselessPeer => "useless peer", - TooManyPeers => "too many peers", - DuplicatePeer => "duplicate peer", - IncompatibleProtocol => "incompatible protocol", - NullIdentity => "null identity", - ClientQuit => "client quit", - UnexpectedIdentity => "unexpected identity", - LocalIdentity => "local identity", - PingTimeout => "ping timeout", - Unknown => "unknown", - }; - - f.write_str(msg) - } -} - -error_chain! { - errors { - #[doc = "Error concerning the network address parsing subsystem."] - AddressParse { - description("Failed to parse network address"), - display("Failed to parse network address"), - } - - #[doc = "Error concerning the network address resolution subsystem."] - AddressResolve(err: Option) { - description("Failed to resolve network address"), - display("Failed to resolve network address {}", err.as_ref().map_or("".to_string(), |e| e.to_string())), - } - - #[doc = "Authentication failure"] - Auth { - description("Authentication failure"), - display("Authentication failure"), - } - - #[doc = "Unrecognised protocol"] - BadProtocol { - description("Bad protocol"), - display("Bad protocol"), - } - - #[doc = "Expired message"] - Expired { - description("Expired message"), - display("Expired message"), - } - - #[doc = "Peer not found"] - PeerNotFound { - description("Peer not found"), - display("Peer not found"), - } - - #[doc = "Peer is disconnected"] - Disconnect(reason: DisconnectReason) { - description("Peer disconnected"), - display("Peer disconnected: {}", reason), - } - - #[doc = "Invalid node id"] - InvalidNodeId { - description("Invalid node id"), - display("Invalid node id"), - } - - #[doc = "Packet size is over the protocol limit"] - OversizedPacket { - description("Packet is too large"), - display("Packet is too large"), - } - - #[doc = "An unknown IO error occurred."] - Io(err: io::Error) { - description("IO Error"), - display("Unexpected IO error: {}", err), - } - } -} - -impl From for Error { - fn from(err: io::Error) -> Self { - Error::from_kind(ErrorKind::Io(err)) - } -} - -impl From for Error { - fn from(_err: net::AddrParseError) -> Self { ErrorKind::AddressParse.into() } -} - -#[test] -fn test_errors() { - assert_eq!(DisconnectReason::ClientQuit, DisconnectReason::from_u8(8)); - let mut r = DisconnectReason::DisconnectRequested; - for i in 0 .. 20 { - r = DisconnectReason::from_u8(i); - } - assert_eq!(DisconnectReason::Unknown, r); -} diff --git a/core/network-libp2p/src/lib.rs b/core/network-libp2p/src/lib.rs index a6f66c6026a81909073ac8ae149bc955de7236f3..5b73db636b0f4d9b54db3418eab58f5ec1aceae4 100644 --- a/core/network-libp2p/src/lib.rs +++ b/core/network-libp2p/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -17,36 +17,152 @@ //! Networking layer of Substrate. mod behaviour; +mod config; mod custom_proto; -mod error; -mod secret; mod service_task; -mod traits; mod transport; +pub use crate::behaviour::Severity; +pub use crate::config::*; pub use crate::custom_proto::{CustomMessage, CustomMessageId, RegisteredProtocol}; -pub use crate::error::{Error, ErrorKind, DisconnectReason}; -pub use crate::secret::obtain_private_key; +pub use crate::config::{NetworkConfiguration, NodeKeyConfig, Secret, NonReservedPeerMode}; pub use crate::service_task::{start_service, Service, ServiceEvent}; -pub use crate::traits::{NetworkConfiguration, NodeIndex, NodeId, NonReservedPeerMode}; -pub use crate::traits::{ProtocolId, Secret, Severity}; -pub use libp2p::{Multiaddr, multiaddr::Protocol, build_multiaddr, PeerId, core::PublicKey}; - -/// Check if node url is valid -pub fn validate_node_url(url: &str) -> Result<(), Error> { - match url.parse::() { - Ok(_) => Ok(()), - Err(_) => Err(ErrorKind::InvalidNodeId.into()), - } -} +pub use libp2p::{Multiaddr, multiaddr, build_multiaddr}; +pub use libp2p::{identity, PeerId, core::PublicKey}; + +use libp2p::core::nodes::ConnectedPoint; +use serde_derive::Serialize; +use std::{collections::{HashMap, HashSet}, error, fmt, time::Duration}; + +/// Protocol / handler id +pub type ProtocolId = [u8; 3]; /// Parses a string address and returns the component, if valid. -pub fn parse_str_addr(addr_str: &str) -> Result<(PeerId, Multiaddr), Error> { - let mut addr: Multiaddr = addr_str.parse().map_err(|_| ErrorKind::AddressParse)?; +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(Protocol::P2p(key)) => - PeerId::from_multihash(key).map_err(|_| ErrorKind::AddressParse)?, - _ => return Err(ErrorKind::AddressParse.into()), + 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 error::Error for ParseErr { + fn source(&self) -> Option<&(dyn 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. +/// +/// **Warning**: This API is not stable. +#[derive(Debug, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct NetworkState { + /// PeerId of the local node. + pub peer_id: String, + /// List of addresses the node is currently listening on. + pub listened_addresses: HashSet, + /// List of addresses the node knows it can be reached as. + pub external_addresses: HashSet, + /// List of node we're connected to. + pub connected_peers: HashMap, + /// List of node that we know of but that we're not connected to. + pub not_connected_peers: HashMap, + /// 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, + /// State of the peerset manager. + pub peerset: serde_json::Value, +} + +#[derive(Debug, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct NetworkStatePeer { + /// How we are connected to the node. + pub endpoint: NetworkStatePeerEndpoint, + /// Node information, as provided by the node itself. Can be empty if not known yet. + pub version_string: Option, + /// Latest ping duration with this node. + pub latest_ping_time: Option, + /// If true, the peer is "enabled", which means that we try to open Substrate-related protocols + /// with this peer. If false, we stick to Kademlia and/or other network-only protocols. + pub enabled: bool, + /// If true, the peer is "open", which means that we have a Substrate-related protocol + /// with this peer. + pub open: bool, + /// List of addresses known for this node. + pub known_addresses: HashSet, +} + +#[derive(Debug, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct NetworkStateNotConnectedPeer { + /// List of addresses known for this node. + pub known_addresses: HashSet, +} + +#[derive(Debug, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub enum NetworkStatePeerEndpoint { + /// We are dialing the given address. + Dialing(Multiaddr), + /// We are listening. + Listening { + /// Address we're listening on that received the connection. + listen_addr: Multiaddr, + /// Address data is sent back to. + send_back_addr: Multiaddr, + }, +} + +impl From for NetworkStatePeerEndpoint { + fn from(endpoint: ConnectedPoint) -> Self { + match endpoint { + ConnectedPoint::Dialer { address } => + NetworkStatePeerEndpoint::Dialing(address), + ConnectedPoint::Listener { listen_addr, send_back_addr } => + NetworkStatePeerEndpoint::Listening { + listen_addr: listen_addr, + send_back_addr: send_back_addr + } + } + } +} diff --git a/core/network-libp2p/src/secret.rs b/core/network-libp2p/src/secret.rs deleted file mode 100644 index 17bd053955e5bcb0f4e5ed50b18affde9c9274bb..0000000000000000000000000000000000000000 --- a/core/network-libp2p/src/secret.rs +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2018 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 crate::NetworkConfiguration; -use libp2p::secio; -use log::{trace, warn}; -use rand::Rng; -use std::io::{Error as IoError, ErrorKind as IoErrorKind, Read, Write}; -use std::{fs, path::Path}; - -// File where the private key is stored. -const SECRET_FILE: &str = "secret"; - -/// Obtains or generates the local private key using the configuration. -pub fn obtain_private_key_from_config( - config: &NetworkConfiguration -) -> Result { - obtain_private_key(&config.use_secret, &config.net_config_path) -} - -/// Obtains or generates the local private key using the configuration. -pub fn obtain_private_key( - secret: &Option<[u8; 32]>, - net_config_path: &Option, -) -> Result { - if let Some(ref secret) = secret { - // Key was specified in the configuration. - secio::SecioKeyPair::secp256k1_raw_key(&secret[..]) - .map_err(|err| IoError::new(IoErrorKind::InvalidData, err)) - } else { - if let Some(ref path) = net_config_path { - fs::create_dir_all(Path::new(path))?; - // Try fetch the key from a the file containing the secret. - let secret_path = Path::new(path).join(SECRET_FILE); - match load_private_key_from_file(&secret_path) { - Ok(s) => Ok(s), - Err(err) => { - // Failed to fetch existing file ; generate a new key - trace!(target: "sub-libp2p", - "Failed to load existing secret key file {:?}, generating new key ; err = {:?}", - secret_path, - err - ); - Ok(gen_key_and_try_write_to_file(&secret_path)) - } - } - - } else { - // No path in the configuration, nothing we can do except generate - // a new key. - let mut key: [u8; 32] = [0; 32]; - rand::rngs::EntropyRng::new().fill(&mut key); - Ok(secio::SecioKeyPair::secp256k1_raw_key(&key) - .expect("randomly-generated key with correct len should always be valid")) - } - } -} - -/// Tries to load a private key from a file located at the given path. -fn load_private_key_from_file

(path: P) - -> Result - where P: AsRef { - fs::File::open(path) - .and_then(|mut file| { - // We are in 2018 and there is still no method on `std::io::Read` - // that directly returns a `Vec`. - let mut buf = Vec::new(); - file.read_to_end(&mut buf).map(|_| buf) - }) - .and_then(|content| - secio::SecioKeyPair::secp256k1_raw_key(&content) - .map_err(|err| IoError::new(IoErrorKind::InvalidData, err)) - ) -} - -/// Generates a new secret key and tries to write it to the given file. -/// Doesn't error if we couldn't open or write to the file. -fn gen_key_and_try_write_to_file

(path: P) -> secio::SecioKeyPair - where P: AsRef { - let raw_key: [u8; 32] = rand::rngs::EntropyRng::new().gen(); - let secio_key = secio::SecioKeyPair::secp256k1_raw_key(&raw_key) - .expect("randomly-generated key with correct len should always be valid"); - - // And store the newly-generated key in the file if possible. - // Errors that happen while doing so are ignored. - match open_priv_key_file(&path) { - Ok(mut file) => - match file.write_all(&raw_key) { - Ok(()) => (), - Err(err) => warn!(target: "sub-libp2p", - "Failed to write secret key in file {:?} ; err = {:?}", - path.as_ref(), - err - ), - }, - Err(err) => warn!(target: "sub-libp2p", - "Failed to store secret key in file {:?} ; err = {:?}", - path.as_ref(), - err - ), - } - - secio_key -} - -/// Opens a file containing a private key in write mode. -#[cfg(unix)] -fn open_priv_key_file

(path: P) -> Result - where P: AsRef { - use std::os::unix::fs::OpenOptionsExt; - fs::OpenOptions::new() - .write(true) - .create_new(true) - .mode(256 | 128) // 0o600 in decimal - .open(path) -} -/// Opens a file containing a private key in write mode. -#[cfg(not(unix))] -fn open_priv_key_file

(path: P) -> Result - where P: AsRef { - fs::OpenOptions::new() - .write(true) - .create_new(true) - .open(path) -} diff --git a/core/network-libp2p/src/service_task.rs b/core/network-libp2p/src/service_task.rs index 9db3d41bd79eac16b7c78ba6b62f667ba4407278..12d05728695a28f51cb938fcac820143c0af49ec 100644 --- a/core/network-libp2p/src/service_task.rs +++ b/core/network-libp2p/src/service_task.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -15,50 +15,81 @@ // along with Substrate. If not, see . use crate::{ - behaviour::Behaviour, behaviour::BehaviourOut, secret::obtain_private_key_from_config, - transport + behaviour::Behaviour, behaviour::BehaviourOut, + transport, NetworkState, NetworkStatePeer, NetworkStateNotConnectedPeer }; -use crate::custom_proto::{CustomMessage, RegisteredProtocol, RegisteredProtocols}; -use crate::{Error, NetworkConfiguration, NodeIndex, ProtocolId, parse_str_addr}; +use crate::custom_proto::{CustomMessage, RegisteredProtocol}; +use crate::{NetworkConfiguration, NonReservedPeerMode, parse_str_addr}; use fnv::FnvHashMap; use futures::{prelude::*, Stream}; -use libp2p::{multiaddr::Protocol, Multiaddr, PeerId, build_multiaddr}; +use libp2p::{multiaddr::Protocol, Multiaddr, core::swarm::NetworkBehaviour, PeerId}; use libp2p::core::{Swarm, nodes::Substream, transport::boxed::Boxed, muxing::StreamMuxerBox}; use libp2p::core::nodes::ConnectedPoint; use log::{debug, info, warn}; -use std::collections::hash_map::Entry; use std::fs; -use std::io::{Error as IoError, ErrorKind as IoErrorKind}; -use std::net::SocketAddr; +use std::io::Error as IoError; use std::path::Path; use std::sync::Arc; use std::time::Duration; -use tokio_timer::Interval; /// Starts the substrate libp2p service. /// /// Returns a stream that must be polled regularly in order for the networking to function. -pub fn start_service( +pub fn start_service( config: NetworkConfiguration, - registered_custom: TProtos, -) -> Result, Error> -where TProtos: IntoIterator>, - TMessage: CustomMessage + Send + 'static { + registered_custom: RegisteredProtocol, +) -> Result<(Service, Arc), IoError> +where TMessage: CustomMessage + Send + 'static { 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), + } + } + + // 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); + } + } + + // Build the peerset. + let (peerset, peerset_receiver) = substrate_peerset::Peerset::from_config(substrate_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. - let local_private_key = obtain_private_key_from_config(&config)?; - let local_public_key = local_private_key.to_public_key(); - let local_peer_id = local_public_key.clone().into_peer_id(); + 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(); // Build the swarm. let (mut swarm, bandwidth) = { - let registered_custom = RegisteredProtocols(registered_custom.into_iter().collect()); - let behaviour = Behaviour::new(&config, local_public_key.clone(), registered_custom); - let (transport, bandwidth) = transport::build_transport(local_private_key); + let user_agent = format!("{} ({})", config.client_version, config.node_name); + let behaviour = Behaviour::new(user_agent, local_public, registered_custom, known_addresses, peerset_receiver); + let (transport, bandwidth) = transport::build_transport(local_identity); (Swarm::new(transport, behaviour, local_peer_id.clone()), bandwidth) }; @@ -78,55 +109,14 @@ where TProtos: IntoIterator>, Swarm::add_external_address(&mut swarm, addr.clone()); } - // Connect to the bootnodes. - for bootnode in config.boot_nodes.iter() { - match parse_str_addr(bootnode) { - Ok((peer_id, _)) => { - Swarm::dial(&mut swarm, peer_id); - }, - Err(_) => { - // If the format of the bootstrap node is not a multiaddr, try to parse it as - // a `SocketAddr`. This corresponds to the format `IP:PORT`. - let addr = match bootnode.parse::() { - Ok(SocketAddr::V4(socket)) => build_multiaddr![Ip4(*socket.ip()), Tcp(socket.port())], - Ok(SocketAddr::V6(socket)) => build_multiaddr![Ip6(*socket.ip()), Tcp(socket.port())], - _ => { - warn!(target: "sub-libp2p", "Not a valid bootnode address: {}", bootnode); - continue - } - }; - - info!(target: "sub-libp2p", "Dialing {} with no peer id. Keep in mind that doing \ - so is vulnerable to man-in-the-middle attacks.", addr); - if let Err(addr) = Swarm::dial_addr(&mut swarm, addr) { - warn!(target: "sub-libp2p", "Bootstrap address not supported: {}", addr) - } - }, - } - } - - // Initialize the reserved peers. - for reserved in config.reserved_nodes.iter() { - if let Ok((peer_id, addr)) = parse_str_addr(reserved) { - swarm.add_reserved_peer(peer_id.clone(), addr); - Swarm::dial(&mut swarm, peer_id); - } else { - warn!(target: "sub-libp2p", "Not a valid reserved node address: {}", reserved); - } - } - - debug!(target: "sub-libp2p", "Topology started with {} entries", - swarm.num_topology_peers()); - - Ok(Service { + let service = Service { swarm, bandwidth, nodes_info: Default::default(), - index_by_id: Default::default(), - next_node_id: 1, - cleanup: Interval::new_interval(Duration::from_secs(60)), injected_events: Vec::new(), - }) + }; + + Ok((service, peerset)) } /// Event produced by the service. @@ -134,10 +124,8 @@ where TProtos: IntoIterator>, pub enum ServiceEvent { /// A custom protocol substream has been opened with a node. OpenedCustomProtocol { - /// Index of the node. - node_index: NodeIndex, - /// Protocol that has been opened. - protocol: ProtocolId, + /// Identity of the node. + peer_id: PeerId, /// Version of the protocol that was opened. version: u8, /// Node debug info @@ -146,32 +134,16 @@ pub enum ServiceEvent { /// A custom protocol substream has been closed. ClosedCustomProtocol { - /// Index of the node. - node_index: NodeIndex, - /// Protocol that has been closed. - protocol: ProtocolId, - /// Node debug info - debug_info: String, - }, - - /// Sustom protocol substreams has been closed. - /// - /// Same as `ClosedCustomProtocol` but with multiple protocols. - ClosedCustomProtocols { - /// Index of the node. - node_index: NodeIndex, - /// Protocols that have been closed. - protocols: Vec, + /// Identity of the node. + peer_id: PeerId, /// Node debug info debug_info: String, }, /// Receives a message on a custom protocol stream. CustomMessage { - /// Index of the node. - node_index: NodeIndex, - /// Protocol which generated the message. - protocol_id: ProtocolId, + /// Identity of the node. + peer_id: PeerId, /// Message that has been received. message: TMessage, }, @@ -179,9 +151,7 @@ pub enum ServiceEvent { /// The substream with a node is clogged. We should avoid sending data to it if possible. Clogged { /// Index of the node. - node_index: NodeIndex, - /// Protocol which generated the message. - protocol_id: ProtocolId, + peer_id: PeerId, /// Copy of the messages that are within the buffer, for further diagnostic. messages: Vec, }, @@ -196,17 +166,7 @@ pub struct Service where TMessage: CustomMessage { bandwidth: Arc, /// Information about all the nodes we're connected to. - nodes_info: FnvHashMap, - - /// Opposite of `nodes_info`. - index_by_id: FnvHashMap, - - /// Next index to assign to a node. - next_node_id: NodeIndex, - - /// Stream that fires when we need to cleanup and flush the topology, and cleanup the disabled - /// peers. - cleanup: Interval, + nodes_info: FnvHashMap, /// Events to produce on the Stream. injected_events: Vec>, @@ -215,16 +175,60 @@ pub struct Service where TMessage: CustomMessage { /// Information about a node we're connected to. #[derive(Debug)] struct NodeInfo { - /// Hash of the public key of the node. - peer_id: PeerId, /// How we're connected to the node. endpoint: ConnectedPoint, /// Version reported by the remote, or `None` if unknown. client_version: Option, + /// Latest ping time with this node. + latest_ping: Option, } impl Service where TMessage: CustomMessage + Send + 'static { + /// Returns a struct containing tons of useful information about the network. + pub fn state(&mut self) -> NetworkState { + let connected_peers = { + let swarm = &mut self.swarm; + self.nodes_info.iter().map(move |(peer_id, info)| { + let known_addresses = NetworkBehaviour::addresses_of_peer(&mut **swarm, peer_id) + .into_iter().collect(); + + (peer_id.to_base58(), NetworkStatePeer { + endpoint: info.endpoint.clone().into(), + version_string: info.client_version.clone(), + latest_ping_time: info.latest_ping, + enabled: swarm.is_enabled(&peer_id), + open: swarm.is_open(&peer_id), + known_addresses, + }) + }).collect() + }; + + let not_connected_peers = { + let swarm = &mut self.swarm; + let nodes_info = &self.nodes_info; + let list = swarm.known_peers().filter(|p| !nodes_info.contains_key(p)) + .cloned().collect::>(); + list.into_iter().map(move |peer_id| { + (peer_id.to_base58(), NetworkStateNotConnectedPeer { + known_addresses: NetworkBehaviour::addresses_of_peer(&mut **swarm, &peer_id) + .into_iter().collect(), + }) + }).collect() + }; + + NetworkState { + peer_id: Swarm::local_peer_id(&self.swarm).to_base58(), + listened_addresses: Swarm::listeners(&self.swarm).cloned().collect(), + external_addresses: Swarm::external_addresses(&self.swarm).cloned().collect(), + average_download_per_sec: self.bandwidth.average_download_per_sec(), + average_upload_per_sec: self.bandwidth.average_upload_per_sec(), + connected_peers, + not_connected_peers, + peerset: self.swarm.peerset_debug_info(), + } + } + /// Returns an iterator that produces the list of addresses we're listening on. #[inline] pub fn listeners(&self) -> impl Iterator { @@ -251,50 +255,19 @@ where TMessage: CustomMessage + Send + 'static { /// Returns the list of all the peers we are connected to. #[inline] - pub fn connected_peers<'a>(&'a self) -> impl Iterator + 'a { - self.nodes_info.keys().cloned() - } - - /// Try to add a reserved peer. - pub fn add_reserved_peer(&mut self, peer_id: PeerId, addr: Multiaddr) { - self.swarm.add_reserved_peer(peer_id, addr); - } - - /// Try to remove a reserved peer. - /// - /// If we are in reserved mode and we were connected to a node with this peer ID, then this - /// method will disconnect it. - pub fn remove_reserved_peer(&mut self, peer_id: PeerId) { - self.swarm.remove_reserved_peer(peer_id); - } - - /// Start accepting all peers again if we weren't. - #[inline] - pub fn accept_unreserved_peers(&mut self) { - self.swarm.accept_unreserved_peers(); - } - - /// Start refusing non-reserved nodes. Disconnects the nodes that we are connected to that - /// aren't reserved. - pub fn deny_unreserved_peers(&mut self) { - self.swarm.deny_unreserved_peers(); - } - - /// Returns the `PeerId` of a node. - #[inline] - pub fn peer_id_of_node(&self, node_index: NodeIndex) -> Option<&PeerId> { - self.nodes_info.get(&node_index).map(|info| &info.peer_id) + pub fn connected_peers<'a>(&'a self) -> impl Iterator + 'a { + self.nodes_info.keys() } /// Returns the way we are connected to a node. #[inline] - pub fn node_endpoint(&self, node_index: NodeIndex) -> Option<&ConnectedPoint> { - self.nodes_info.get(&node_index).map(|info| &info.endpoint) + pub fn node_endpoint(&self, peer_id: &PeerId) -> Option<&ConnectedPoint> { + self.nodes_info.get(peer_id).map(|info| &info.endpoint) } /// Returns the client version reported by a node. - pub fn node_client_version(&self, node_index: NodeIndex) -> Option<&str> { - self.nodes_info.get(&node_index) + pub fn node_client_version(&self, peer_id: &PeerId) -> Option<&str> { + self.nodes_info.get(peer_id) .and_then(|info| info.client_version.as_ref().map(|s| &s[..])) } @@ -304,113 +277,72 @@ where TMessage: CustomMessage + Send + 'static { /// invalid. pub fn send_custom_message( &mut self, - node_index: NodeIndex, - protocol: ProtocolId, + peer_id: &PeerId, message: TMessage ) { - if let Some(peer_id) = self.nodes_info.get(&node_index).map(|info| &info.peer_id) { - self.swarm.send_custom_message(peer_id, protocol, message); - } else { - warn!(target: "sub-libp2p", "Tried to send message to unknown node: {:}", node_index); - } - } - - /// Disconnects a peer and bans it for a little while. - /// - /// Same as `drop_node`, except that the same peer will not be able to reconnect later. - #[inline] - pub fn ban_node(&mut self, node_index: NodeIndex) { - if let Some(info) = self.nodes_info.get(&node_index) { - info!(target: "sub-libp2p", "Banned {:?} (#{:?}, {:?}, {:?})", info.peer_id, - node_index, info.endpoint, info.client_version); - self.swarm.ban_node(info.peer_id.clone()); - } + self.swarm.send_custom_message(peer_id, message); } /// Disconnects a peer. /// /// This is asynchronous and will not immediately close the peer. /// Corresponding closing events will be generated once the closing actually happens. - #[inline] - pub fn drop_node(&mut self, node_index: NodeIndex) { - if let Some(info) = self.nodes_info.get(&node_index) { - debug!(target: "sub-libp2p", "Dropping {:?} on purpose (#{:?}, {:?}, {:?})", - info.peer_id, node_index, info.endpoint, info.client_version); - self.swarm.drop_node(&info.peer_id); + pub fn drop_node(&mut self, peer_id: &PeerId) { + if let Some(info) = self.nodes_info.get(peer_id) { + debug!(target: "sub-libp2p", "Dropping {:?} on purpose ({:?}, {:?})", + peer_id, info.endpoint, info.client_version); + self.swarm.drop_node(peer_id); } } + /// Adds a hard-coded address for the given peer, that never expires. + pub fn add_known_address(&mut self, peer_id: PeerId, addr: Multiaddr) { + self.swarm.add_known_address(peer_id, addr) + } + /// Get debug info for a given peer. - pub fn peer_debug_info(&self, who: NodeIndex) -> String { - if let Some(info) = self.nodes_info.get(&who) { - format!("{:?} (version: {:?}) through {:?}", info.peer_id, info.client_version, info.endpoint) + pub fn peer_debug_info(&self, who: &PeerId) -> String { + if let Some(info) = self.nodes_info.get(who) { + format!("{:?} (version: {:?}) through {:?}", who, info.client_version, info.endpoint) } else { "unknown".to_string() } } - /// Returns the `NodeIndex` of a peer, or assigns one if none exists. - fn index_of_peer_or_assign(&mut self, peer: PeerId, endpoint: ConnectedPoint) -> NodeIndex { - match self.index_by_id.entry(peer) { - Entry::Occupied(entry) => { - let id = *entry.get(); - self.nodes_info.insert(id, NodeInfo { - peer_id: entry.key().clone(), - endpoint, - client_version: None, - }); - id - }, - Entry::Vacant(entry) => { - let id = self.next_node_id; - self.next_node_id += 1; - self.nodes_info.insert(id, NodeInfo { - peer_id: entry.key().clone(), - endpoint, - client_version: None, - }); - entry.insert(id); - id - }, - } - } - /// Polls for what happened on the network. fn poll_swarm(&mut self) -> Poll>, IoError> { loop { match self.swarm.poll() { - Ok(Async::Ready(Some(BehaviourOut::CustomProtocolOpen { protocol_id, peer_id, version, endpoint }))) => { - debug!(target: "sub-libp2p", "Opened custom protocol with {:?}", peer_id); - let node_index = self.index_of_peer_or_assign(peer_id, endpoint); + Ok(Async::Ready(Some(BehaviourOut::CustomProtocolOpen { peer_id, version, endpoint }))) => { + self.nodes_info.insert(peer_id.clone(), NodeInfo { + endpoint, + client_version: None, + latest_ping: None, + }); + let debug_info = self.peer_debug_info(&peer_id); break Ok(Async::Ready(Some(ServiceEvent::OpenedCustomProtocol { - node_index, - protocol: protocol_id, + peer_id, version, - debug_info: self.peer_debug_info(node_index), + debug_info, }))) } - Ok(Async::Ready(Some(BehaviourOut::CustomProtocolClosed { protocol_id, peer_id, result }))) => { - debug!(target: "sub-libp2p", "Custom protocol with {:?} closed: {:?}", peer_id, result); - let node_index = *self.index_by_id.get(&peer_id).expect("index_by_id is always kept in sync with the state of the behaviour"); + Ok(Async::Ready(Some(BehaviourOut::CustomProtocolClosed { peer_id, .. }))) => { + let debug_info = self.peer_debug_info(&peer_id); + self.nodes_info.remove(&peer_id); break Ok(Async::Ready(Some(ServiceEvent::ClosedCustomProtocol { - node_index, - protocol: protocol_id, - debug_info: self.peer_debug_info(node_index), + peer_id, + debug_info, }))) } - Ok(Async::Ready(Some(BehaviourOut::CustomMessage { protocol_id, peer_id, message }))) => { - let node_index = *self.index_by_id.get(&peer_id).expect("index_by_id is always kept in sync with the state of the behaviour"); + Ok(Async::Ready(Some(BehaviourOut::CustomMessage { peer_id, message }))) => { break Ok(Async::Ready(Some(ServiceEvent::CustomMessage { - node_index, - protocol_id, + peer_id, message, }))) } - Ok(Async::Ready(Some(BehaviourOut::Clogged { protocol_id, peer_id, messages }))) => { - let node_index = *self.index_by_id.get(&peer_id).expect("index_by_id is always kept in sync with the state of the behaviour"); + Ok(Async::Ready(Some(BehaviourOut::Clogged { peer_id, messages }))) => { break Ok(Async::Ready(Some(ServiceEvent::Clogged { - node_index, - protocol_id, + peer_id, messages, }))) } @@ -418,10 +350,16 @@ where TMessage: CustomMessage + Send + 'static { // Contrary to the other events, this one can happen even on nodes which don't // have any open custom protocol slot. Therefore it is not necessarily in the // list. - if let Some(id) = self.index_by_id.get(&peer_id) { - self.nodes_info.get_mut(id) - .expect("index_by_id and nodes_info are always kept in sync; QED") - .client_version = Some(info.agent_version); + if let Some(n) = self.nodes_info.get_mut(&peer_id) { + n.client_version = Some(info.agent_version); + } + } + Ok(Async::Ready(Some(BehaviourOut::PingSuccess { peer_id, ping_time }))) => { + // Contrary to the other events, this one can happen even on nodes which don't + // have any open custom protocol slot. Therefore it is not necessarily in the + // list. + if let Some(n) = self.nodes_info.get_mut(&peer_id) { + n.latest_ping = Some(ping_time); } } Ok(Async::NotReady) => break Ok(Async::NotReady), @@ -430,40 +368,6 @@ where TMessage: CustomMessage + Send + 'static { } } } - - /// Polls the stream that fires when we need to cleanup and flush the topology. - fn poll_cleanup(&mut self) -> Poll>, IoError> { - loop { - match self.cleanup.poll() { - Ok(Async::NotReady) => return Ok(Async::NotReady), - Ok(Async::Ready(Some(_))) => { - debug!(target: "sub-libp2p", "Cleaning and flushing topology"); - self.swarm.cleanup(); - if let Err(err) = self.swarm.flush_topology() { - warn!(target: "sub-libp2p", "Failed to flush topology: {:?}", err); - } - debug!(target: "sub-libp2p", "Topology now contains {} nodes", - self.swarm.num_topology_peers()); - } - Ok(Async::Ready(None)) => { - warn!(target: "sub-libp2p", "Topology flush stream ended unexpectedly"); - return Ok(Async::Ready(None)) - } - Err(err) => { - warn!(target: "sub-libp2p", "Topology flush stream errored: {:?}", err); - return Err(IoError::new(IoErrorKind::Other, err)) - } - } - } - } -} - -impl Drop for Service where TMessage: CustomMessage { - fn drop(&mut self) { - if let Err(err) = self.swarm.flush_topology() { - warn!(target: "sub-libp2p", "Failed to flush topology: {:?}", err); - } - } } impl Stream for Service where TMessage: CustomMessage + Send + 'static { @@ -480,11 +384,6 @@ impl Stream for Service where TMessage: CustomMessage + Send Async::NotReady => (), } - match self.poll_cleanup()? { - Async::Ready(value) => return Ok(Async::Ready(value)), - Async::NotReady => (), - } - // The only way we reach this is if we went through all the `NotReady` paths above, // ensuring the current task is registered everywhere. Ok(Async::NotReady) diff --git a/core/network-libp2p/src/traits.rs b/core/network-libp2p/src/traits.rs deleted file mode 100644 index fc57a9aef3fab8665920f483dfc7548b8a2cdc8c..0000000000000000000000000000000000000000 --- a/core/network-libp2p/src/traits.rs +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2015-2018 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::{fmt, iter, net::Ipv4Addr, str}; -use libp2p::{multiaddr::Protocol, Multiaddr, PeerId}; - -/// Protocol / handler id -pub type ProtocolId = [u8; 3]; - -/// Node public key -pub type NodeId = PeerId; - -/// Local (temporary) peer session ID. -pub type NodeIndex = usize; - -/// secio secret key; -pub type Secret = [u8; 32]; - -/// Network service configuration -#[derive(Debug, PartialEq, Clone)] -pub struct NetworkConfiguration { - /// Directory path to store general network configuration. None means nothing will be saved - pub config_path: Option, - /// Directory path to store network-specific configuration. None means nothing will be saved - pub net_config_path: Option, - /// Multiaddresses to listen for incoming connections. - pub listen_addresses: Vec, - /// Multiaddresses to advertise. Detected automatically if empty. - pub public_addresses: Vec, - /// List of initial node addresses - pub boot_nodes: Vec, - /// Use provided node key instead of default - pub use_secret: Option, - /// Maximum allowed number of incoming connections - pub in_peers: u32, - /// Number of outgoing connections we're trying to maintain - pub out_peers: u32, - /// List of reserved node addresses. - pub reserved_nodes: Vec, - /// The non-reserved peer mode. - pub non_reserved_mode: NonReservedPeerMode, - /// Client identifier. Sent over the wire for debugging purposes. - pub client_version: String, - /// Name of the node. Sent over the wire for debugging purposes. - pub node_name: String, -} - -impl Default for NetworkConfiguration { - fn default() -> Self { - NetworkConfiguration::new() - } -} - -impl NetworkConfiguration { - /// Create a new instance of default settings. - pub fn new() -> Self { - NetworkConfiguration { - config_path: None, - net_config_path: None, - listen_addresses: Vec::new(), - public_addresses: Vec::new(), - boot_nodes: Vec::new(), - use_secret: None, - in_peers: 25, - out_peers: 75, - reserved_nodes: Vec::new(), - non_reserved_mode: NonReservedPeerMode::Accept, - client_version: "unknown".into(), - node_name: "unknown".into(), - } - } - - /// Create new default configuration for localhost-only connection with random port (useful for testing) - 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))) - .collect() - ]; - config - } -} - -/// The severity of misbehaviour of a peer that is reported. -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Severity { - /// Peer is timing out. Could be bad connectivity of overload of work on either of our sides. - Timeout, - /// Peer has been notably useless. E.g. unable to answer a request that we might reasonably consider - /// it could answer. - Useless(String), - /// Peer has behaved in an invalid manner. This doesn't necessarily need to be Byzantine, but peer - /// must have taken concrete action in order to behave in such a way which is wantanly invalid. - Bad(String), -} - -impl fmt::Display for Severity { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match self { - Severity::Timeout => write!(fmt, "Timeout"), - Severity::Useless(r) => write!(fmt, "Useless ({})", r), - Severity::Bad(r) => write!(fmt, "Bad ({})", r), - } - } -} - -/// Non-reserved peer modes. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum NonReservedPeerMode { - /// Accept them. This is the default. - Accept, - /// Deny them. - Deny, -} - -impl NonReservedPeerMode { - /// Attempt to parse the peer mode from a string. - pub fn parse(s: &str) -> Option { - match s { - "accept" => Some(NonReservedPeerMode::Accept), - "deny" => Some(NonReservedPeerMode::Deny), - _ => None, - } - } -} diff --git a/core/network-libp2p/src/transport.rs b/core/network-libp2p/src/transport.rs index c095602a11ede122676e26a73d760318f6bff6cc..404fdb6bdaad8d9244ee1dca62ac8e2aa70863d3 100644 --- a/core/network-libp2p/src/transport.rs +++ b/core/network-libp2p/src/transport.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ use futures::prelude::*; use libp2p::{ InboundUpgradeExt, OutboundUpgradeExt, PeerId, Transport, - mplex, secio, yamux, tcp, dns, websocket, bandwidth + mplex, identity, secio, yamux, tcp, dns, websocket, bandwidth }; use libp2p::core::{self, transport::boxed::Boxed, muxing::StreamMuxerBox}; use std::{io, sync::Arc, time::Duration, usize}; @@ -29,7 +29,7 @@ pub use self::bandwidth::BandwidthSinks; /// Returns a `BandwidthSinks` object that allows querying the average bandwidth produced by all /// the connections spawned with this transport. pub fn build_transport( - local_private_key: secio::SecioKeyPair + keypair: identity::Keypair ) -> (Boxed<(PeerId, StreamMuxerBox), io::Error>, Arc) { let mut mplex_config = mplex::MplexConfig::new(); mplex_config.max_buffer_len_behaviour(mplex::MaxBufferBehaviour::Block); @@ -42,7 +42,7 @@ pub fn build_transport( // TODO: rework the transport creation (https://github.com/libp2p/rust-libp2p/issues/783) let transport = transport - .with_upgrade(secio::SecioConfig::new(local_private_key)) + .with_upgrade(secio::SecioConfig::new(keypair)) .and_then(move |out, endpoint| { let peer_id = out.remote_key.into_peer_id(); let peer_id2 = peer_id.clone(); diff --git a/core/network-libp2p/tests/test.rs b/core/network-libp2p/tests/test.rs index 40b9598f5441cfb97b1453f99d460513a7695dbe..437f65118455d648129c5027f06ac64e8858a853 100644 --- a/core/network-libp2p/tests/test.rs +++ b/core/network-libp2p/tests/test.rs @@ -16,8 +16,8 @@ use futures::{future, stream, prelude::*, try_ready}; use rand::seq::SliceRandom; -use std::{io, iter}; -use substrate_network_libp2p::{CustomMessage, Protocol, ServiceEvent, build_multiaddr}; +use std::io; +use substrate_network_libp2p::{CustomMessage, multiaddr::Protocol, ServiceEvent, build_multiaddr}; /// Builds two services. The second one and further have the first one as its bootstrap node. /// This is to be used only for testing, and a panic will happen if something goes wrong. @@ -41,7 +41,7 @@ fn build_nodes(num: usize) -> Vec> }; let proto = substrate_network_libp2p::RegisteredProtocol::new(*b"tst", &[1]); - result.push(substrate_network_libp2p::start_service(config, iter::once(proto)).unwrap()); + result.push(substrate_network_libp2p::start_service(config, proto).unwrap().0); } result @@ -58,8 +58,7 @@ fn basic_two_nodes_connectivity() { let fut1 = future::poll_fn(move || -> io::Result<_> { match try_ready!(service1.poll()) { - Some(ServiceEvent::OpenedCustomProtocol { protocol, version, .. }) => { - assert_eq!(protocol, *b"tst"); + Some(ServiceEvent::OpenedCustomProtocol { version, .. }) => { assert_eq!(version, 1); Ok(Async::Ready(())) }, @@ -69,8 +68,7 @@ fn basic_two_nodes_connectivity() { let fut2 = future::poll_fn(move || -> io::Result<_> { match try_ready!(service2.poll()) { - Some(ServiceEvent::OpenedCustomProtocol { protocol, version, .. }) => { - assert_eq!(protocol, *b"tst"); + Some(ServiceEvent::OpenedCustomProtocol { version, .. }) => { assert_eq!(version, 1); Ok(Async::Ready(())) }, @@ -101,9 +99,9 @@ fn two_nodes_transfer_lots_of_packets() { let fut1 = future::poll_fn(move || -> io::Result<_> { loop { match try_ready!(service1.poll()) { - Some(ServiceEvent::OpenedCustomProtocol { node_index, protocol, .. }) => { + Some(ServiceEvent::OpenedCustomProtocol { peer_id, .. }) => { for n in 0 .. NUM_PACKETS { - service1.send_custom_message(node_index, protocol, vec![(n % 256) as u8]); + service1.send_custom_message(&peer_id, vec![(n % 256) as u8]); } }, _ => panic!(), @@ -229,9 +227,9 @@ fn basic_two_nodes_requests_in_parallel() { let fut1 = future::poll_fn(move || -> io::Result<_> { loop { match try_ready!(service1.poll()) { - Some(ServiceEvent::OpenedCustomProtocol { node_index, protocol, .. }) => { + Some(ServiceEvent::OpenedCustomProtocol { peer_id, .. }) => { for msg in to_send.drain(..) { - service1.send_custom_message(node_index, protocol, msg); + service1.send_custom_message(&peer_id, msg); } }, _ => panic!(), diff --git a/core/network/Cargo.toml b/core/network/Cargo.toml index b6d51a27d11e874c5a94029e36c6080f27d345b4..bed1946fa8f72655f50bc2e33c18f25b561a8e91 100644 --- a/core/network/Cargo.toml +++ b/core/network/Cargo.toml @@ -25,9 +25,9 @@ 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 = "3.0" -parity-codec-derive = "3.0" +parity-codec = { version = "3.2", features = ["derive"] } network_libp2p = { package = "substrate-network-libp2p", path = "../../core/network-libp2p" } +peerset = { package = "substrate-peerset", path = "../../core/peerset" } tokio = "0.1.11" keyring = { package = "substrate-keyring", path = "../../core/keyring", optional = true } test_client = { package = "substrate-test-client", path = "../../core/test-client", optional = true } diff --git a/core/network/src/blocks.rs b/core/network/src/blocks.rs index b0fadca7dae8656d29abecf5d7a137df44c3aba9..60c6886f09f27c210876825bcc4fa364235676e2 100644 --- a/core/network/src/blocks.rs +++ b/core/network/src/blocks.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -20,7 +20,7 @@ use std::ops::Range; use std::collections::{HashMap, BTreeMap}; use std::collections::hash_map::Entry; use log::trace; -use network_libp2p::NodeIndex; +use network_libp2p::PeerId; use runtime_primitives::traits::{Block as BlockT, NumberFor, As}; use crate::message; @@ -32,7 +32,7 @@ pub struct BlockData { /// The Block Message from the wire pub block: message::BlockData, /// The peer, we received this from - pub origin: Option, + pub origin: Option, } #[derive(Debug)] @@ -58,7 +58,7 @@ impl BlockRangeState { pub struct BlockCollection { /// Downloaded blocks. blocks: BTreeMap, BlockRangeState>, - peer_requests: HashMap>, + peer_requests: HashMap>, } impl BlockCollection { @@ -77,7 +77,7 @@ impl BlockCollection { } /// Insert a set of blocks into collection. - pub fn insert(&mut self, start: NumberFor, blocks: Vec>, who: NodeIndex) { + pub fn insert(&mut self, start: NumberFor, blocks: Vec>, who: PeerId) { if blocks.is_empty() { return; } @@ -96,11 +96,11 @@ impl BlockCollection { } self.blocks.insert(start, BlockRangeState::Complete(blocks.into_iter() - .map(|b| BlockData { origin: Some(who), block: b }).collect())); + .map(|b| BlockData { origin: Some(who.clone()), block: b }).collect())); } /// Returns a set of block hashes that require a header download. The returned set is marked as being downloaded. - pub fn needed_blocks(&mut self, who: NodeIndex, count: usize, peer_best: NumberFor, common: NumberFor) -> Option>> { + pub fn needed_blocks(&mut self, who: PeerId, count: usize, peer_best: NumberFor, common: NumberFor) -> Option>> { // First block number that we need to download let first_different = common + As::sa(1); let count = As::sa(count as u64); @@ -166,8 +166,8 @@ impl BlockCollection { drained } - pub fn clear_peer_download(&mut self, who: NodeIndex) { - match self.peer_requests.entry(who) { + pub fn clear_peer_download(&mut self, who: &PeerId) { + match self.peer_requests.entry(who.clone()) { Entry::Occupied(entry) => { let start = entry.remove(); let remove = match self.blocks.get_mut(&start) { @@ -195,7 +195,7 @@ impl BlockCollection { #[cfg(test)] mod test { use super::{BlockCollection, BlockData, BlockRangeState}; - use crate::message; + use crate::{message, PeerId}; use runtime_primitives::testing::{Block as RawBlock, ExtrinsicWrapper}; use primitives::H256; @@ -221,7 +221,7 @@ mod test { fn create_clear() { let mut bc = BlockCollection::new(); assert!(is_empty(&bc)); - bc.insert(1, generate_blocks(100), 0); + bc.insert(1, generate_blocks(100), PeerId::random()); assert!(!is_empty(&bc)); bc.clear(); assert!(is_empty(&bc)); @@ -231,43 +231,43 @@ mod test { fn insert_blocks() { let mut bc = BlockCollection::new(); assert!(is_empty(&bc)); - let peer0 = 0; - let peer1 = 1; - let peer2 = 2; + let peer0 = PeerId::random(); + let peer1 = PeerId::random(); + let peer2 = PeerId::random(); let blocks = generate_blocks(150); - assert_eq!(bc.needed_blocks(peer0, 40, 150, 0), Some(1 .. 41)); - assert_eq!(bc.needed_blocks(peer1, 40, 150, 0), Some(41 .. 81)); - assert_eq!(bc.needed_blocks(peer2, 40, 150, 0), Some(81 .. 121)); + assert_eq!(bc.needed_blocks(peer0.clone(), 40, 150, 0), Some(1 .. 41)); + assert_eq!(bc.needed_blocks(peer1.clone(), 40, 150, 0), Some(41 .. 81)); + assert_eq!(bc.needed_blocks(peer2.clone(), 40, 150, 0), Some(81 .. 121)); - bc.clear_peer_download(peer1); - bc.insert(41, blocks[41..81].to_vec(), peer1); + bc.clear_peer_download(&peer1); + bc.insert(41, blocks[41..81].to_vec(), peer1.clone()); assert_eq!(bc.drain(1), vec![]); - assert_eq!(bc.needed_blocks(peer1, 40, 150, 0), Some(121 .. 151)); - bc.clear_peer_download(peer0); - bc.insert(1, blocks[1..11].to_vec(), peer0); + assert_eq!(bc.needed_blocks(peer1.clone(), 40, 150, 0), Some(121 .. 151)); + bc.clear_peer_download(&peer0); + bc.insert(1, blocks[1..11].to_vec(), peer0.clone()); - assert_eq!(bc.needed_blocks(peer0, 40, 150, 0), Some(11 .. 41)); - assert_eq!(bc.drain(1), blocks[1..11].iter().map(|b| BlockData { block: b.clone(), origin: Some(0) }).collect::>()); + assert_eq!(bc.needed_blocks(peer0.clone(), 40, 150, 0), Some(11 .. 41)); + assert_eq!(bc.drain(1), blocks[1..11].iter().map(|b| BlockData { block: b.clone(), origin: Some(peer0.clone()) }).collect::>()); - bc.clear_peer_download(peer0); - bc.insert(11, blocks[11..41].to_vec(), peer0); + bc.clear_peer_download(&peer0); + bc.insert(11, blocks[11..41].to_vec(), peer0.clone()); let drained = bc.drain(12); - assert_eq!(drained[..30], blocks[11..41].iter().map(|b| BlockData { block: b.clone(), origin: Some(0) }).collect::>()[..]); - assert_eq!(drained[30..], blocks[41..81].iter().map(|b| BlockData { block: b.clone(), origin: Some(1) }).collect::>()[..]); + assert_eq!(drained[..30], blocks[11..41].iter().map(|b| BlockData { block: b.clone(), origin: Some(peer0.clone()) }).collect::>()[..]); + assert_eq!(drained[30..], blocks[41..81].iter().map(|b| BlockData { block: b.clone(), origin: Some(peer1.clone()) }).collect::>()[..]); - bc.clear_peer_download(peer2); - assert_eq!(bc.needed_blocks(peer2, 40, 150, 80), Some(81 .. 121)); - bc.clear_peer_download(peer2); - bc.insert(81, blocks[81..121].to_vec(), peer2); - bc.clear_peer_download(peer1); - bc.insert(121, blocks[121..150].to_vec(), peer1); + bc.clear_peer_download(&peer2); + assert_eq!(bc.needed_blocks(peer2.clone(), 40, 150, 80), Some(81 .. 121)); + bc.clear_peer_download(&peer2); + bc.insert(81, blocks[81..121].to_vec(), peer2.clone()); + bc.clear_peer_download(&peer1); + bc.insert(121, blocks[121..150].to_vec(), peer1.clone()); assert_eq!(bc.drain(80), vec![]); let drained = bc.drain(81); - assert_eq!(drained[..40], blocks[81..121].iter().map(|b| BlockData { block: b.clone(), origin: Some(2) }).collect::>()[..]); - assert_eq!(drained[40..], blocks[121..150].iter().map(|b| BlockData { block: b.clone(), origin: Some(1) }).collect::>()[..]); + assert_eq!(drained[..40], blocks[81..121].iter().map(|b| BlockData { block: b.clone(), origin: Some(peer2.clone()) }).collect::>()[..]); + assert_eq!(drained[40..], blocks[121..150].iter().map(|b| BlockData { block: b.clone(), origin: Some(peer1.clone()) }).collect::>()[..]); } #[test] @@ -280,7 +280,8 @@ mod test { let blocks = generate_blocks(10).into_iter().map(|b| BlockData { block: b, origin: None }).collect(); bc.blocks.insert(114305, BlockRangeState::Complete(blocks)); - assert_eq!(bc.needed_blocks(0, 128, 10000, 000), Some(1 .. 100)); - assert_eq!(bc.needed_blocks(0, 128, 10000, 600), Some(100 + 128 .. 100 + 128 + 128)); + let peer0 = PeerId::random(); + assert_eq!(bc.needed_blocks(peer0.clone(), 128, 10000, 000), Some(1 .. 100)); + assert_eq!(bc.needed_blocks(peer0.clone(), 128, 10000, 600), Some(100 + 128 .. 100 + 128 + 128)); } } diff --git a/core/network/src/chain.rs b/core/network/src/chain.rs index 51057df4dc9b5bcc639c086730be9adae0d7dce4..87c0dca9c1306e14ccd85ea1274f44dece25789c 100644 --- a/core/network/src/chain.rs +++ b/core/network/src/chain.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/network/src/config.rs b/core/network/src/config.rs index b7a8ede0ec31ce02edce3235bee2dee3cc607d65..2491fc21c4c0746747a6a49d8341a3393a886c88 100644 --- a/core/network/src/config.rs +++ b/core/network/src/config.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ //! Configuration for the networking layer of Substrate. -pub use network_libp2p::{NonReservedPeerMode, NetworkConfiguration, Secret}; +pub use network_libp2p::{NonReservedPeerMode, NetworkConfiguration, NodeKeyConfig, Secret}; use bitflags::bitflags; use crate::chain::Client; diff --git a/core/network/src/consensus_gossip.rs b/core/network/src/consensus_gossip.rs index 720cf55a67b75e3697bcd96b80b6274cc7b6c9bc..3f6073f1d4e2a51d2ec18af9e2ce3f420d4f53ae 100644 --- a/core/network/src/consensus_gossip.rs +++ b/core/network/src/consensus_gossip.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -19,12 +19,11 @@ use std::collections::{HashMap, HashSet}; use std::sync::Arc; -use std::time::{Instant, Duration}; use log::{trace, debug}; use futures::sync::mpsc; use rand::{self, seq::SliceRandom}; use lru_cache::LruCache; -use network_libp2p::{Severity, NodeIndex}; +use network_libp2p::{Severity, PeerId}; use runtime_primitives::traits::{Block as BlockT, Hash, HashFor}; pub use crate::message::generic::{Message, ConsensusMessage}; use crate::protocol::Context; @@ -32,7 +31,6 @@ use crate::config::Roles; use crate::ConsensusEngineId; // FIXME: Add additional spam/DoS attack protection: https://github.com/paritytech/substrate/issues/1115 -const MESSAGE_LIFETIME: Duration = Duration::from_secs(120); const KNOWN_MESSAGES_CACHE_SIZE: usize = 4096; struct PeerConsensus { @@ -40,17 +38,25 @@ struct PeerConsensus { is_authority: bool, } +#[derive(Clone, Copy)] +enum Status { + Live, + Future, +} + struct MessageEntry { message_hash: B::Hash, topic: B::Hash, message: ConsensusMessage, - timestamp: Instant, + status: Status, } /// Message validation result. pub enum ValidationResult { /// Message is valid with this topic. Valid(H), + /// Message is future with this topic. + Future(H), /// Invalid message. Invalid, /// Obsolete message. @@ -61,12 +67,20 @@ pub enum ValidationResult { pub trait Validator { /// Validate consensus message. fn validate(&self, data: &[u8]) -> ValidationResult; + + /// Produce a closure for validating messages on a given topic. + fn message_expired<'a>(&'a self) -> Box bool + 'a> { + Box::new(move |_topic, data| match self.validate(data) { + ValidationResult::Valid(_) | ValidationResult::Future(_) => false, + ValidationResult::Invalid | ValidationResult::Expired => true, + }) + } } /// Consensus network protocol handler. Manages statements and candidate requests. pub struct ConsensusGossip { - peers: HashMap>, - live_message_sinks: HashMap>>>, + peers: HashMap>, + live_message_sinks: HashMap<(ConsensusEngineId, B::Hash), Vec>>>, messages: Vec>, known_messages: LruCache, validators: HashMap>>, @@ -95,16 +109,16 @@ impl ConsensusGossip { } /// Handle new connected peer. - pub fn new_peer(&mut self, protocol: &mut Context, who: NodeIndex, roles: Roles) { + pub fn new_peer(&mut self, protocol: &mut Context, who: PeerId, roles: Roles) { if roles.intersects(Roles::AUTHORITY) { trace!(target:"gossip", "Registering {:?} {}", roles, who); - let now = Instant::now(); // Send out all known messages to authorities. let mut known_messages = HashSet::new(); for entry in self.messages.iter() { - if entry.timestamp + MESSAGE_LIFETIME < now { continue }; + if let Status::Future = entry.status { continue } + known_messages.insert(entry.message_hash); - protocol.send_message(who, Message::Consensus(entry.message.clone())); + protocol.send_message(who.clone(), Message::Consensus(entry.message.clone())); } self.peers.insert(who, PeerConsensus { known_messages, @@ -124,13 +138,14 @@ impl ConsensusGossip { protocol: &mut Context, message_hash: B::Hash, get_message: F, + force: bool, ) where F: Fn() -> ConsensusMessage, { let mut non_authorities: Vec<_> = self.peers.iter() .filter_map(|(id, ref peer)| - if !peer.is_authority && !peer.known_messages.contains(&message_hash) { - Some(*id) + if !peer.is_authority && (!peer.known_messages.contains(&message_hash) || force) { + Some(id.clone()) } else { None } @@ -146,44 +161,48 @@ impl ConsensusGossip { for (id, ref mut peer) in self.peers.iter_mut() { if peer.is_authority { - if peer.known_messages.insert(message_hash.clone()) { + if peer.known_messages.insert(message_hash.clone()) || force { let message = get_message(); trace!(target:"gossip", "Propagating to authority {}: {:?}", id, message); - protocol.send_message(*id, Message::Consensus(message)); + protocol.send_message(id.clone(), Message::Consensus(message)); } } else if non_authorities.contains(&id) { - if peer.known_messages.insert(message_hash.clone()) { - let message = get_message(); - trace!(target:"gossip", "Propagating to {}: {:?}", id, message); - protocol.send_message(*id, Message::Consensus(message)); - } + let message = get_message(); + trace!(target:"gossip", "Propagating to {}: {:?}", id, message); + protocol.send_message(id.clone(), Message::Consensus(message)); } } } - fn register_message(&mut self, message_hash: B::Hash, topic: B::Hash, get_message: F) + fn register_message( + &mut self, + message_hash: B::Hash, + topic: B::Hash, + status: Status, + get_message: F, + ) where F: Fn() -> ConsensusMessage { - if self.known_messages.insert(message_hash, ()).is_none() - { + if self.known_messages.insert(message_hash, ()).is_none() { self.messages.push(MessageEntry { topic, message_hash, message: get_message(), - timestamp: Instant::now(), + status, }); - } } /// Call when a peer has been disconnected to stop tracking gossip status. - pub fn peer_disconnected(&mut self, _protocol: &mut Context, who: NodeIndex) { + pub fn peer_disconnected(&mut self, _protocol: &mut Context, who: PeerId) { self.peers.remove(&who); } /// Prune old or no longer relevant consensus messages. Provide a predicate /// for pruning, which returns `false` when the items with a given topic should be pruned. pub fn collect_garbage(&mut self) { + use std::collections::hash_map::Entry; + self.live_message_sinks.retain(|_, sinks| { sinks.retain(|sink| !sink.is_closed()); !sinks.is_empty() @@ -192,17 +211,22 @@ impl ConsensusGossip { let known_messages = &mut self.known_messages; let before = self.messages.len(); let validators = &self.validators; - let now = Instant::now(); - self.messages.retain(|entry| { - entry.timestamp + MESSAGE_LIFETIME >= now - && match validators.get(&entry.message.engine_id) - .map(|v| v.validate(&entry.message.data)) - { - Some(ValidationResult::Valid(_)) => true, - _ => false, - } - }); + let mut check_fns = HashMap::new(); + let mut message_expired = move |entry: &MessageEntry| { + let engine_id = entry.message.engine_id; + let check_fn = match check_fns.entry(engine_id) { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(vacant) => match validators.get(&engine_id) { + None => return true, // treat all messages with no validator as expired + Some(validator) => vacant.insert(validator.message_expired()), + } + }; + + (check_fn)(entry.topic, &entry.message.data) + }; + + self.messages.retain(|entry| !message_expired(entry)); trace!(target: "gossip", "Cleaned up {} stale messages, {} left ({} known)", before - self.messages.len(), @@ -216,12 +240,46 @@ impl ConsensusGossip { } /// Get data of valid, incoming messages for a topic (but might have expired meanwhile) - pub fn messages_for(&mut self, topic: B::Hash) -> mpsc::UnboundedReceiver> { + pub fn messages_for(&mut self, engine_id: ConsensusEngineId, topic: B::Hash) + -> mpsc::UnboundedReceiver> + { let (tx, rx) = mpsc::unbounded(); - for entry in self.messages.iter().filter(|e| e.topic == topic) { - tx.unbounded_send(entry.message.data.clone()).expect("receiver known to be live; qed"); + + let validator = match self.validators.get(&engine_id) { + None => { + self.live_message_sinks.entry((engine_id, topic)).or_default().push(tx); + return rx; + } + Some(v) => v, + }; + + for entry in self.messages.iter_mut() + .filter(|e| e.topic == topic && e.message.engine_id == engine_id) + { + let live = match entry.status { + Status::Live => true, + Status::Future => match validator.validate(&entry.message.data) { + ValidationResult::Valid(_) => { + entry.status = Status::Live; + true + } + _ => { + // don't send messages considered to be future still. + // if messages are considered expired they'll be cleaned up when we + // collect garbage. + false + } + } + }; + + if live { + entry.status = Status::Live; + tx.unbounded_send(entry.message.data.clone()) + .expect("receiver known to be live; qed"); + } } - self.live_message_sinks.entry(topic).or_default().push(tx); + + self.live_message_sinks.entry((engine_id, topic)).or_default().push(tx); rx } @@ -233,9 +291,8 @@ impl ConsensusGossip { pub fn on_incoming( &mut self, protocol: &mut Context, - who: NodeIndex, + who: PeerId, message: ConsensusMessage, - is_syncing: bool, ) -> Option<(B::Hash, ConsensusMessage)> { let message_hash = HashFor::::hash(&message.data[..]); @@ -247,11 +304,13 @@ impl ConsensusGossip { if let Some(ref mut peer) = self.peers.get_mut(&who) { use std::collections::hash_map::Entry; - //validate the message - let topic = match self.validators.get(&message.engine_id) + let engine_id = message.engine_id; + // validate the message + let (topic, status) = match self.validators.get(&engine_id) .map(|v| v.validate(&message.data)) { - Some(ValidationResult::Valid(topic)) => topic, + Some(ValidationResult::Valid(topic)) => (topic, Status::Live), + Some(ValidationResult::Future(topic)) => (topic, Status::Future), Some(ValidationResult::Invalid) => { trace!(target:"gossip", "Invalid message from {}", who); protocol.report_peer( @@ -262,26 +321,21 @@ impl ConsensusGossip { }, Some(ValidationResult::Expired) => { trace!(target:"gossip", "Ignored expired message from {}", who); - if !is_syncing { - protocol.report_peer( - who, - Severity::Useless(format!("Sent expired consensus message")), - ); - } return None; - } + }, None => { protocol.report_peer( - who, + who.clone(), Severity::Useless(format!("Sent unknown consensus engine id")), ); - trace!(target:"gossip", "Unknown message engine id {:?} from {}", message.engine_id, who); + trace!(target:"gossip", "Unknown message engine id {:?} from {}", + engine_id, who); return None; - } + }, }; peer.known_messages.insert(message_hash); - if let Entry::Occupied(mut entry) = self.live_message_sinks.entry(topic) { + if let Entry::Occupied(mut entry) = self.live_message_sinks.entry((engine_id, topic)) { debug!(target: "gossip", "Pushing consensus message to sinks for {}.", topic); entry.get_mut().retain(|sink| { if let Err(e) = sink.unbounded_send(message.data.clone()) { @@ -293,7 +347,7 @@ impl ConsensusGossip { entry.remove_entry(); } } - self.multicast_inner(protocol, message_hash, topic, || message.clone()); + self.multicast_inner(protocol, message_hash, topic, status, || message.clone(), false); Some((topic, message)) } else { trace!(target:"gossip", "Ignored statement from unregistered peer {}", who); @@ -307,9 +361,10 @@ impl ConsensusGossip { protocol: &mut Context, topic: B::Hash, message: ConsensusMessage, + force: bool, ) { let message_hash = HashFor::::hash(&message.data); - self.multicast_inner(protocol, message_hash, topic, || message.clone()); + self.multicast_inner(protocol, message_hash, topic, Status::Live, || message.clone(), force); } fn multicast_inner( @@ -317,51 +372,50 @@ impl ConsensusGossip { protocol: &mut Context, message_hash: B::Hash, topic: B::Hash, + status: Status, get_message: F, + force: bool, ) where F: Fn() -> ConsensusMessage { - self.register_message(message_hash, topic, &get_message); - self.propagate(protocol, message_hash, get_message); - } - - /// Note new consensus session. - pub fn new_session(&mut self, _parent_hash: B::Hash) { - self.collect_garbage(); + self.register_message(message_hash, topic, status, &get_message); + if let Status::Live = status { + self.propagate(protocol, message_hash, get_message, force); + } } } #[cfg(test)] mod tests { use runtime_primitives::testing::{H256, Block as RawBlock, ExtrinsicWrapper}; - use std::time::Instant; + use futures::Stream; + use super::*; type Block = RawBlock>; macro_rules! push_msg { - ($consensus:expr, $topic:expr, $hash: expr, $now: expr, $m:expr) => { + ($consensus:expr, $topic:expr, $hash: expr, $m:expr) => { if $consensus.known_messages.insert($hash, ()).is_none() { $consensus.messages.push(MessageEntry { topic: $topic, message_hash: $hash, - message: ConsensusMessage { data: $m, engine_id: [0, 0, 0, 0]}, - timestamp: $now, + message: ConsensusMessage { data: $m, engine_id: [0, 0, 0, 0] }, + status: Status::Live, }); } } } - #[test] - fn collects_garbage() { - - struct AllowAll; - impl Validator for AllowAll { - fn validate(&self, _data: &[u8]) -> ValidationResult { - ValidationResult::Valid(H256::default()) - } + struct AllowAll; + impl Validator for AllowAll { + fn validate(&self, _data: &[u8]) -> ValidationResult { + ValidationResult::Valid(H256::default()) } + } + #[test] + fn collects_garbage() { struct AllowOne; impl Validator for AllowOne { fn validate(&self, data: &[u8]) -> ValidationResult { @@ -381,9 +435,8 @@ mod tests { let m1 = vec![1, 2, 3]; let m2 = vec![4, 5, 6]; - let now = Instant::now(); - push_msg!(consensus, prev_hash, m1_hash, now, m1); - push_msg!(consensus, best_hash, m2_hash, now, m2.clone()); + push_msg!(consensus, prev_hash, m1_hash, m1); + push_msg!(consensus, best_hash, m2_hash, m2.clone()); consensus.known_messages.insert(m1_hash, ()); consensus.known_messages.insert(m2_hash, ()); @@ -401,15 +454,6 @@ mod tests { // known messages are only pruned based on size. assert_eq!(consensus.known_messages.len(), 2); assert!(consensus.known_messages.contains_key(&m2_hash)); - - // make timestamp expired, but the message is still kept as known - consensus.messages.clear(); - consensus.known_messages.clear(); - consensus.register_validator(test_engine_id, Arc::new(AllowAll)); - push_msg!(consensus, best_hash, m2_hash, now - MESSAGE_LIFETIME, m2.clone()); - consensus.collect_garbage(); - assert!(consensus.messages.is_empty()); - assert_eq!(consensus.known_messages.len(), 1); } #[test] @@ -417,14 +461,15 @@ mod tests { use futures::Stream; let mut consensus = ConsensusGossip::::new(); + consensus.register_validator([0, 0, 0, 0], Arc::new(AllowAll)); let message = ConsensusMessage { data: vec![4, 5, 6], engine_id: [0, 0, 0, 0] }; let message_hash = HashFor::::hash(&message.data); let topic = HashFor::::hash(&[1,2,3]); - consensus.register_message(message_hash, topic, || message.clone()); - let stream = consensus.messages_for(topic); + consensus.register_message(message_hash, topic, Status::Live, || message.clone()); + let stream = consensus.messages_for([0, 0, 0, 0], topic); assert_eq!(stream.wait().next(), Some(Ok(message.data))); } @@ -437,29 +482,47 @@ mod tests { let msg_a = ConsensusMessage { data: vec![1, 2, 3], engine_id: [0, 0, 0, 0] }; let msg_b = ConsensusMessage { data: vec![4, 5, 6], engine_id: [0, 0, 0, 0] }; - consensus.register_message(HashFor::::hash(&msg_a.data), topic, || msg_a.clone()); - consensus.register_message(HashFor::::hash(&msg_b.data), topic, || msg_b.clone()); + consensus.register_message(HashFor::::hash(&msg_a.data), topic, Status::Live, || msg_a.clone()); + consensus.register_message(HashFor::::hash(&msg_b.data), topic, Status::Live, || msg_b.clone()); assert_eq!(consensus.messages.len(), 2); } #[test] fn can_keep_multiple_subscribers_per_topic() { - use futures::Stream; - let mut consensus = ConsensusGossip::::new(); + consensus.register_validator([0, 0, 0, 0], Arc::new(AllowAll)); let message = ConsensusMessage { data: vec![4, 5, 6], engine_id: [0, 0, 0, 0] }; let message_hash = HashFor::::hash(&message.data); let topic = HashFor::::hash(&[1,2,3]); - consensus.register_message(message_hash, topic, || message.clone()); + consensus.register_message(message_hash, topic, Status::Live, || message.clone()); - let stream1 = consensus.messages_for(topic); - let stream2 = consensus.messages_for(topic); + let stream1 = consensus.messages_for([0, 0, 0, 0], topic); + let stream2 = consensus.messages_for([0, 0, 0, 0], topic); assert_eq!(stream1.wait().next(), Some(Ok(message.data.clone()))); assert_eq!(stream2.wait().next(), Some(Ok(message.data))); } + + #[test] + fn topics_are_localized_to_engine_id() { + let mut consensus = ConsensusGossip::::new(); + consensus.register_validator([0, 0, 0, 0], Arc::new(AllowAll)); + + let topic = [1; 32].into(); + let msg_a = ConsensusMessage { data: vec![1, 2, 3], engine_id: [0, 0, 0, 0] }; + let msg_b = ConsensusMessage { data: vec![4, 5, 6], engine_id: [0, 0, 0, 1] }; + + consensus.register_message(HashFor::::hash(&msg_a.data), topic, Status::Live, || msg_a.clone()); + consensus.register_message(HashFor::::hash(&msg_b.data), topic, Status::Live, || msg_b.clone()); + + let mut stream = consensus.messages_for([0, 0, 0, 0], topic).wait(); + + assert_eq!(stream.next(), Some(Ok(vec![1, 2, 3]))); + let _ = consensus.live_message_sinks.remove(&([0, 0, 0, 0], topic)); + assert_eq!(stream.next(), None); + } } diff --git a/core/network/src/error.rs b/core/network/src/error.rs index 36b2b90a5d78e7e9d4dbef9778c77022ef9cee43..bf687f99698e91a796c3edbf5af11b8314a3b221 100644 --- a/core/network/src/error.rs +++ b/core/network/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -22,12 +22,10 @@ use error_chain::*; use std::io::Error as IoError; -use network_libp2p::Error as NetworkError; use client; error_chain! { foreign_links { - Network(NetworkError) #[doc = "Devp2p error."]; Io(IoError) #[doc = "IO error."]; } diff --git a/core/network/src/lib.rs b/core/network/src/lib.rs index 31c90cb3113c1fd31cd48da5d8d3525ded6b724f..0f184af77302eaad4657b2636103f978f7d8e2b3 100644 --- a/core/network/src/lib.rs +++ b/core/network/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -42,8 +42,11 @@ pub use service::{Service, FetchFuture, TransactionPool, ManageNetwork, NetworkM pub use protocol::{ProtocolStatus, PeerInfo, Context}; pub use sync::{Status as SyncStatus, SyncState}; pub use network_libp2p::{ - NodeIndex, ProtocolId, Severity, Protocol, Multiaddr, - obtain_private_key, build_multiaddr, PeerId, PublicKey + identity, multiaddr, + ProtocolId, Severity, Multiaddr, + NetworkState, NetworkStatePeer, NetworkStateNotConnectedPeer, NetworkStatePeerEndpoint, + NodeKeyConfig, Secret, Secp256k1Secret, Ed25519Secret, + build_multiaddr, PeerId, PublicKey }; pub use message::{generic as generic_message, RequestId, Status as StatusMessage, ConsensusEngineId}; pub use error::Error; diff --git a/core/network/src/message.rs b/core/network/src/message.rs index 416574e387610b6a77fa724d43a8004512851084..355935b10ece69827df608dc5b00b4574b7c8237 100644 --- a/core/network/src/message.rs +++ b/core/network/src/message.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -19,7 +19,6 @@ use bitflags::bitflags; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT}; use parity_codec::{Encode, Decode, Input, Output}; -use parity_codec_derive::{Encode, Decode}; pub use self::generic::{ BlockAnnounce, RemoteCallRequest, RemoteReadRequest, RemoteHeaderRequest, RemoteHeaderResponse, @@ -131,7 +130,6 @@ pub mod generic { use parity_codec::{Encode, Decode}; use network_libp2p::{CustomMessage, CustomMessageId}; use runtime_primitives::Justification; - use parity_codec_derive::{Encode, Decode}; use crate::config::Roles; use super::{ BlockAttributes, RemoteCallResponse, RemoteReadResponse, diff --git a/core/network/src/on_demand.rs b/core/network/src/on_demand.rs index 62868693598882c0a457f6db4df7ce6a96a4b28d..6a890144655c9d7656004b60a60d01c8c66f5090 100644 --- a/core/network/src/on_demand.rs +++ b/core/network/src/on_demand.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -29,7 +29,7 @@ use client::{error::{Error as ClientError, ErrorKind as ClientErrorKind}}; use client::light::fetcher::{Fetcher, FetchChecker, RemoteHeaderRequest, RemoteCallRequest, RemoteReadRequest, RemoteChangesRequest, ChangesProof}; use crate::message; -use network_libp2p::{Severity, NodeIndex}; +use network_libp2p::{Severity, PeerId}; use crate::config::Roles; use crate::service::{NetworkChan, NetworkMsg}; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, NumberFor}; @@ -42,13 +42,13 @@ const RETRY_COUNT: usize = 1; /// On-demand service API. pub trait OnDemandService: Send + Sync { /// When new node is connected. - fn on_connect(&self, peer: NodeIndex, role: Roles, best_number: NumberFor); + fn on_connect(&self, peer: PeerId, role: Roles, best_number: NumberFor); /// When block is announced by the peer. - fn on_block_announce(&self, peer: NodeIndex, best_number: NumberFor); + fn on_block_announce(&self, peer: PeerId, best_number: NumberFor); /// When node is disconnected. - fn on_disconnect(&self, peer: NodeIndex); + fn on_disconnect(&self, peer: PeerId); /// Maintain peers requests. fn maintain_peers(&self); @@ -56,20 +56,20 @@ pub trait OnDemandService: Send + Sync { /// When header response is received from remote node. fn on_remote_header_response( &self, - peer: NodeIndex, + peer: PeerId, response: message::RemoteHeaderResponse ); /// When read response is received from remote node. - fn on_remote_read_response(&self, peer: NodeIndex, response: message::RemoteReadResponse); + fn on_remote_read_response(&self, peer: PeerId, response: message::RemoteReadResponse); /// When call response is received from remote node. - fn on_remote_call_response(&self, peer: NodeIndex, response: message::RemoteCallResponse); + fn on_remote_call_response(&self, peer: PeerId, response: message::RemoteCallResponse); /// When changes response is received from remote node. fn on_remote_changes_response( &self, - peer: NodeIndex, + peer: PeerId, response: message::RemoteChangesResponse, Block::Hash> ); } @@ -90,9 +90,9 @@ pub struct RemoteResponse { struct OnDemandCore { next_request_id: u64, pending_requests: VecDeque>, - active_peers: LinkedHashMap>, - idle_peers: VecDeque, - best_blocks: HashMap>, + active_peers: LinkedHashMap>, + idle_peers: VecDeque, + best_blocks: HashMap>, } struct Request { @@ -170,13 +170,13 @@ impl OnDemand where } /// Try to accept response from given peer. - fn accept_response) -> Accept>(&self, rtype: &str, peer: NodeIndex, request_id: u64, try_accept: F) { + fn accept_response) -> Accept>(&self, rtype: &str, peer: PeerId, request_id: u64, try_accept: F) { let mut core = self.core.lock(); - let request = match core.remove(peer, request_id) { + let request = match core.remove(peer.clone(), request_id) { Some(request) => request, None => { let reason = format!("Invalid remote {} response from peer", rtype); - self.send(NetworkMsg::ReportPeer(peer, Severity::Bad(reason))); + self.send(NetworkMsg::ReportPeer(peer.clone(), Severity::Bad(reason))); core.remove_peer(peer); return; }, @@ -187,7 +187,7 @@ impl OnDemand where Accept::Ok => (retry_count, None), Accept::CheckFailed(error, retry_request_data) => { let reason = format!("Failed to check remote {} response from peer: {}", rtype, error); - self.send(NetworkMsg::ReportPeer(peer, Severity::Bad(reason))); + self.send(NetworkMsg::ReportPeer(peer.clone(), Severity::Bad(reason))); core.remove_peer(peer); if retry_count > 0 { @@ -200,7 +200,7 @@ impl OnDemand where }, Accept::Unexpected(retry_request_data) => { let reason = format!("Unexpected response to remote {} from peer", rtype); - self.send(NetworkMsg::ReportPeer(peer, Severity::Bad(reason))); + self.send(NetworkMsg::ReportPeer(peer.clone(), Severity::Bad(reason))); core.remove_peer(peer); (retry_count, Some(retry_request_data)) @@ -219,7 +219,7 @@ impl OnDemandService for OnDemand where B: BlockT, B::Header: HeaderT, { - fn on_connect(&self, peer: NodeIndex, role: Roles, best_number: NumberFor) { + fn on_connect(&self, peer: PeerId, role: Roles, best_number: NumberFor) { if !role.intersects(Roles::FULL | Roles::AUTHORITY) { return; } @@ -229,13 +229,13 @@ impl OnDemandService for OnDemand where core.dispatch(self); } - fn on_block_announce(&self, peer: NodeIndex, best_number: NumberFor) { + fn on_block_announce(&self, peer: PeerId, best_number: NumberFor) { let mut core = self.core.lock(); core.update_peer(peer, best_number); core.dispatch(self); } - fn on_disconnect(&self, peer: NodeIndex) { + fn on_disconnect(&self, peer: PeerId) { let mut core = self.core.lock(); core.remove_peer(peer); core.dispatch(self); @@ -249,7 +249,7 @@ impl OnDemandService for OnDemand where core.dispatch(self); } - fn on_remote_header_response(&self, peer: NodeIndex, response: message::RemoteHeaderResponse) { + fn on_remote_header_response(&self, peer: PeerId, response: message::RemoteHeaderResponse) { self.accept_response("header", peer, response.id, |request| match request.data { RequestData::RemoteHeader(request, sender) => match self.checker.check_header_proof(&request, response.header, response.proof) { Ok(response) => { @@ -263,7 +263,7 @@ impl OnDemandService for OnDemand where }) } - fn on_remote_read_response(&self, peer: NodeIndex, response: message::RemoteReadResponse) { + fn on_remote_read_response(&self, peer: PeerId, response: message::RemoteReadResponse) { self.accept_response("read", peer, response.id, |request| match request.data { RequestData::RemoteRead(request, sender) => match self.checker.check_read_proof(&request, response.proof) { Ok(response) => { @@ -277,7 +277,7 @@ impl OnDemandService for OnDemand where }) } - fn on_remote_call_response(&self, peer: NodeIndex, response: message::RemoteCallResponse) { + fn on_remote_call_response(&self, peer: PeerId, response: message::RemoteCallResponse) { self.accept_response("call", peer, response.id, |request| match request.data { RequestData::RemoteCall(request, sender) => match self.checker.check_execution_proof(&request, response.proof) { Ok(response) => { @@ -291,7 +291,7 @@ impl OnDemandService for OnDemand where }) } - fn on_remote_changes_response(&self, peer: NodeIndex, response: message::RemoteChangesResponse, B::Hash>) { + fn on_remote_changes_response(&self, peer: PeerId, response: message::RemoteChangesResponse, B::Hash>) { self.accept_response("changes", peer, response.id, |request| match request.data { RequestData::RemoteChanges(request, sender) => match self.checker.check_changes_proof( &request, ChangesProof { @@ -350,16 +350,16 @@ impl OnDemandCore where B: BlockT, B::Header: HeaderT, { - pub fn add_peer(&mut self, peer: NodeIndex, best_number: NumberFor) { - self.idle_peers.push_back(peer); + pub fn add_peer(&mut self, peer: PeerId, best_number: NumberFor) { + self.idle_peers.push_back(peer.clone()); self.best_blocks.insert(peer, best_number); } - pub fn update_peer(&mut self, peer: NodeIndex, best_number: NumberFor) { + pub fn update_peer(&mut self, peer: PeerId, best_number: NumberFor) { self.best_blocks.insert(peer, best_number); } - pub fn remove_peer(&mut self, peer: NodeIndex) { + pub fn remove_peer(&mut self, peer: PeerId) { self.best_blocks.remove(&peer); if let Some(request) = self.active_peers.remove(&peer) { @@ -372,7 +372,7 @@ impl OnDemandCore where } } - pub fn maintain_peers(&mut self) -> Vec { + pub fn maintain_peers(&mut self) -> Vec { let now = Instant::now(); let mut bad_peers = Vec::new(); loop { @@ -399,8 +399,8 @@ impl OnDemandCore where }); } - pub fn remove(&mut self, peer: NodeIndex, id: u64) -> Option> { - match self.active_peers.entry(peer) { + pub fn remove(&mut self, peer: PeerId, id: u64) -> Option> { + match self.active_peers.entry(peer.clone()) { Entry::Occupied(entry) => match entry.get().id == id { true => { self.idle_peers.push_back(peer); @@ -441,7 +441,7 @@ impl OnDemandCore where if !can_be_processed_by_peer { // return peer to the back of the queue - self.idle_peers.push_back(peer); + self.idle_peers.push_back(peer.clone()); // we have enumerated all peers and noone can handle request if Some(peer) == last_peer { @@ -458,7 +458,7 @@ impl OnDemandCore where let mut request = self.pending_requests.pop_front().expect("checked in loop condition; qed"); request.timestamp = Instant::now(); trace!(target: "sync", "Dispatching remote request {} to peer {}", request.id, peer); - on_demand.send(NetworkMsg::Outgoing(peer, request.message())); + on_demand.send(NetworkMsg::Outgoing(peer.clone(), request.message())); self.active_peers.insert(peer, request); } @@ -532,7 +532,7 @@ pub mod tests { RemoteCallRequest, RemoteReadRequest, RemoteChangesRequest, ChangesProof}; use crate::config::Roles; use crate::message; - use network_libp2p::{NodeIndex, ProtocolId, Severity}; + use network_libp2p::{PeerId, Severity}; use crate::service::{network_channel, NetworkPort, NetworkMsg}; use super::{REQUEST_TIMEOUT, OnDemand, OnDemandService}; use test_client::runtime::{changes_trie_config, Block, Header}; @@ -586,7 +586,7 @@ pub mod tests { core.idle_peers.len() + core.active_peers.len() } - fn receive_call_response(on_demand: &OnDemand, peer: NodeIndex, id: message::RequestId) { + fn receive_call_response(on_demand: &OnDemand, peer: PeerId, id: message::RequestId) { on_demand.on_remote_call_response(peer, message::RemoteCallResponse { id: id, proof: vec![vec![2]], @@ -621,22 +621,27 @@ pub mod tests { #[test] fn knows_about_peers_roles() { let (_, on_demand) = dummy(true); - on_demand.on_connect(0, Roles::LIGHT, 1000); - on_demand.on_connect(1, Roles::FULL, 2000); - on_demand.on_connect(2, Roles::AUTHORITY, 3000); - assert_eq!(vec![1, 2], on_demand.core.lock().idle_peers.iter().cloned().collect::>()); - assert_eq!(on_demand.core.lock().best_blocks.get(&1), Some(&2000)); - assert_eq!(on_demand.core.lock().best_blocks.get(&2), Some(&3000)); + let peer0 = PeerId::random(); + let peer1 = PeerId::random(); + let peer2 = PeerId::random(); + on_demand.on_connect(peer0, Roles::LIGHT, 1000); + on_demand.on_connect(peer1.clone(), Roles::FULL, 2000); + on_demand.on_connect(peer2.clone(), Roles::AUTHORITY, 3000); + assert_eq!(vec![peer1.clone(), peer2.clone()], on_demand.core.lock().idle_peers.iter().cloned().collect::>()); + assert_eq!(on_demand.core.lock().best_blocks.get(&peer1), Some(&2000)); + assert_eq!(on_demand.core.lock().best_blocks.get(&peer2), Some(&3000)); } #[test] fn disconnects_from_idle_peer() { + let peer0 = PeerId::random(); + let (_, on_demand) = dummy(true); - on_demand.on_connect(0, Roles::FULL, 100); + on_demand.on_connect(peer0.clone(), Roles::FULL, 100); assert_eq!(1, total_peers(&*on_demand)); assert!(!on_demand.core.lock().best_blocks.is_empty()); - on_demand.on_disconnect(0); + on_demand.on_disconnect(peer0); assert_eq!(0, total_peers(&*on_demand)); assert!(on_demand.core.lock().best_blocks.is_empty()); } @@ -644,11 +649,13 @@ pub mod tests { #[test] fn disconnects_from_timeouted_peer() { let (_x, on_demand) = dummy(true); - let (network_sender, network_port) = network_channel(ProtocolId::default()); + let (network_sender, network_port) = network_channel(); + let peer0 = PeerId::random(); + let peer1 = PeerId::random(); on_demand.set_network_sender(network_sender.clone()); - on_demand.on_connect(0, Roles::FULL, 1000); - on_demand.on_connect(1, Roles::FULL, 1000); - assert_eq!(vec![0, 1], on_demand.core.lock().idle_peers.iter().cloned().collect::>()); + on_demand.on_connect(peer0.clone(), Roles::FULL, 1000); + on_demand.on_connect(peer1.clone(), Roles::FULL, 1000); + assert_eq!(vec![peer0.clone(), peer1.clone()], on_demand.core.lock().idle_peers.iter().cloned().collect::>()); assert!(on_demand.core.lock().active_peers.is_empty()); on_demand.remote_call(RemoteCallRequest { @@ -658,22 +665,23 @@ pub mod tests { call_data: vec![], retry_count: None, }); - assert_eq!(vec![1], on_demand.core.lock().idle_peers.iter().cloned().collect::>()); - assert_eq!(vec![0], on_demand.core.lock().active_peers.keys().cloned().collect::>()); + assert_eq!(vec![peer1.clone()], on_demand.core.lock().idle_peers.iter().cloned().collect::>()); + assert_eq!(vec![peer0.clone()], on_demand.core.lock().active_peers.keys().cloned().collect::>()); - on_demand.core.lock().active_peers[&0].timestamp = Instant::now() - REQUEST_TIMEOUT - REQUEST_TIMEOUT; + on_demand.core.lock().active_peers[&peer0].timestamp = Instant::now() - REQUEST_TIMEOUT - REQUEST_TIMEOUT; on_demand.maintain_peers(); assert!(on_demand.core.lock().idle_peers.is_empty()); - assert_eq!(vec![1], on_demand.core.lock().active_peers.keys().cloned().collect::>()); + assert_eq!(vec![peer1.clone()], on_demand.core.lock().active_peers.keys().cloned().collect::>()); assert_disconnected_peer(network_port, Severity::Timeout); } #[test] fn disconnects_from_peer_on_response_with_wrong_id() { let (_x, on_demand) = dummy(true); - let (network_sender, network_port) = network_channel(ProtocolId::default()); + let peer0 = PeerId::random(); + let (network_sender, network_port) = network_channel(); on_demand.set_network_sender(network_sender.clone()); - on_demand.on_connect(0, Roles::FULL, 1000); + on_demand.on_connect(peer0.clone(), Roles::FULL, 1000); on_demand.remote_call(RemoteCallRequest { block: Default::default(), @@ -682,7 +690,7 @@ pub mod tests { call_data: vec![], retry_count: None, }); - receive_call_response(&*on_demand, 0, 1); + receive_call_response(&*on_demand, peer0, 1); assert_disconnected_peer(network_port, Severity::Bad("Invalid remote call response from peer".to_string())); assert_eq!(on_demand.core.lock().pending_requests.len(), 1); } @@ -690,7 +698,8 @@ pub mod tests { #[test] fn disconnects_from_peer_on_incorrect_response() { let (_x, on_demand) = dummy(false); - let (network_sender, network_port) = network_channel(ProtocolId::default()); + let (network_sender, network_port) = network_channel(); + let peer0 = PeerId::random(); on_demand.set_network_sender(network_sender.clone()); on_demand.remote_call(RemoteCallRequest { block: Default::default(), @@ -700,8 +709,8 @@ pub mod tests { retry_count: Some(1), }); - on_demand.on_connect(0, Roles::FULL, 1000); - receive_call_response(&*on_demand, 0, 0); + on_demand.on_connect(peer0.clone(), Roles::FULL, 1000); + receive_call_response(&*on_demand, peer0.clone(), 0); assert_disconnected_peer(network_port, Severity::Bad("Failed to check remote call response from peer: Backend error: Test error".to_string())); assert_eq!(on_demand.core.lock().pending_requests.len(), 1); } @@ -709,20 +718,22 @@ pub mod tests { #[test] fn disconnects_from_peer_on_unexpected_response() { let (_x, on_demand) = dummy(true); - let (network_sender, network_port) = network_channel(ProtocolId::default()); + let (network_sender, network_port) = network_channel(); + let peer0 = PeerId::random(); on_demand.set_network_sender(network_sender.clone()); - on_demand.on_connect(0, Roles::FULL, 1000); + on_demand.on_connect(peer0.clone(), Roles::FULL, 1000); - receive_call_response(&*on_demand, 0, 0); + receive_call_response(&*on_demand, peer0, 0); assert_disconnected_peer(network_port, Severity::Bad("Invalid remote call response from peer".to_string())); } #[test] fn disconnects_from_peer_on_wrong_response_type() { let (_x, on_demand) = dummy(false); - let (network_sender, network_port) = network_channel(ProtocolId::default()); + let peer0 = PeerId::random(); + let (network_sender, network_port) = network_channel(); on_demand.set_network_sender(network_sender.clone()); - on_demand.on_connect(0, Roles::FULL, 1000); + on_demand.on_connect(peer0.clone(), Roles::FULL, 1000); on_demand.remote_call(RemoteCallRequest { block: Default::default(), @@ -732,7 +743,7 @@ pub mod tests { retry_count: Some(1), }); - on_demand.on_remote_read_response(0, message::RemoteReadResponse { + on_demand.on_remote_read_response(peer0.clone(), message::RemoteReadResponse { id: 0, proof: vec![vec![2]], }); @@ -745,11 +756,12 @@ pub mod tests { use parking_lot::{Condvar, Mutex}; let retry_count = 2; + let peer_ids = (0 .. retry_count + 1).map(|_| PeerId::random()).collect::>(); let (_x, on_demand) = dummy(false); - let (network_sender, _network_port) = network_channel(ProtocolId::default()); + let (network_sender, _network_port) = network_channel(); on_demand.set_network_sender(network_sender.clone()); for i in 0..retry_count+1 { - on_demand.on_connect(i, Roles::FULL, 1000); + on_demand.on_connect(peer_ids[i].clone(), Roles::FULL, 1000); } let sync = Arc::new((Mutex::new(0), Mutex::new(0), Condvar::new())); @@ -773,7 +785,7 @@ pub mod tests { for i in 0..retry_count+1 { let mut current = current.lock(); *current = *current + 1; - receive_call_response(&*on_demand, i, i as u64); + receive_call_response(&*on_demand, peer_ids[i].clone(), i as u64); } let mut finished_at = finished_at.lock(); @@ -786,9 +798,10 @@ pub mod tests { #[test] fn receives_remote_call_response() { let (_x, on_demand) = dummy(true); - let (network_sender, _network_port) = network_channel(ProtocolId::default()); + let (network_sender, _network_port) = network_channel(); + let peer0 = PeerId::random(); on_demand.set_network_sender(network_sender.clone()); - on_demand.on_connect(0, Roles::FULL, 1000); + on_demand.on_connect(peer0.clone(), Roles::FULL, 1000); let response = on_demand.remote_call(RemoteCallRequest { block: Default::default(), @@ -802,16 +815,17 @@ pub mod tests { assert_eq!(result, vec![42]); }); - receive_call_response(&*on_demand, 0, 0); + receive_call_response(&*on_demand, peer0.clone(), 0); thread.join().unwrap(); } #[test] fn receives_remote_read_response() { let (_x, on_demand) = dummy(true); - let (network_sender, _network_port) = network_channel(ProtocolId::default()); + let (network_sender, _network_port) = network_channel(); + let peer0 = PeerId::random(); on_demand.set_network_sender(network_sender.clone()); - on_demand.on_connect(0, Roles::FULL, 1000); + on_demand.on_connect(peer0.clone(), Roles::FULL, 1000); let response = on_demand.remote_read(RemoteReadRequest { header: dummy_header(), @@ -824,7 +838,7 @@ pub mod tests { assert_eq!(result, Some(vec![42])); }); - on_demand.on_remote_read_response(0, message::RemoteReadResponse { + on_demand.on_remote_read_response(peer0.clone(), message::RemoteReadResponse { id: 0, proof: vec![vec![2]], }); @@ -834,9 +848,10 @@ pub mod tests { #[test] fn receives_remote_header_response() { let (_x, on_demand) = dummy(true); - let (network_sender, _network_port) = network_channel(ProtocolId::default()); + let (network_sender, _network_port) = network_channel(); + let peer0 = PeerId::random(); on_demand.set_network_sender(network_sender.clone()); - on_demand.on_connect(0, Roles::FULL, 1000); + on_demand.on_connect(peer0.clone(), Roles::FULL, 1000); let response = on_demand.remote_header(RemoteHeaderRequest { cht_root: Default::default(), @@ -852,7 +867,7 @@ pub mod tests { ); }); - on_demand.on_remote_header_response(0, message::RemoteHeaderResponse { + on_demand.on_remote_header_response(peer0.clone(), message::RemoteHeaderResponse { id: 0, header: Some(Header { parent_hash: Default::default(), @@ -869,9 +884,10 @@ pub mod tests { #[test] fn receives_remote_changes_response() { let (_x, on_demand) = dummy(true); - let (network_sender, _network_port) = network_channel(ProtocolId::default()); + let (network_sender, _network_port) = network_channel(); + let peer0 = PeerId::random(); on_demand.set_network_sender(network_sender.clone()); - on_demand.on_connect(0, Roles::FULL, 1000); + on_demand.on_connect(peer0.clone(), Roles::FULL, 1000); let response = on_demand.remote_changes(RemoteChangesRequest { changes_trie_config: changes_trie_config(), @@ -887,7 +903,7 @@ pub mod tests { assert_eq!(result, vec![(100, 2)]); }); - on_demand.on_remote_changes_response(0, message::RemoteChangesResponse { + on_demand.on_remote_changes_response(peer0.clone(), message::RemoteChangesResponse { id: 0, max: 1000, proof: vec![vec![2]], @@ -900,10 +916,12 @@ pub mod tests { #[test] fn does_not_sends_request_to_peer_who_has_no_required_block() { let (_x, on_demand) = dummy(true); - let (network_sender, _network_port) = network_channel(ProtocolId::default()); + let (network_sender, _network_port) = network_channel(); + let peer1 = PeerId::random(); + let peer2 = PeerId::random(); on_demand.set_network_sender(network_sender.clone()); - on_demand.on_connect(1, Roles::FULL, 100); + on_demand.on_connect(peer1.clone(), Roles::FULL, 100); on_demand.remote_header(RemoteHeaderRequest { cht_root: Default::default(), @@ -921,22 +939,22 @@ pub mod tests { retry_count: None, }); - on_demand.on_connect(2, Roles::FULL, 150); + on_demand.on_connect(peer2.clone(), Roles::FULL, 150); - assert_eq!(vec![1, 2], on_demand.core.lock().idle_peers.iter().cloned().collect::>()); + assert_eq!(vec![peer1.clone(), peer2.clone()], on_demand.core.lock().idle_peers.iter().cloned().collect::>()); assert_eq!(on_demand.core.lock().pending_requests.len(), 3); - on_demand.on_block_announce(1, 250); + on_demand.on_block_announce(peer1.clone(), 250); - assert_eq!(vec![2], on_demand.core.lock().idle_peers.iter().cloned().collect::>()); + assert_eq!(vec![peer2.clone()], on_demand.core.lock().idle_peers.iter().cloned().collect::>()); assert_eq!(on_demand.core.lock().pending_requests.len(), 2); - on_demand.on_block_announce(2, 250); + on_demand.on_block_announce(peer2.clone(), 250); assert!(!on_demand.core.lock().idle_peers.iter().any(|_| true)); assert_eq!(on_demand.core.lock().pending_requests.len(), 1); - on_demand.on_remote_header_response(1, message::RemoteHeaderResponse { + on_demand.on_remote_header_response(peer1.clone(), message::RemoteHeaderResponse { id: 0, header: Some(dummy_header()), proof: vec![], @@ -952,7 +970,10 @@ pub mod tests { // loop forever after dispatching a request to the last peer, since the // last peer was not updated let (_x, on_demand) = dummy(true); - let (network_sender, _network_port) = network_channel(ProtocolId::default()); + let (network_sender, _network_port) = network_channel(); + let peer1 = PeerId::random(); + let peer2 = PeerId::random(); + let peer3 = PeerId::random(); on_demand.set_network_sender(network_sender.clone()); on_demand.remote_header(RemoteHeaderRequest { @@ -966,18 +987,19 @@ pub mod tests { retry_count: None, }); - on_demand.on_connect(1, Roles::FULL, 200); - on_demand.on_connect(2, Roles::FULL, 200); - on_demand.on_connect(3, Roles::FULL, 250); + on_demand.on_connect(peer1.clone(), Roles::FULL, 200); + on_demand.on_connect(peer2.clone(), Roles::FULL, 200); + on_demand.on_connect(peer3.clone(), Roles::FULL, 250); - assert_eq!(vec![1, 2], on_demand.core.lock().idle_peers.iter().cloned().collect::>()); + assert_eq!(vec![peer1.clone(), peer2.clone()], on_demand.core.lock().idle_peers.iter().cloned().collect::>()); assert_eq!(on_demand.core.lock().pending_requests.len(), 1); } #[test] fn tries_to_send_all_pending_requests() { let (_x, on_demand) = dummy(true); - let (network_sender, _network_port) = network_channel(ProtocolId::default()); + let (network_sender, _network_port) = network_channel(); + let peer1 = PeerId::random(); on_demand.set_network_sender(network_sender.clone()); on_demand.remote_header(RemoteHeaderRequest { @@ -991,7 +1013,7 @@ pub mod tests { retry_count: None, }); - on_demand.on_connect(1, Roles::FULL, 250); + on_demand.on_connect(peer1.clone(), Roles::FULL, 250); assert!(on_demand.core.lock().idle_peers.iter().cloned().collect::>().is_empty()); assert_eq!(on_demand.core.lock().pending_requests.len(), 1); diff --git a/core/network/src/protocol.rs b/core/network/src/protocol.rs index a85b2e0cec80b779cb223d150699d004d21ab53d..27e615e56ff38e9a64c6e5b61c426da74c7ffe96 100644 --- a/core/network/src/protocol.rs +++ b/core/network/src/protocol.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -15,7 +15,9 @@ // along with Substrate. If not, see . use crossbeam_channel::{self as channel, Receiver, Sender, select}; -use network_libp2p::{NodeIndex, Severity}; +use futures::sync::mpsc; +use parking_lot::Mutex; +use network_libp2p::{PeerId, Severity}; use primitives::storage::StorageKey; use runtime_primitives::generic::BlockId; use runtime_primitives::traits::{As, Block as BlockT, Header as HeaderT, NumberFor, Zero}; @@ -28,6 +30,7 @@ use crate::specialization::NetworkSpecialization; use crate::sync::{ChainSync, Status as SyncStatus, SyncState}; use crate::service::{NetworkChan, NetworkMsg, TransactionPool, ExHashT}; use crate::config::{ProtocolConfig, Roles}; +use parking_lot::RwLock; use rustc_hex::ToHex; use std::collections::{BTreeMap, HashMap}; use std::sync::Arc; @@ -39,8 +42,12 @@ use client::light::fetcher::ChangesProof; use crate::{error, util::LruHashSet}; const REQUEST_TIMEOUT_SEC: u64 = 40; -const TICK_TIMEOUT: time::Duration = time::Duration::from_millis(1000); -const PROPAGATE_TIMEOUT: time::Duration = time::Duration::from_millis(5000); +/// Interval at which we perform time based maintenance +const TICK_TIMEOUT: time::Duration = time::Duration::from_millis(1100); +/// Interval at which we propagate exstrinsics; +const PROPAGATE_TIMEOUT: time::Duration = time::Duration::from_millis(2900); +/// Interval at which we send status updates on the SyncProvider status stream. +const STATUS_INTERVAL: time::Duration = time::Duration::from_millis(5000); /// Current protocol version. pub(crate) const CURRENT_VERSION: u32 = 2; @@ -56,8 +63,10 @@ const LIGHT_MAXIMAL_BLOCKS_DIFFERENCE: u64 = 8192; // Lock must always be taken in order declared here. pub struct Protocol, H: ExHashT> { + status_sinks: Arc>>>>, network_chan: NetworkChan, port: Receiver>, + from_network_port: Receiver>, config: ProtocolConfig, on_demand: Option>>, genesis_hash: B::Hash, @@ -66,9 +75,25 @@ pub struct Protocol, H: ExHashT> { consensus_gossip: ConsensusGossip, context_data: ContextData, // Connected peers pending Status message. - handshaking_peers: HashMap, + handshaking_peers: HashMap, + // Connected peers from whom we received a Status message, + // similar to context_data.peers but shared with the SyncProvider. + connected_peers: Arc>>>, transaction_pool: Arc>, } + +/// A peer from whom we have received a Status message. +#[derive(Clone)] +pub struct ConnectedPeer { + pub peer_info: PeerInfo +} + +/// A peer that we are connected to +/// and from whom we have not yet received a Status message. +struct HandshakingPeer { + timestamp: time::Instant, +} + /// Syncing status and statistics #[derive(Clone)] pub struct ProtocolStatus { @@ -115,13 +140,13 @@ pub trait Context { fn client(&self) -> &crate::chain::Client; /// Point out that a peer has been malign or irresponsible or appeared lazy. - fn report_peer(&mut self, who: NodeIndex, reason: Severity); + fn report_peer(&mut self, who: PeerId, reason: Severity); /// Get peer info. - fn peer_info(&self, peer: NodeIndex) -> Option>; + fn peer_info(&self, peer: &PeerId) -> Option>; /// Send a message to a peer. - fn send_message(&mut self, who: NodeIndex, data: crate::message::Message); + fn send_message(&mut self, who: PeerId, data: crate::message::Message); } /// Protocol context. @@ -137,16 +162,16 @@ impl<'a, B: BlockT + 'a, H: 'a + ExHashT> ProtocolContext<'a, B, H> { } impl<'a, B: BlockT + 'a, H: ExHashT + 'a> Context for ProtocolContext<'a, B, H> { - fn send_message(&mut self, who: NodeIndex, message: Message) { + fn send_message(&mut self, who: PeerId, message: Message) { send_message(&mut self.context_data.peers, &self.network_chan, who, message) } - fn report_peer(&mut self, who: NodeIndex, reason: Severity) { + fn report_peer(&mut self, who: PeerId, reason: Severity) { self.network_chan.send(NetworkMsg::ReportPeer(who, reason)) } - fn peer_info(&self, who: NodeIndex) -> Option> { - self.context_data.peers.get(&who).map(|p| p.info.clone()) + fn peer_info(&self, who: &PeerId) -> Option> { + self.context_data.peers.get(who).map(|p| p.info.clone()) } fn client(&self) -> &Client { @@ -157,7 +182,7 @@ impl<'a, B: BlockT + 'a, H: ExHashT + 'a> Context for ProtocolContext<'a, B, /// Data necessary to create a context. struct ContextData { // All connected peers - peers: HashMap>, + peers: HashMap>, pub chain: Arc>, } @@ -183,44 +208,36 @@ impl, &mut Context)> GossipTask< } } -/// Messages sent to Protocol. -pub enum ProtocolMsg,> { - /// A peer connected, with debug info. - PeerConnected(NodeIndex, String), - /// A peer disconnected, with debug info. - PeerDisconnected(NodeIndex, String), - /// A custom message from another peer. - CustomMessage(NodeIndex, Message), - /// Ask the protocol for its status. - Status(Sender>), - /// Tell protocol to propagate extrinsics. - PropagateExtrinsics, - /// 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. - GossipConsensusMessage(B::Hash, ConsensusEngineId, Vec), - /// Return a list of peers currently known to protocol. - Peers(Sender)>>), - /// Let protocol know a peer is currenlty clogged. - PeerClogged(NodeIndex, Option>), - /// Tell protocol to maintain sync. - MaintainSync, +/// 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, - /// Propagate a block to peers. - AnnounceBlock(B::Hash), + /// Propagate status updates. + Status, + /// Tell protocol to propagate extrinsics. + 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), + /// 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. + GossipConsensusMessage(B::Hash, ConsensusEngineId, Vec, bool), /// Tell protocol to abort sync (does not stop protocol). /// Only used in tests. #[cfg(any(test, feature = "test-helpers"))] @@ -231,11 +248,30 @@ pub enum ProtocolMsg,> { Tick, } +/// Messages sent to Protocol from Network-libp2p. +pub enum FromNetworkMsg { + /// A peer connected, with debug info. + PeerConnected(PeerId, String), + /// A peer disconnected, with debug info. + PeerDisconnected(PeerId, String), + /// A custom message from another peer. + CustomMessage(PeerId, Message), + /// Let protocol know a peer is currenlty clogged. + PeerClogged(PeerId, Option>), +} + +enum Incoming> { + FromNetwork(FromNetworkMsg), + FromClient(ProtocolMsg) +} + impl, H: ExHashT> Protocol { /// Create a new instance. pub fn new( + status_sinks: Arc>>>>, is_offline: Arc, is_major_syncing: Arc, + connected_peers: Arc>>>, network_chan: NetworkChan, config: ProtocolConfig, chain: Arc>, @@ -243,15 +279,18 @@ impl, H: ExHashT> Protocol { on_demand: Option>>, transaction_pool: Arc>, specialization: S, - ) -> error::Result>> { - let (sender, port) = channel::unbounded(); + ) -> error::Result<(Sender>, Sender>)> { + let (protocol_sender, port) = channel::unbounded(); + let (from_network_sender, from_network_port) = channel::bounded(4); let info = chain.info()?; let sync = ChainSync::new(is_offline, is_major_syncing, config.roles, &info, import_queue); let _ = thread::Builder::new() .name("Protocol".into()) .spawn(move || { let mut protocol = Protocol { + status_sinks, network_chan, + from_network_port, port, config: config, context_data: ContextData { @@ -264,56 +303,68 @@ impl, H: ExHashT> Protocol { specialization: specialization, consensus_gossip: ConsensusGossip::new(), handshaking_peers: HashMap::new(), + connected_peers, transaction_pool: transaction_pool, }; let tick_timeout = channel::tick(TICK_TIMEOUT); let propagate_timeout = channel::tick(PROPAGATE_TIMEOUT); - while protocol.run(&tick_timeout, &propagate_timeout) { + let status_interval = channel::tick(STATUS_INTERVAL); + while protocol.run(&tick_timeout, &propagate_timeout, &status_interval) { // Running until all senders have been dropped... } }) .expect("Protocol thread spawning failed"); - Ok(sender) + Ok((protocol_sender, from_network_sender)) } fn run( &mut self, tick_timeout: &Receiver, propagate_timeout: &Receiver, + status_interval: &Receiver, ) -> bool { let msg = select! { recv(self.port) -> event => { match event { - Ok(msg) => msg, + Ok(msg) => Incoming::FromClient(msg), // Our sender has been dropped, quit. Err(_) => { - ProtocolMsg::Stop + Incoming::FromClient(ProtocolMsg::Stop) + }, + } + }, + recv(self.from_network_port) -> event => { + match event { + Ok(msg) => Incoming::FromNetwork(msg), + // Our sender has been dropped, quit. + Err(_) => { + Incoming::FromClient(ProtocolMsg::Stop) }, } }, recv(tick_timeout) -> _ => { - ProtocolMsg::Tick + Incoming::FromClient(ProtocolMsg::Tick) }, recv(propagate_timeout) -> _ => { - ProtocolMsg::PropagateExtrinsics + Incoming::FromClient(ProtocolMsg::PropagateExtrinsics) + }, + recv(status_interval) -> _ => { + Incoming::FromClient(ProtocolMsg::Status) }, }; self.handle_msg(msg) } - fn handle_msg(&mut self, msg: ProtocolMsg) -> bool { + fn handle_msg(&mut self, msg: Incoming) -> bool { match msg { - ProtocolMsg::Peers(sender) => { - let peers = self.context_data.peers.iter().map(|(idx, p)| (*idx, p.info.clone())).collect(); - let _ = sender.send(peers); - }, - ProtocolMsg::PeerDisconnected(who, debug_info) => self.on_peer_disconnected(who, debug_info), - ProtocolMsg::PeerConnected(who, debug_info) => self.on_peer_connected(who, debug_info), - ProtocolMsg::PeerClogged(who, message) => self.on_clogged_peer(who, message), - ProtocolMsg::CustomMessage(who, message) => { - self.on_custom_message(who, message) - }, - ProtocolMsg::Status(sender) => self.status(sender), + Incoming::FromNetwork(msg) => self.handle_network_msg(msg), + Incoming::FromClient(msg) => self.handle_client_msg(msg), + } + } + + fn handle_client_msg(&mut self, msg: ProtocolMsg) -> bool { + match msg { + ProtocolMsg::Status => self.on_status(), ProtocolMsg::BlockImported(hash, header) => self.on_block_imported(hash, &header), ProtocolMsg::BlockFinalized(hash, header) => self.on_block_finalized(hash, &header), ProtocolMsg::ExecuteWithSpec(task) => { @@ -326,14 +377,15 @@ impl, H: ExHashT> Protocol { ProtocolContext::new(&mut self.context_data, &self.network_chan); task.call_box(&mut self.consensus_gossip, &mut context); } - ProtocolMsg::GossipConsensusMessage(topic, engine_id, message) => { - self.gossip_consensus_message(topic, engine_id, message) + ProtocolMsg::GossipConsensusMessage(topic, engine_id, message, force) => { + self.gossip_consensus_message(topic, engine_id, message, force) } - ProtocolMsg::MaintainSync => { + ProtocolMsg::BlocksProcessed(hashes, has_error) => { + self.sync.blocks_processed(hashes, has_error); let mut context = ProtocolContext::new(&mut self.context_data, &self.network_chan); self.sync.maintain_sync(&mut context); - } + }, ProtocolMsg::RestartSync => { let mut context = ProtocolContext::new(&mut self.context_data, &self.network_chan); @@ -341,6 +393,7 @@ impl, H: ExHashT> Protocol { } ProtocolMsg::AnnounceBlock(hash) => self.announce_block(hash), ProtocolMsg::BlockImportedSync(hash, number) => self.sync.block_imported(&hash, number), + ProtocolMsg::ClearJustificationRequests => self.sync.clear_justification_requests(), ProtocolMsg::RequestJustification(hash, number) => { let mut context = ProtocolContext::new(&mut self.context_data, &self.network_chan); @@ -359,7 +412,19 @@ impl, H: ExHashT> Protocol { true } - fn handle_response(&mut self, who: NodeIndex, response: &message::BlockResponse) -> Option> { + fn handle_network_msg(&mut self, msg: FromNetworkMsg) -> bool { + match msg { + FromNetworkMsg::PeerDisconnected(who, debug_info) => self.on_peer_disconnected(who, debug_info), + FromNetworkMsg::PeerConnected(who, debug_info) => self.on_peer_connected(who, debug_info), + FromNetworkMsg::PeerClogged(who, message) => self.on_clogged_peer(who, message), + FromNetworkMsg::CustomMessage(who, message) => { + self.on_custom_message(who, message) + }, + } + true + } + + fn handle_response(&mut self, who: PeerId, response: &message::BlockResponse) -> Option> { if let Some(ref mut peer) = self.context_data.peers.get_mut(&who) { if let Some(_) = peer.obsolete_requests.remove(&response.id) { trace!(target: "sync", "Ignoring obsolete block response packet from {} ({})", who, response.id,); @@ -377,8 +442,22 @@ impl, H: ExHashT> Protocol { None } - /// Returns protocol status - fn status(&mut self, sender: Sender>) { + fn update_peer_info(&mut self, who: &PeerId) { + if let Some(info) = self.sync.peer_info(who) { + if let Some(ref mut peer) = self.context_data.peers.get_mut(who) { + peer.info.best_hash = info.best_hash; + peer.info.best_number = info.best_number; + } + let mut peers = self.connected_peers.write(); + if let Some(ref mut peer) = peers.get_mut(who) { + peer.peer_info.best_hash = info.best_hash; + peer.peer_info.best_number = info.best_number; + } + } + } + + /// Propagates protocol statuses. + fn on_status(&mut self) { let status = ProtocolStatus { sync: self.sync.status(), num_peers: self.context_data.peers.values().count(), @@ -389,19 +468,23 @@ impl, H: ExHashT> Protocol { .filter(|p| p.block_request.is_some()) .count(), }; - let _ = sender.send(status); + self.status_sinks.lock().retain(|sink| sink.unbounded_send(status.clone()).is_ok()); } - fn on_custom_message(&mut self, who: NodeIndex, message: Message) { + fn on_custom_message(&mut self, who: PeerId, message: Message) { match message { GenericMessage::Status(s) => self.on_status_message(who, s), GenericMessage::BlockRequest(r) => self.on_block_request(who, r), GenericMessage::BlockResponse(r) => { - if let Some(request) = self.handle_response(who, &r) { - self.on_block_response(who, request, r); + if let Some(request) = self.handle_response(who.clone(), &r) { + self.on_block_response(who.clone(), request, r); + self.update_peer_info(&who); } }, - GenericMessage::BlockAnnounce(announce) => self.on_block_announce(who, announce), + GenericMessage::BlockAnnounce(announce) => { + self.on_block_announce(who.clone(), announce); + self.update_peer_info(&who); + }, GenericMessage::Transactions(m) => self.on_extrinsics(who, m), GenericMessage::RemoteCallRequest(request) => self.on_remote_call_request(who, request), GenericMessage::RemoteCallResponse(response) => self.on_remote_call_response(who, response), @@ -416,7 +499,6 @@ impl, H: ExHashT> Protocol { &mut ProtocolContext::new(&mut self.context_data, &self.network_chan), who, msg, - self.sync.status().is_major_syncing(), ); } other => self.specialization.on_message( @@ -427,7 +509,7 @@ impl, H: ExHashT> Protocol { } } - fn send_message(&mut self, who: NodeIndex, message: Message) { + fn send_message(&mut self, who: PeerId, message: Message) { send_message::( &mut self.context_data.peers, &self.network_chan, @@ -436,41 +518,49 @@ impl, H: ExHashT> Protocol { ); } - fn gossip_consensus_message(&mut self, topic: B::Hash, engine_id: ConsensusEngineId, message: Vec) { + fn gossip_consensus_message( + &mut self, + topic: B::Hash, + engine_id: ConsensusEngineId, + message: Vec, + force: bool, + ) { self.consensus_gossip.multicast( &mut ProtocolContext::new(&mut self.context_data, &self.network_chan), topic, ConsensusMessage{ data: message, engine_id }, + force, ); } /// Called when a new peer is connected - fn on_peer_connected(&mut self, who: NodeIndex, debug_info: String) { + fn on_peer_connected(&mut self, who: PeerId, debug_info: String) { trace!(target: "sync", "Connecting {}: {}", who, debug_info); - self.handshaking_peers.insert(who, time::Instant::now()); + self.handshaking_peers.insert(who.clone(), HandshakingPeer { timestamp: time::Instant::now() }); self.send_status(who); } /// Called by peer when it is disconnecting - fn on_peer_disconnected(&mut self, peer: NodeIndex, debug_info: String) { + fn on_peer_disconnected(&mut self, peer: PeerId, debug_info: String) { trace!(target: "sync", "Disconnecting {}: {}", peer, debug_info); // lock all the the peer lists so that add/remove peer events are in order let removed = { self.handshaking_peers.remove(&peer); + self.connected_peers.write().remove(&peer); self.context_data.peers.remove(&peer).is_some() }; if removed { let mut context = ProtocolContext::new(&mut self.context_data, &self.network_chan); - self.consensus_gossip.peer_disconnected(&mut context, peer); - self.sync.peer_disconnected(&mut context, peer); - self.specialization.on_disconnect(&mut context, peer); + self.consensus_gossip.peer_disconnected(&mut context, peer.clone()); + self.sync.peer_disconnected(&mut context, peer.clone()); + self.specialization.on_disconnect(&mut context, peer.clone()); self.on_demand.as_ref().map(|s| s.on_disconnect(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, who: NodeIndex, _msg: Option>) { + pub fn on_clogged_peer(&self, who: PeerId, _msg: Option>) { // We don't do anything but print some diagnostics for now. if let Some(peer) = self.context_data.peers.get(&who) { debug!(target: "sync", "Clogged peer {} (protocol_version: {:?}; roles: {:?}; \ @@ -482,7 +572,7 @@ impl, H: ExHashT> Protocol { } } - fn on_block_request(&mut self, peer: NodeIndex, request: message::BlockRequest) { + fn on_block_request(&mut self, peer: PeerId, request: message::BlockRequest) { trace!(target: "sync", "BlockRequest {} from {}: from {:?} to {:?} max {:?}", request.id, peer, @@ -548,7 +638,7 @@ impl, H: ExHashT> Protocol { fn on_block_response( &mut self, - peer: NodeIndex, + peer: PeerId, request: message::BlockRequest, response: message::BlockResponse, ) { @@ -573,16 +663,7 @@ impl, H: ExHashT> Protocol { response, ); } else { - // import_queue.import_blocks also acquires sync.write(); - // Break the cycle by doing these separately from the outside; - let new_blocks = { - self.sync.on_block_data(&mut ProtocolContext::new(&mut self.context_data, &self.network_chan), peer, request, response) - }; - - if let Some((origin, new_blocks)) = new_blocks { - let import_queue = self.sync.import_queue(); - import_queue.import_blocks(origin, new_blocks); - } + self.sync.on_block_data(&mut ProtocolContext::new(&mut self.context_data, &self.network_chan), peer, request, response); } } @@ -603,15 +684,15 @@ impl, H: ExHashT> Protocol { for (who, peer) in self.context_data.peers.iter() { if peer.block_request.as_ref().map_or(false, |(t, _)| (tick - *t).as_secs() > REQUEST_TIMEOUT_SEC) { trace!(target: "sync", "Reqeust timeout {}", who); - aborting.push(*who); + aborting.push(who.clone()); } else if peer.obsolete_requests.values().any(|t| (tick - *t).as_secs() > REQUEST_TIMEOUT_SEC) { trace!(target: "sync", "Obsolete timeout {}", who); - aborting.push(*who); + aborting.push(who.clone()); } } - for (who, _) in self.handshaking_peers.iter().filter(|(_, t)| (tick - **t).as_secs() > REQUEST_TIMEOUT_SEC) { + for (who, _) in self.handshaking_peers.iter().filter(|(_, handshaking)| (tick - handshaking.timestamp).as_secs() > REQUEST_TIMEOUT_SEC) { trace!(target: "sync", "Handshake timeout {}", who); - aborting.push(*who); + aborting.push(who.clone()); } } @@ -624,7 +705,7 @@ impl, H: ExHashT> Protocol { } /// Called by peer to report status - fn on_status_message(&mut self, who: NodeIndex, status: message::Status) { + fn on_status_message(&mut self, who: PeerId, status: message::Status) { trace!(target: "sync", "New peer {} {:?}", who, status); { if self.context_data.peers.contains_key(&who) { @@ -676,13 +757,27 @@ impl, H: ExHashT> Protocol { let cache_limit = NonZeroUsize::new(1_000_000).expect("1_000_000 > 0; qed"); - let peer = Peer { - info: PeerInfo { - protocol_version: status.version, - roles: status.roles, - best_hash: status.best_hash, - best_number: status.best_number + let info = match self.handshaking_peers.remove(&who) { + Some(_handshaking) => { + let peer_info = PeerInfo { + protocol_version: status.version, + roles: status.roles, + best_hash: status.best_hash, + best_number: status.best_number + }; + self.connected_peers + .write() + .insert(who.clone(), ConnectedPeer { peer_info: peer_info.clone() }); + peer_info + }, + None => { + debug!(target: "sync", "Received status from previously unconnected node {}", who); + return; }, + }; + + let peer = Peer { + info, block_request: None, known_extrinsics: LruHashSet::new(cache_limit), known_blocks: LruHashSet::new(cache_limit), @@ -690,22 +785,22 @@ impl, H: ExHashT> Protocol { obsolete_requests: HashMap::new(), }; self.context_data.peers.insert(who.clone(), peer); - self.handshaking_peers.remove(&who); + debug!(target: "sync", "Connected {}", who); } let mut context = ProtocolContext::new(&mut self.context_data, &self.network_chan); self.on_demand .as_ref() - .map(|s| s.on_connect(who, status.roles, status.best_number)); - self.sync.new_peer(&mut context, who); + .map(|s| s.on_connect(who.clone(), status.roles, status.best_number)); + self.sync.new_peer(&mut context, who.clone()); self.consensus_gossip - .new_peer(&mut context, who, status.roles); + .new_peer(&mut context, who.clone(), status.roles); self.specialization.on_connect(&mut context, who, status); } /// Called when peer sends us new extrinsics - fn on_extrinsics(&mut self, who: NodeIndex, extrinsics: message::Transactions) { + fn on_extrinsics(&mut self, who: PeerId, extrinsics: message::Transactions) { // Accept extrinsics only when fully synced if self.sync.status().state != SyncState::Idle { trace!(target: "sync", "{} Ignoring extrinsics while syncing", who); @@ -734,7 +829,7 @@ impl, H: ExHashT> Protocol { let extrinsics = self.transaction_pool.transactions(); let mut propagated_to = HashMap::new(); - for (who, ref mut peer) in self.context_data.peers.iter_mut() { + for (who, peer) in self.context_data.peers.iter_mut() { let (hashes, to_send): (Vec<_>, Vec<_>) = extrinsics .iter() .filter(|&(ref hash, _)| peer.known_extrinsics.insert(hash.clone())) @@ -742,21 +837,14 @@ impl, H: ExHashT> Protocol { .unzip(); if !to_send.is_empty() { - let (sender, port) = channel::unbounded(); - let _ = self - .network_chan - .send(NetworkMsg::GetPeerId(who.clone(), sender)); - let node_id = port.recv().expect("1. We are running 2. Network should be running too."); - if let Some(id) = node_id { - for hash in hashes { - propagated_to - .entry(hash) - .or_insert_with(Vec::new) - .push(id.clone()); - } + for hash in hashes { + propagated_to + .entry(hash) + .or_insert_with(Vec::new) + .push(who.to_base58()); } trace!(target: "sync", "Sending {} transactions to {}", to_send.len(), who); - self.network_chan.send(NetworkMsg::Outgoing(*who, GenericMessage::Transactions(to_send))) + self.network_chan.send(NetworkMsg::Outgoing(who.clone(), GenericMessage::Transactions(to_send))) } } self.transaction_pool.on_broadcasted(propagated_to); @@ -785,12 +873,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); - self.network_chan.send(NetworkMsg::Outgoing(*who, message.clone())) + self.network_chan.send(NetworkMsg::Outgoing(who.clone(), message.clone())) } } /// Send Status message - fn send_status(&mut self, who: NodeIndex) { + fn send_status(&mut self, who: PeerId) { if let Ok(info) = self.context_data.chain.info() { let status = message::generic::Status { version: CURRENT_VERSION, @@ -821,7 +909,7 @@ impl, H: ExHashT> Protocol { self.abort(); } - fn on_block_announce(&mut self, who: NodeIndex, announce: message::BlockAnnounce) { + fn on_block_announce(&mut self, who: PeerId, announce: message::BlockAnnounce) { let header = announce.header; let hash = header.hash(); { @@ -831,7 +919,7 @@ impl, H: ExHashT> Protocol { } self.on_demand .as_ref() - .map(|s| s.on_block_announce(who, *header.number())); + .map(|s| s.on_block_announce(who.clone(), *header.number())); self.sync.on_block_announce( &mut ProtocolContext::new(&mut self.context_data, &self.network_chan), who, @@ -860,7 +948,7 @@ 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); - self.network_chan.send(NetworkMsg::Outgoing(*who, message.clone())) + self.network_chan.send(NetworkMsg::Outgoing(who.clone(), message.clone())) } } } @@ -875,7 +963,7 @@ impl, H: ExHashT> Protocol { fn on_remote_call_request( &mut self, - who: NodeIndex, + who: PeerId, request: message::RemoteCallRequest, ) { trace!(target: "sync", "Remote call request {} from {} ({} at {})", request.id, who, request.method, request.block); @@ -901,7 +989,7 @@ impl, H: ExHashT> Protocol { ); } - fn on_remote_call_response(&mut self, who: NodeIndex, response: message::RemoteCallResponse) { + fn on_remote_call_response(&mut self, who: PeerId, response: message::RemoteCallResponse) { trace!(target: "sync", "Remote call response {} from {}", response.id, who); self.on_demand .as_ref() @@ -910,7 +998,7 @@ impl, H: ExHashT> Protocol { fn on_remote_read_request( &mut self, - who: NodeIndex, + who: PeerId, request: message::RemoteReadRequest, ) { trace!(target: "sync", "Remote read request {} from {} ({} at {})", @@ -931,7 +1019,7 @@ impl, H: ExHashT> Protocol { }), ); } - fn on_remote_read_response(&mut self, who: NodeIndex, response: message::RemoteReadResponse) { + fn on_remote_read_response(&mut self, who: PeerId, response: message::RemoteReadResponse) { trace!(target: "sync", "Remote read response {} from {}", response.id, who); self.on_demand .as_ref() @@ -940,7 +1028,7 @@ impl, H: ExHashT> Protocol { fn on_remote_header_request( &mut self, - who: NodeIndex, + who: PeerId, request: message::RemoteHeaderRequest>, ) { trace!(target: "sync", "Remote header proof request {} from {} ({})", @@ -965,7 +1053,7 @@ impl, H: ExHashT> Protocol { fn on_remote_header_response( &mut self, - who: NodeIndex, + who: PeerId, response: message::RemoteHeaderResponse, ) { trace!(target: "sync", "Remote header proof response {} from {}", response.id, who); @@ -976,7 +1064,7 @@ impl, H: ExHashT> Protocol { fn on_remote_changes_request( &mut self, - who: NodeIndex, + who: PeerId, request: message::RemoteChangesRequest, ) { trace!(target: "sync", "Remote changes proof request {} from {} for key {} ({}..{})", @@ -1009,7 +1097,7 @@ impl, H: ExHashT> Protocol { fn on_remote_changes_response( &mut self, - who: NodeIndex, + who: PeerId, response: message::RemoteChangesResponse, B::Hash>, ) { trace!(target: "sync", "Remote changes proof response {} from {} (max={})", @@ -1021,9 +1109,9 @@ impl, H: ExHashT> Protocol { } fn send_message( - peers: &mut HashMap>, + peers: &mut HashMap>, network_chan: &NetworkChan, - who: NodeIndex, + who: PeerId, mut message: Message, ) { if let GenericMessage::BlockRequest(ref mut r) = message { @@ -1100,20 +1188,20 @@ macro_rules! construct_simple_protocol { fn on_connect( &mut self, _ctx: &mut $crate::Context<$block>, - _who: $crate::NodeIndex, + _who: $crate::PeerId, _status: $crate::StatusMessage<$block> ) { $( self.$sub_protocol_name.on_connect(_ctx, _who, _status); )* } - fn on_disconnect(&mut self, _ctx: &mut $crate::Context<$block>, _who: $crate::NodeIndex) { + fn on_disconnect(&mut self, _ctx: &mut $crate::Context<$block>, _who: $crate::PeerId) { $( self.$sub_protocol_name.on_disconnect(_ctx, _who); )* } fn on_message( &mut self, _ctx: &mut $crate::Context<$block>, - _who: $crate::NodeIndex, + _who: $crate::PeerId, _message: &mut Option<$crate::message::Message<$block>> ) { $( self.$sub_protocol_name.on_message(_ctx, _who, _message); )* diff --git a/core/network/src/service.rs b/core/network/src/service.rs index cc5f6ffeea80fdf0c4ff8ff90f1a5cd9392358f0..d0cd0540d2f02da145a991895350ae6a0db59d25 100644 --- a/core/network/src/service.rs +++ b/core/network/src/service.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -19,15 +19,16 @@ use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use std::{io, thread}; use log::{warn, debug, error, trace, info}; -use futures::{Async, Future, Stream, stream, sync::oneshot}; -use parking_lot::Mutex; -use network_libp2p::{ProtocolId, NetworkConfiguration, NodeIndex, ErrorKind, Severity}; +use futures::{Async, Future, Stream, stream, sync::oneshot, sync::mpsc}; +use parking_lot::{Mutex, RwLock}; +use network_libp2p::{ProtocolId, NetworkConfiguration, Severity}; use network_libp2p::{start_service, parse_str_addr, Service as NetworkService, ServiceEvent as NetworkServiceEvent}; -use network_libp2p::{Protocol as Libp2pProtocol, RegisteredProtocol}; +use network_libp2p::{multiaddr, RegisteredProtocol, NetworkState}; +use peerset::Peerset; use consensus::import_queue::{ImportQueue, Link}; use crate::consensus_gossip::ConsensusGossip; use crate::message::{Message, ConsensusEngineId}; -use crate::protocol::{self, Context, Protocol, ProtocolMsg, ProtocolStatus, PeerInfo}; +use crate::protocol::{self, Context, FromNetworkMsg, Protocol, ConnectedPeer, ProtocolMsg, ProtocolStatus, PeerInfo}; use crate::config::Params; use crossbeam_channel::{self as channel, Receiver, Sender, TryRecvError}; use crate::error::Error; @@ -42,12 +43,17 @@ pub use network_libp2p::PeerId; /// Type that represents fetch completion future. pub type FetchFuture = oneshot::Receiver>; + /// Sync status pub trait SyncProvider: Send + Sync { - /// Get sync status - fn status(&self) -> ProtocolStatus; + /// Get a stream of sync statuses. + fn status(&self) -> mpsc::UnboundedReceiver>; + /// Get network state. + fn network_state(&self) -> NetworkState; /// Get currently connected peers - fn peers(&self) -> Vec<(NodeIndex, Option, PeerInfo)>; + fn peers(&self) -> Vec<(PeerId, PeerInfo)>; + /// Are we in the process of downloading the chain? + fn is_major_syncing(&self) -> bool; } /// Minimum Requirements for a Hash within Networking @@ -71,6 +77,7 @@ pub trait TransactionPool: Send + Sync { } /// A link implementation that connects to the network. +#[derive(Clone)] pub struct NetworkLink> { /// The protocol sender pub(crate) protocol_sender: Sender>, @@ -83,7 +90,11 @@ impl> Link for NetworkLink { let _ = self.protocol_sender.send(ProtocolMsg::BlockImportedSync(hash.clone(), number)); } - fn justification_imported(&self, who: NodeIndex, hash: &B::Hash, number: NumberFor, success: bool) { + fn blocks_processed(&self, processed_blocks: Vec, has_error: bool) { + let _ = self.protocol_sender.send(ProtocolMsg::BlocksProcessed(processed_blocks, has_error)); + } + + fn justification_imported(&self, who: PeerId, hash: &B::Hash, number: NumberFor, success: bool) { let _ = self.protocol_sender.send(ProtocolMsg::JustificationImportResult(hash.clone(), number, success)); if !success { let reason = Severity::Bad(format!("Invalid justification provided for #{}", hash).to_string()); @@ -91,20 +102,20 @@ impl> Link for NetworkLink { } } - fn request_justification(&self, hash: &B::Hash, number: NumberFor) { - let _ = self.protocol_sender.send(ProtocolMsg::RequestJustification(hash.clone(), number)); + fn clear_justification_requests(&self) { + let _ = self.protocol_sender.send(ProtocolMsg::ClearJustificationRequests); } - fn maintain_sync(&self) { - let _ = self.protocol_sender.send(ProtocolMsg::MaintainSync); + fn request_justification(&self, hash: &B::Hash, number: NumberFor) { + let _ = self.protocol_sender.send(ProtocolMsg::RequestJustification(hash.clone(), number)); } - fn useless_peer(&self, who: NodeIndex, reason: &str) { + fn useless_peer(&self, who: PeerId, reason: &str) { trace!(target:"sync", "Useless peer {}, {}", who, reason); self.network_sender.send(NetworkMsg::ReportPeer(who, Severity::Useless(reason.to_string()))); } - fn note_useless_and_restart_sync(&self, who: NodeIndex, reason: &str) { + fn note_useless_and_restart_sync(&self, who: PeerId, reason: &str) { trace!(target:"sync", "Bad peer {}, {}", who, reason); // is this actually malign or just useless? self.network_sender.send(NetworkMsg::ReportPeer(who, Severity::Useless(reason.to_string()))); @@ -118,12 +129,19 @@ impl> Link for NetworkLink { /// Substrate network service. Handles network IO and manages connectivity. pub struct Service> { - // Are we connected to any peer? + /// Sinks to propagate status updates. + status_sinks: Arc>>>>, + /// Are we connected to any peer? is_offline: Arc, - // Are we actively catching up with the chain? + /// Are we actively catching up with the chain? is_major_syncing: Arc, + /// Peers whom we are connected with. + peers: Arc>>>, /// Network service network: Arc>>>, + /// Peerset manager (PSM); manages the reputation of nodes and indicates the network which + /// nodes it should be connected to or not. + peerset: Arc, /// Protocol sender protocol_sender: Sender>, /// Sender for messages to the background service task, and handle for the background thread. @@ -139,13 +157,17 @@ impl> Service { protocol_id: ProtocolId, import_queue: Box>, ) -> Result<(Arc>, NetworkChan), Error> { - let (network_chan, network_port) = network_channel(protocol_id); + let (network_chan, network_port) = network_channel(); + let status_sinks = Arc::new(Mutex::new(Vec::new())); // Start in off-line mode, since we're not connected to any nodes yet. let is_offline = Arc::new(AtomicBool::new(true)); let is_major_syncing = Arc::new(AtomicBool::new(false)); - let protocol_sender = Protocol::new( + let peers: Arc>>> = Arc::new(Default::default()); + let (protocol_sender, network_to_protocol_sender) = Protocol::new( + status_sinks.clone(), is_offline.clone(), is_major_syncing.clone(), + peers.clone(), network_chan.clone(), params.config, params.chain, @@ -156,16 +178,19 @@ impl> Service { )?; let versions = [(protocol::CURRENT_VERSION as u8)]; let registered = RegisteredProtocol::new(protocol_id, &versions[..]); - let (thread, network) = start_thread( - protocol_sender.clone(), + let (thread, network, peerset) = start_thread( + network_to_protocol_sender, network_port, params.network_config, registered, )?; let service = Arc::new(Service { + status_sinks, is_offline, is_major_syncing, + peers, + peerset, network, protocol_sender: protocol_sender.clone(), bg_thread: Some(thread), @@ -227,11 +252,17 @@ impl> Service { } /// Send a consensus message through the gossip - pub fn gossip_consensus_message(&self, topic: B::Hash, engine_id: ConsensusEngineId, message: Vec) { + pub fn gossip_consensus_message( + &self, + topic: B::Hash, + engine_id: ConsensusEngineId, + message: Vec, + force: bool, + ) { let _ = self .protocol_sender .send(ProtocolMsg::GossipConsensusMessage( - topic, engine_id, message, + topic, engine_id, message, force, )); } @@ -252,11 +283,17 @@ impl> Service { .protocol_sender .send(ProtocolMsg::ExecuteWithGossip(Box::new(f))); } + + /// Are we in the process of downloading the chain? + /// Used by both SyncProvider and SyncOracle. + fn is_major_syncing(&self) -> bool { + self.is_major_syncing.load(Ordering::Relaxed) + } } impl> ::consensus::SyncOracle for Service { fn is_major_syncing(&self) -> bool { - self.is_major_syncing.load(Ordering::Relaxed) + self.is_major_syncing() } fn is_offline(&self) -> bool { self.is_offline.load(Ordering::Relaxed) @@ -275,25 +312,23 @@ impl> Drop for Service { } impl> SyncProvider for Service { + fn is_major_syncing(&self) -> bool { + self.is_major_syncing() + } /// Get sync status - fn status(&self) -> ProtocolStatus { - let (sender, port) = channel::unbounded(); - let _ = self.protocol_sender.send(ProtocolMsg::Status(sender)); - port.recv().expect("1. Protocol keeps handling messages until all senders are dropped, - or the ProtocolMsg::Stop message is received, - 2 Service keeps a sender to protocol, and the ProtocolMsg::Stop is never sent.") - } - - fn peers(&self) -> Vec<(NodeIndex, Option, PeerInfo)> { - let (sender, port) = channel::unbounded(); - let _ = self.protocol_sender.send(ProtocolMsg::Peers(sender)); - let peers = port.recv().expect("1. Protocol keeps handling messages until all senders are dropped, - or the ProtocolMsg::Stop message is received, - 2 Service keeps a sender to protocol, and the ProtocolMsg::Stop is never sent."); - let network = self.network.lock(); - peers.into_iter().map(|(idx, info)| { - (idx, network.peer_id_of_node(idx).map(|p| p.clone()), info) - }).collect::>() + fn status(&self) -> mpsc::UnboundedReceiver> { + let (sink, stream) = mpsc::unbounded(); + self.status_sinks.lock().push(sink); + stream + } + + fn network_state(&self) -> NetworkState { + self.network.lock().state() + } + + fn peers(&self) -> Vec<(PeerId, PeerInfo)> { + let peers = (*self.peers.read()).clone(); + peers.into_iter().map(|(idx, connected)| (idx, connected.peer_info)).collect() } } @@ -313,20 +348,21 @@ pub trait ManageNetwork { impl> ManageNetwork for Service { fn accept_unreserved_peers(&self) { - self.network.lock().accept_unreserved_peers(); + self.peerset.set_reserved_only(false); } fn deny_unreserved_peers(&self) { - self.network.lock().deny_unreserved_peers(); + self.peerset.set_reserved_only(true); } fn remove_reserved_peer(&self, peer: PeerId) { - self.network.lock().remove_reserved_peer(peer); + self.peerset.remove_reserved_peer(&peer); } fn add_reserved_peer(&self, peer: String) -> Result<(), String> { - let (addr, peer_id) = parse_str_addr(&peer).map_err(|e| format!("{:?}", e))?; - self.network.lock().add_reserved_peer(addr, peer_id); + 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); Ok(()) } @@ -337,7 +373,7 @@ impl> ManageNetwork for Service .next() .map(|addr| { let mut addr = addr.clone(); - addr.append(Libp2pProtocol::P2p(network.peer_id().clone().into())); + addr.append(multiaddr::Protocol::P2p(network.peer_id().clone().into())); addr.to_string() }); ret @@ -346,10 +382,10 @@ impl> ManageNetwork for Service /// Create a NetworkPort/Chan pair. -pub fn network_channel(protocol_id: ProtocolId) -> (NetworkChan, NetworkPort) { +pub fn network_channel() -> (NetworkChan, NetworkPort) { let (network_sender, network_receiver) = channel::unbounded(); let task_notify = Arc::new(AtomicTask::new()); - let network_port = NetworkPort::new(network_receiver, protocol_id, task_notify.clone()); + let network_port = NetworkPort::new(network_receiver, task_notify.clone()); let network_chan = NetworkChan::new(network_sender, task_notify); (network_chan, network_port) } @@ -389,26 +425,24 @@ impl Drop for NetworkChan { /// A receiver of NetworkMsg that makes the protocol-id available with each message. pub struct NetworkPort { receiver: Receiver>, - protocol_id: ProtocolId, task_notify: Arc, } impl NetworkPort { /// Create a new network port for a given protocol-id. - pub fn new(receiver: Receiver>, protocol_id: ProtocolId, task_notify: Arc) -> Self { + pub fn new(receiver: Receiver>, task_notify: Arc) -> Self { Self { receiver, - protocol_id, task_notify, } } /// Receive a message, if any is currently-enqueued. /// Register the current tokio task for notification when a new message is available. - pub fn take_one_message(&self) -> Result)>, ()> { + pub fn take_one_message(&self) -> Result>, ()> { self.task_notify.register(); match self.receiver.try_recv() { - Ok(msg) => Ok(Some((self.protocol_id.clone(), msg))), + Ok(msg) => Ok(Some(msg)), Err(TryRecvError::Empty) => Ok(None), Err(TryRecvError::Disconnected) => Err(()), } @@ -424,34 +458,24 @@ impl NetworkPort { /// Messages to be handled by NetworkService. #[derive(Debug)] pub enum NetworkMsg { - /// Ask network to convert a list of nodes, to a list of peers. - PeerIds(Vec, Sender)>>), /// Send an outgoing custom message. - Outgoing(NodeIndex, Message), + Outgoing(PeerId, Message), /// Report a peer. - ReportPeer(NodeIndex, Severity), - /// Get a peer id. - GetPeerId(NodeIndex, Sender>), + ReportPeer(PeerId, Severity), } /// Starts the background thread that handles the networking. -fn start_thread>( - protocol_sender: Sender>, +fn start_thread( + protocol_sender: Sender>, network_port: NetworkPort, config: NetworkConfiguration, registered: RegisteredProtocol>, -) -> Result<((oneshot::Sender<()>, thread::JoinHandle<()>), Arc>>>), Error> { - let protocol_id = registered.id(); - +) -> Result<((oneshot::Sender<()>, thread::JoinHandle<()>), Arc>>>, Arc), Error> { // Start the main service. - let service = match start_service(config, Some(registered)) { - Ok(service) => Arc::new(Mutex::new(service)), + let (service, peerset) = match start_service(config, registered) { + Ok((service, peerset)) => (Arc::new(Mutex::new(service)), peerset), Err(err) => { - match err.kind() { - ErrorKind::Io(ref e) if e.kind() == io::ErrorKind::AddrInUse => - warn!("Network port is already in use, make sure that another instance of Substrate client is not running or change the port using the --port option."), - _ => warn!("Error starting network: {}", err), - }; + warn!("Error starting network: {}", err); return Err(err.into()) }, }; @@ -460,7 +484,7 @@ fn start_thread>( let service_clone = service.clone(); let mut runtime = RuntimeBuilder::new().name_prefix("libp2p-").build()?; let thread = thread::Builder::new().name("network".to_string()).spawn(move || { - let fut = run_thread(protocol_sender, service_clone, network_port, protocol_id) + let fut = run_thread(protocol_sender, service_clone, network_port) .select(close_rx.then(|_| Ok(()))) .map(|(val, _)| val) .map_err(|(err,_ )| err); @@ -473,15 +497,14 @@ fn start_thread>( }; })?; - Ok(((close_tx, thread), service)) + Ok(((close_tx, thread), service, peerset)) } /// Runs the background thread that handles the networking. -fn run_thread>( - protocol_sender: Sender>, +fn run_thread( + protocol_sender: Sender>, network_service: Arc>>>, network_port: NetworkPort, - protocol_id: ProtocolId, ) -> impl Future { let network_service_2 = network_service.clone(); @@ -493,38 +516,32 @@ fn run_thread>( Ok(None) => Ok(Async::NotReady), Err(_) => Err(()) } - }).for_each(move |(protocol_id, msg)| { + }).for_each(move |msg| { // Handle message from Protocol. match msg { - NetworkMsg::PeerIds(node_idxs, sender) => { - let reply = node_idxs.into_iter().map(|idx| { - (idx, network_service_2.lock().peer_id_of_node(idx).map(|p| p.clone())) - }).collect::>(); - let _ = sender.send(reply); - } NetworkMsg::Outgoing(who, outgoing_message) => { network_service_2 .lock() - .send_custom_message(who, protocol_id, outgoing_message); + .send_custom_message(&who, outgoing_message); }, NetworkMsg::ReportPeer(who, severity) => { match severity { Severity::Bad(message) => { info!(target: "sync", "Banning {:?} because {:?}", who, message); - network_service_2.lock().ban_node(who) + warn!(target: "sync", "Banning a node is a deprecated mechanism that \ + should be removed"); + network_service_2.lock().drop_node(&who) + }, + Severity::Useless(message) => { + debug!(target: "sync", "Dropping {:?} because {:?}", who, message); + network_service_2.lock().drop_node(&who) + }, + Severity::Timeout => { + debug!(target: "sync", "Dropping {:?} because it timed out", who); + network_service_2.lock().drop_node(&who) }, - Severity::Useless(_) => network_service_2.lock().drop_node(who), - Severity::Timeout => network_service_2.lock().drop_node(who), } }, - NetworkMsg::GetPeerId(who, sender) => { - let node_id = network_service_2 - .lock() - .peer_id_of_node(who) - .cloned() - .map(|id| id.to_base58()); - let _ = sender.send(node_id); - }, } Ok(()) }) @@ -539,29 +556,22 @@ fn run_thread>( // The network service produces events about what happens on the network. Let's process them. let network = stream::poll_fn(move || network_service.lock().poll()).for_each(move |event| { match event { - NetworkServiceEvent::ClosedCustomProtocols { node_index, protocols, debug_info } => { - if !protocols.is_empty() { - debug_assert_eq!(protocols, &[protocol_id]); - let _ = protocol_sender.send( - ProtocolMsg::PeerDisconnected(node_index, debug_info)); - } - } - NetworkServiceEvent::OpenedCustomProtocol { node_index, version, debug_info, .. } => { + NetworkServiceEvent::OpenedCustomProtocol { peer_id, version, debug_info, .. } => { debug_assert_eq!(version, protocol::CURRENT_VERSION as u8); - let _ = protocol_sender.send(ProtocolMsg::PeerConnected(node_index, debug_info)); + let _ = protocol_sender.send(FromNetworkMsg::PeerConnected(peer_id, debug_info)); } - NetworkServiceEvent::ClosedCustomProtocol { node_index, debug_info, .. } => { - let _ = protocol_sender.send(ProtocolMsg::PeerDisconnected(node_index, debug_info)); + NetworkServiceEvent::ClosedCustomProtocol { peer_id, debug_info, .. } => { + let _ = protocol_sender.send(FromNetworkMsg::PeerDisconnected(peer_id, debug_info)); } - NetworkServiceEvent::CustomMessage { node_index, message, .. } => { - let _ = protocol_sender.send(ProtocolMsg::CustomMessage(node_index, message)); + NetworkServiceEvent::CustomMessage { peer_id, message, .. } => { + let _ = protocol_sender.send(FromNetworkMsg::CustomMessage(peer_id, message)); return Ok(()) } - NetworkServiceEvent::Clogged { node_index, messages, .. } => { + NetworkServiceEvent::Clogged { peer_id, messages, .. } => { debug!(target: "sync", "{} clogging messages:", messages.len()); for msg in messages.into_iter().take(5) { debug!(target: "sync", "{:?}", msg); - let _ = protocol_sender.send(ProtocolMsg::PeerClogged(node_index, Some(msg))); + let _ = protocol_sender.send(FromNetworkMsg::PeerClogged(peer_id.clone(), Some(msg))); } } }; diff --git a/core/network/src/specialization.rs b/core/network/src/specialization.rs index 662dfdad75151865cad4c86690f16359cda90ec6..e440097dd1f674cc5e0afc41751e9b12dd1dcce9 100644 --- a/core/network/src/specialization.rs +++ b/core/network/src/specialization.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ //! Specializations of the substrate network protocol to allow more complex forms of communication. -use crate::NodeIndex; +use crate::PeerId; use runtime_primitives::traits::Block as BlockT; use crate::protocol::Context; @@ -26,13 +26,13 @@ pub trait NetworkSpecialization: Send + Sync + 'static { fn status(&self) -> Vec; /// Called when a peer successfully handshakes. - fn on_connect(&mut self, ctx: &mut Context, who: NodeIndex, status: crate::message::Status); + fn on_connect(&mut self, ctx: &mut Context, who: PeerId, status: crate::message::Status); /// Called when a peer is disconnected. If the peer ID is unknown, it should be ignored. - fn on_disconnect(&mut self, ctx: &mut Context, who: NodeIndex); + fn on_disconnect(&mut self, ctx: &mut Context, who: PeerId); /// Called when a network-specific message arrives. - fn on_message(&mut self, ctx: &mut Context, who: NodeIndex, message: &mut Option>); + fn on_message(&mut self, ctx: &mut Context, who: PeerId, message: &mut Option>); /// Called on abort. fn on_abort(&mut self) { } diff --git a/core/network/src/sync.rs b/core/network/src/sync.rs index 1cf639ee65c11a4eeb579cab08ad540862dab852..80ff8221a1a02fb844c1fcc8874c0fe27223f68a 100644 --- a/core/network/src/sync.rs +++ b/core/network/src/sync.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -14,22 +14,24 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . +use std::cmp::max; use std::collections::{HashMap, VecDeque}; use std::time::{Duration, Instant}; use log::{debug, trace, warn}; use crate::protocol::Context; use fork_tree::ForkTree; -use network_libp2p::{Severity, NodeIndex}; +use network_libp2p::{Severity, PeerId}; use client::{BlockStatus, ClientInfo}; use consensus::BlockOrigin; use consensus::import_queue::{ImportQueue, IncomingBlock}; use client::error::Error as ClientError; use crate::blocks::BlockCollection; use runtime_primitives::Justification; -use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, As, NumberFor}; +use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, As, NumberFor, Zero, CheckedSub}; use runtime_primitives::generic::BlockId; use crate::message::{self, generic::Message as GenericMessage}; use crate::config::Roles; +use std::collections::HashSet; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; @@ -44,7 +46,6 @@ const JUSTIFICATION_RETRY_WAIT: Duration = Duration::from_secs(10); // 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. -// TODO: this should take finality into account. See https://github.com/paritytech/substrate/issues/1606 const MAX_UNKNOWN_FORK_DOWNLOAD_LEN: u32 = 32; #[derive(Debug)] @@ -56,9 +57,28 @@ struct PeerSync { pub recently_announced: VecDeque, } +#[derive(Debug)] +/// Peer sync status. +pub(crate) struct PeerInfo { + /// Their best block hash. + pub best_hash: B::Hash, + /// Their best block number. + pub best_number: NumberFor, +} + +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +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)] enum PeerSyncState { - AncestorSearch(NumberFor), + AncestorSearch(NumberFor, AncestorSearchState), Available, DownloadingNew(NumberFor), DownloadingStale(B::Hash), @@ -76,8 +96,9 @@ type PendingJustification = (::Hash, NumberFor); struct PendingJustifications { justifications: ForkTree, ()>, pending_requests: VecDeque>, - peer_requests: HashMap>, - previous_requests: HashMap, Vec<(NodeIndex, Instant)>>, + peer_requests: HashMap>, + previous_requests: HashMap, Vec<(PeerId, Instant)>>, + importing_requests: HashSet>, } impl PendingJustifications { @@ -87,6 +108,7 @@ impl PendingJustifications { pending_requests: VecDeque::new(), peer_requests: HashMap::new(), previous_requests: HashMap::new(), + importing_requests: HashSet::new(), } } @@ -95,7 +117,7 @@ impl PendingJustifications { /// justification request for block #10 to a peer at block #2), and we also /// throttle requests to the same peer if a previous justification request /// yielded no results. - fn dispatch(&mut self, peers: &mut HashMap>, protocol: &mut Context) { + fn dispatch(&mut self, peers: &mut HashMap>, protocol: &mut Context) { if self.pending_requests.is_empty() { return; } @@ -112,11 +134,11 @@ impl PendingJustifications { if sync.state != PeerSyncState::Available || self.peer_requests.contains_key(&peer) { None } else { - Some((*peer, sync.best_number)) + Some((peer.clone(), sync.best_number)) } }).collect::>(); - let mut last_peer = available_peers.back().map(|p| p.0); + let mut last_peer = available_peers.back().map(|p| p.0.clone()); let mut unhandled_requests = VecDeque::new(); loop { @@ -136,17 +158,17 @@ impl PendingJustifications { peer_best_number >= request.1 && !self.previous_requests - .get(&request) - .map(|requests| requests.iter().any(|i| i.0 == peer)) - .unwrap_or(false) + .get(&request) + .map(|requests| requests.iter().any(|i| i.0 == peer)) + .unwrap_or(false) }; if !peer_eligible { - available_peers.push_back((peer, peer_best_number)); + available_peers.push_back((peer.clone(), peer_best_number)); // we tried all peers and none can answer this request if Some(peer) == last_peer { - last_peer = available_peers.back().map(|p| p.0); + last_peer = available_peers.back().map(|p| p.0.clone()); let request = self.pending_requests.pop_front() .expect("verified to be Some in the beginning of the loop; qed"); @@ -157,12 +179,12 @@ impl PendingJustifications { continue; } - last_peer = available_peers.back().map(|p| p.0); + last_peer = available_peers.back().map(|p| p.0.clone()); let request = self.pending_requests.pop_front() .expect("verified to be Some in the beginning of the loop; qed"); - self.peer_requests.insert(peer, request); + self.peer_requests.insert(peer.clone(), request); peers.get_mut(&peer) .expect("peer was is taken from available_peers; available_peers is a subset of peers; qed") @@ -213,7 +235,7 @@ impl PendingJustifications { } /// Retry any pending request if a peer disconnected. - fn peer_disconnected(&mut self, who: NodeIndex) { + fn peer_disconnected(&mut self, who: PeerId) { if let Some(request) = self.peer_requests.remove(&who) { self.pending_requests.push_front(request); } @@ -223,13 +245,24 @@ impl PendingJustifications { /// Queues a retry in case the import failed. fn justification_import_result(&mut self, hash: B::Hash, number: NumberFor, success: bool) { let request = (hash, number); + + if !self.importing_requests.remove(&request) { + debug!(target: "sync", "Got justification import result for unknown justification {:?} {:?} request.", + request.0, + request.1, + ); + + return; + }; + if success { if self.justifications.finalize_root(&request.0).is_none() { warn!(target: "sync", "Imported justification for {:?} {:?} which isn't a root in the tree: {:?}", - request.0, - request.1, - self.justifications.roots().collect::>(), + request.0, + request.1, + self.justifications.roots().collect::>(), ); + return; }; @@ -248,7 +281,7 @@ impl PendingJustifications { /// was `None`. fn on_response( &mut self, - who: NodeIndex, + who: PeerId, justification: Option, import_queue: &ImportQueue, ) { @@ -258,6 +291,7 @@ impl PendingJustifications { if let Some(request) = self.peer_requests.remove(&who) { if let Some(justification) = justification { import_queue.import_justification(who.clone(), request.0, request.1, justification); + self.importing_requests.insert(request); return } @@ -265,6 +299,7 @@ impl PendingJustifications { .entry(request) .or_insert(Vec::new()) .push((who, Instant::now())); + self.pending_requests.push_front(request); } } @@ -279,7 +314,11 @@ impl PendingJustifications { ) -> Result<(), fork_tree::Error> where F: Fn(&B::Hash, &B::Hash) -> Result { - use std::collections::HashSet; + if self.importing_requests.contains(&(*best_finalized_hash, best_finalized_number)) { + // we imported this justification ourselves, so we should get back a response + // from the import queue through `justification_import_result` + return Ok(()); + } self.justifications.finalize(best_finalized_hash, best_finalized_number, &is_descendent_of)?; @@ -291,18 +330,28 @@ impl PendingJustifications { Ok(()) } + + /// Clear all data. + fn clear(&mut self) { + self.justifications = ForkTree::new(); + self.pending_requests.clear(); + self.peer_requests.clear(); + self.previous_requests.clear(); + } } /// Relay chain sync strategy. pub struct ChainSync { genesis_hash: B::Hash, - peers: HashMap>, + peers: HashMap>, blocks: BlockCollection, best_queued_number: NumberFor, best_queued_hash: B::Hash, required_block_attributes: message::BlockAttributes, justifications: PendingJustifications, import_queue: Box>, + queue_blocks: HashSet, + best_importing_number: NumberFor, is_stopping: AtomicBool, is_offline: Arc, is_major_syncing: Arc, @@ -367,6 +416,8 @@ impl ChainSync { justifications: PendingJustifications::new(), required_block_attributes, import_queue, + queue_blocks: Default::default(), + best_importing_number: Zero::zero(), is_stopping: Default::default(), is_offline, is_major_syncing, @@ -377,11 +428,6 @@ impl ChainSync { self.peers.values().max_by_key(|p| p.best_number).map(|p| p.best_number) } - /// Returns import queue reference. - pub(crate) fn import_queue(&self) -> Box> { - self.import_queue.clone() - } - fn state(&self, best_seen: &Option>) -> SyncState { match best_seen { &Some(n) if n > self.best_queued_number && n - self.best_queued_number > As::sa(5) => SyncState::Downloading, @@ -389,6 +435,16 @@ impl ChainSync { } } + /// Returns peer sync status (if any). + 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 sync status. pub(crate) fn status(&self) -> Status { let best_seen = self.best_seen_block(); @@ -401,7 +457,7 @@ impl ChainSync { } /// Handle new connected peer. - pub(crate) fn new_peer(&mut self, protocol: &mut Context, who: NodeIndex) { + pub(crate) fn new_peer(&mut self, protocol: &mut Context, who: PeerId) { // Initialize some variables to determine if // is_offline or is_major_syncing should be updated // after processing this new peer. @@ -409,8 +465,9 @@ impl ChainSync { let previous_best_seen = self.best_seen_block(); let previous_state = self.state(&previous_best_seen); - if let Some(info) = protocol.peer_info(who) { - match (block_status(&*protocol.client(), &*self.import_queue, info.best_hash), info.best_number) { + if let Some(info) = protocol.peer_info(&who) { + let status = block_status(&*protocol.client(), &self.queue_blocks, info.best_hash); + match (status, info.best_number) { (Err(e), _) => { debug!(target:"sync", "Error reading blockchain: {:?}", e); let reason = format!("Error legimimately reading blockchain status: {:?}", e); @@ -424,7 +481,7 @@ impl ChainSync { let reason = format!("New peer with unknown genesis hash {} ({}).", info.best_hash, info.best_number); protocol.report_peer(who, Severity::Bad(reason)); }, - (Ok(BlockStatus::Unknown), _) if self.import_queue.status().importing_count > MAJOR_SYNC_BLOCKS => { + (Ok(BlockStatus::Unknown), _) if self.queue_blocks.len() > MAJOR_SYNC_BLOCKS => { // when actively syncing the common point moves too fast. 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 { @@ -440,18 +497,18 @@ impl ChainSync { if our_best > As::sa(0) { 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); - self.peers.insert(who, PeerSync { + self.peers.insert(who.clone(), PeerSync { common_number: As::sa(0), best_hash: info.best_hash, best_number: info.best_number, - state: PeerSyncState::AncestorSearch(common_best), + state: PeerSyncState::AncestorSearch(common_best, AncestorSearchState::ExponentialBackoff(As::sa(1))), recently_announced: Default::default(), }); Self::request_ancestry(protocol, who, common_best) } else { // 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, PeerSync { + self.peers.insert(who.clone(), PeerSync { common_number: As::sa(0), best_hash: info.best_hash, best_number: info.best_number, @@ -461,9 +518,9 @@ impl ChainSync { self.download_new(protocol, who) } }, - (Ok(BlockStatus::Queued), _) | (Ok(BlockStatus::InChain), _) => { + (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, PeerSync { + self.peers.insert(who.clone(), PeerSync { common_number: info.best_number, best_hash: info.best_hash, best_number: info.best_number, @@ -491,23 +548,62 @@ impl ChainSync { } } + fn handle_ancestor_search_state( + state: AncestorSearchState, + curr_block_num: NumberFor, + block_hash_match: bool, + ) -> Option<(AncestorSearchState, NumberFor)> { + match state { + AncestorSearchState::ExponentialBackoff(next_distance_to_tip) => { + if block_hash_match && next_distance_to_tip == As::sa(1) { + // 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 / As::sa(2); + let middle = left + (right - left) / As::sa(2); + Some((AncestorSearchState::BinarySearch(left, right), middle)) + } else { + let next_block_num = curr_block_num.checked_sub(&next_distance_to_tip).unwrap_or(As::sa(0)); + let next_distance_to_tip = next_distance_to_tip * As::sa(2); + 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) / As::sa(2); + Some((AncestorSearchState::BinarySearch(left, right), middle)) + }, + } + } + /// Handle new block data. pub(crate) fn on_block_data( &mut self, protocol: &mut Context, - who: NodeIndex, + 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(); } - match peer.state { + let peer_state = peer.state.clone(); + match peer_state { PeerSyncState::DownloadingNew(start_block) => { - self.blocks.clear_peer_download(who); + self.blocks.clear_peer_download(&who); peer.state = PeerSyncState::Available; self.blocks.insert(start_block, blocks, who); self.blocks @@ -531,47 +627,42 @@ impl ChainSync { header: b.header, body: b.body, justification: b.justification, - origin: Some(who), + origin: Some(who.clone()), } }).collect() }, - PeerSyncState::AncestorSearch(n) => { - match blocks.get(0) { - Some(ref block) => { - trace!(target: "sync", "Got ancestry block #{} ({}) from peer {}", n, block.hash, who); - match protocol.client().block_hash(n) { - Ok(Some(block_hash)) if block_hash == block.hash => { - if peer.common_number < n { - peer.common_number = n; - } - peer.state = PeerSyncState::Available; - trace!(target:"sync", "Found common ancestor for peer {}: {} ({})", who, block.hash, n); - vec![] - }, - Ok(our_best) if n > As::sa(0) => { - trace!(target:"sync", "Ancestry block mismatch for peer {}: theirs: {} ({}), ours: {:?}", who, block.hash, n, our_best); - let n = n - As::sa(1); - peer.state = PeerSyncState::AncestorSearch(n); - Self::request_ancestry(protocol, who, n); - return None; - }, - Ok(_) => { // genesis mismatch - trace!(target:"sync", "Ancestry search: genesis mismatch for peer {}", who); - protocol.report_peer(who, Severity::Bad("Ancestry search: genesis mismatch for peer".to_string())); - return None; - }, - Err(e) => { - let reason = format!("Error answering legitimate blockchain query: {:?}", e); - protocol.report_peer(who, Severity::Useless(reason)); - return None; - } - } + 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 => { + (None, _) => { trace!(target:"sync", "Invalid response when searching for ancestor from {}", who); protocol.report_peer(who, Severity::Bad("Invalid response when searching for ancestor".to_string())); - return None; - } + return; + }, + (_, Err(e)) => { + let reason = format!("Error answering legitimate blockchain query: {:?}", e); + protocol.report_peer(who, Severity::Useless(reason)); + return; + }, + }; + if block_hash_match && peer.common_number < num { + peer.common_number = num; + } + if !block_hash_match && num == As::sa(0) { + trace!(target:"sync", "Ancestry search: genesis mismatch for peer {}", who); + protocol.report_peer(who, Severity::Bad("Ancestry search: genesis mismatch for peer".to_string())); + return; + } + 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; + } else { + peer.state = PeerSyncState::Available; + vec![] } }, PeerSyncState::Available | PeerSyncState::DownloadingJustification(..) => Vec::new(), @@ -593,14 +684,21 @@ impl ChainSync { self.block_queued(&hash, number); } self.maintain_sync(protocol); - Some((origin, new_blocks)) + let new_best_importing_number = new_blocks + .last() + .and_then(|b| b.header.as_ref().map(|h| h.number().clone())) + .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); + self.import_queue.import_blocks(origin, new_blocks); } /// Handle new justification data. pub(crate) fn on_block_justification_data( &mut self, protocol: &mut Context, - who: NodeIndex, + who: PeerId, _request: message::BlockRequest, response: message::BlockResponse, ) { @@ -644,12 +742,22 @@ impl ChainSync { self.maintain_sync(protocol); } + /// A batch of blocks have been processed, with or without errors. + pub fn blocks_processed(&mut self, 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(); + } + } + /// Maintain the sync process (download new blocks, fetch justifications). pub fn maintain_sync(&mut self, protocol: &mut Context) { if self.is_stopping.load(Ordering::SeqCst) { return } - let peers: Vec = self.peers.keys().map(|p| *p).collect(); + let peers: Vec = self.peers.keys().map(|p| p.clone()).collect(); for peer in peers { self.download_new(protocol, peer); } @@ -673,6 +781,11 @@ impl ChainSync { self.justifications.dispatch(&mut self.peers, protocol); } + /// Clears all pending justification requests. + pub fn clear_justification_requests(&mut self) { + self.justifications.clear(); + } + pub fn justification_import_result(&mut self, hash: B::Hash, number: NumberFor, success: bool) { self.justifications.justification_import_result(hash, number, success); } @@ -714,7 +827,7 @@ impl ChainSync { } // Update common blocks for (n, peer) in self.peers.iter_mut() { - if let PeerSyncState::AncestorSearch(_) = peer.state { + if let PeerSyncState::AncestorSearch(_, _) = peer.state { // Abort search. peer.state = PeerSyncState::Available; } @@ -733,13 +846,17 @@ impl ChainSync { } /// Handle new block announcement. - pub(crate) fn on_block_announce(&mut self, protocol: &mut Context, who: NodeIndex, hash: B::Hash, header: &B::Header) { + pub(crate) fn on_block_announce(&mut self, protocol: &mut Context, who: PeerId, hash: B::Hash, header: &B::Header) { let number = *header.number(); if number <= As::sa(0) { trace!(target: "sync", "Ignored invalid block announcement from {}: {}", who, hash); return; } - let known_parent = self.is_known(protocol, &header.parent_hash()); + let parent_status = block_status(&*protocol.client(), &self.queue_blocks, header.parent_hash().clone()).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); if let Some(ref mut peer) = self.peers.get_mut(&who) { while peer.recently_announced.len() >= ANNOUNCE_HISTORY_SIZE { @@ -751,7 +868,7 @@ impl ChainSync { peer.best_number = number; peer.best_hash = hash; } - if let PeerSyncState::AncestorSearch(_) = peer.state { + if let PeerSyncState::AncestorSearch(_, _) = peer.state { return; } if header.parent_hash() == &self.best_queued_hash || known_parent { @@ -767,15 +884,28 @@ impl ChainSync { let stale = number <= self.best_queued_number; if stale { if !(known_parent || self.is_already_downloading(header.parent_hash())) { - trace!(target: "sync", "Considering new unknown stale block announced from {}: {} {:?}", who, hash, header); - self.download_unknown_stale(protocol, who, &hash); + if protocol.client().block_status(&BlockId::Number(*header.number())) + .unwrap_or(BlockStatus::Unknown) == BlockStatus::InChainPruned + { + trace!(target: "sync", "Ignored unknown ancient block announced from {}: {} {:?}", who, hash, header); + } else { + trace!(target: "sync", "Considering new unknown stale block announced from {}: {} {:?}", who, hash, header); + self.download_unknown_stale(protocol, who, &hash); + } } else { - trace!(target: "sync", "Considering new stale block announced from {}: {} {:?}", who, hash, header); - self.download_stale(protocol, who, &hash); + if ancient_parent { + trace!(target: "sync", "Ignored ancient stale block announced from {}: {} {:?}", who, hash, header); + } else { + self.download_stale(protocol, who, &hash); + } } } else { - trace!(target: "sync", "Considering new block announced from {}: {} {:?}", who, hash, header); - self.download_new(protocol, who); + if ancient_parent { + trace!(target: "sync", "Ignored ancient block announced from {}: {} {:?}", who, hash, header); + } else { + trace!(target: "sync", "Considering new block announced from {}: {} {:?}", who, hash, header); + self.download_new(protocol, who); + } } } else { trace!(target: "sync", "Known block announce from {}: {}", who, hash); @@ -787,14 +917,14 @@ impl ChainSync { } fn is_known(&self, protocol: &mut Context, hash: &B::Hash) -> bool { - block_status(&*protocol.client(), &*self.import_queue, *hash).ok().map_or(false, |s| s != BlockStatus::Unknown) + block_status(&*protocol.client(), &self.queue_blocks, *hash).ok().map_or(false, |s| s != BlockStatus::Unknown) } /// Handle disconnected peer. - pub(crate) fn peer_disconnected(&mut self, protocol: &mut Context, who: NodeIndex) { + pub(crate) fn peer_disconnected(&mut self, protocol: &mut Context, who: PeerId) { let previous_best_seen = self.best_seen_block(); let previous_state = self.state(&previous_best_seen); - self.blocks.clear_peer_download(who); + self.blocks.clear_peer_download(&who); self.peers.remove(&who); if self.peers.len() == 0 { // We're not connected to any peer anymore. @@ -813,7 +943,8 @@ impl ChainSync { /// Restart the sync process. pub(crate) fn restart(&mut self, protocol: &mut Context) { - self.import_queue.clear(); + self.queue_blocks.clear(); + self.best_importing_number = Zero::zero(); self.blocks.clear(); match protocol.client().info() { Ok(info) => { @@ -827,7 +958,7 @@ impl ChainSync { self.best_queued_number = As::sa(0); } } - let ids: Vec = self.peers.drain().map(|(id, _)| id).collect(); + let ids: Vec = self.peers.drain().map(|(id, _)| id).collect(); for id in ids { self.new_peer(protocol, id); } @@ -840,7 +971,7 @@ impl ChainSync { } // Download old block with known parent. - fn download_stale(&mut self, protocol: &mut Context, who: NodeIndex, hash: &B::Hash) { + fn download_stale(&mut self, protocol: &mut Context, who: PeerId, hash: &B::Hash) { if let Some(ref mut peer) = self.peers.get_mut(&who) { match peer.state { PeerSyncState::Available => { @@ -861,7 +992,7 @@ impl ChainSync { } // Download old block with unknown parent. - fn download_unknown_stale(&mut self, protocol: &mut Context, who: NodeIndex, hash: &B::Hash) { + fn download_unknown_stale(&mut self, protocol: &mut Context, who: PeerId, hash: &B::Hash) { if let Some(ref mut peer) = self.peers.get_mut(&who) { match peer.state { PeerSyncState::Available => { @@ -882,18 +1013,17 @@ impl ChainSync { } // Issue a request for a peer to download new blocks, if any are available - fn download_new(&mut self, protocol: &mut Context, who: NodeIndex) { + fn download_new(&mut self, protocol: &mut Context, who: PeerId) { if let Some(ref mut peer) = self.peers.get_mut(&who) { - let import_status = self.import_queue.status(); // when there are too many blocks in the queue => do not try to download new blocks - if import_status.importing_count > MAX_IMPORTING_BLOCKS { + if self.queue_blocks.len() > MAX_IMPORTING_BLOCKS { trace!(target: "sync", "Too many blocks in the queue."); return; } 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); - if let Some(range) = self.blocks.needed_blocks(who, MAX_BLOCKS_TO_REQUEST, peer.best_number, peer.common_number) { + if let Some(range) = self.blocks.needed_blocks(who.clone(), MAX_BLOCKS_TO_REQUEST, peer.best_number, peer.common_number) { trace!(target: "sync", "Requesting blocks from {}, ({} to {})", who, range.start, range.end); let request = message::generic::BlockRequest { id: 0, @@ -914,7 +1044,7 @@ impl ChainSync { } } - fn request_ancestry(protocol: &mut Context, who: NodeIndex, block: NumberFor) { + fn request_ancestry(protocol: &mut Context, who: PeerId, block: NumberFor) { trace!(target: "sync", "Requesting ancestry block #{} from {}", block, who); let request = message::generic::BlockRequest { id: 0, @@ -931,10 +1061,10 @@ impl ChainSync { /// Get block status, taking into account import queue. fn block_status( chain: &crate::chain::Client, - queue: &ImportQueue, + queue_blocks: &HashSet, hash: B::Hash) -> Result { - if queue.is_importing(&hash) { + if queue_blocks.contains(&hash) { return Ok(BlockStatus::Queued); } diff --git a/core/network/src/test/block_import.rs b/core/network/src/test/block_import.rs index aca789ce2b8608c78d0a8136b937bf0f0d2c3ae6..3b5e44cc47e5a76d1b2b65de3ded66a0f78abdfa 100644 --- a/core/network/src/test/block_import.rs +++ b/core/network/src/test/block_import.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -26,7 +26,7 @@ struct TestLink {} impl Link for TestLink {} -fn prepare_good_block() -> (client::Client, Hash, u64, IncomingBlock) { +fn prepare_good_block() -> (client::Client, Hash, u64, PeerId, IncomingBlock) { let client = test_client::new(); let block = client.new_block().unwrap().bake().unwrap(); client.import(BlockOrigin::File, block).unwrap(); @@ -34,27 +34,28 @@ fn prepare_good_block() -> (client::Client Link for NoopLink { } /// The test specialization. -pub struct DummySpecialization { } +#[derive(Clone)] +pub struct DummySpecialization; impl NetworkSpecialization for DummySpecialization { fn status(&self) -> Vec { vec![] } - fn on_connect(&mut self, _ctx: &mut Context, _peer_id: NodeIndex, _status: crate::message::Status) { + fn on_connect(&mut self, _ctx: &mut Context, _peer_id: PeerId, _status: crate::message::Status) { } - fn on_disconnect(&mut self, _ctx: &mut Context, _peer_id: NodeIndex) { + fn on_disconnect(&mut self, _ctx: &mut Context, _peer_id: PeerId) { } fn on_message( &mut self, _ctx: &mut Context, - _peer_id: NodeIndex, + _peer_id: PeerId, _message: &mut Option>, ) { } @@ -117,39 +117,118 @@ impl NetworkSpecialization for DummySpecialization { pub type PeersClient = client::Client; -pub struct Peer { +#[derive(Clone)] +/// A Link that can wait for a block to have been imported. +pub struct TestLink + Clone> { + import_done: Arc, + hash: Arc>, + link: NetworkLink, +} + +impl + Clone> TestLink { + fn new( + protocol_sender: Sender>, + network_sender: NetworkChan + ) -> TestLink { + TestLink { + import_done: Arc::new(AtomicBool::new(false)), + hash: Arc::new(Mutex::new(Default::default())), + link: NetworkLink { + protocol_sender, + network_sender, + } + } + } + + /// Set the hash which will be awaited for import. + fn with_hash(&self, hash: Hash) { + self.import_done.store(false, Ordering::SeqCst); + *self.hash.lock() = hash; + } + + /// Simulate a synchronous import. + fn wait_for_import(&self) { + while !self.import_done.load(Ordering::SeqCst) { + thread::sleep(Duration::from_millis(20)); + } + } +} + +impl + Clone> Link for TestLink { + fn block_imported(&self, hash: &Hash, number: NumberFor) { + if hash == &*self.hash.lock() { + self.import_done.store(true, Ordering::SeqCst); + } + self.link.block_imported(hash, number); + } + + fn blocks_processed(&self, processed_blocks: Vec, has_error: bool) { + self.link.blocks_processed(processed_blocks, has_error); + } + + fn justification_imported(&self, who: PeerId, hash: &Hash, number:NumberFor, success: bool) { + self.link.justification_imported(who, hash, number, success); + } + + fn request_justification(&self, hash: &Hash, number: NumberFor) { + self.link.request_justification(hash, number); + } + + fn useless_peer(&self, who: PeerId, reason: &str) { + self.link.useless_peer(who, reason); + } + + fn note_useless_and_restart_sync(&self, who: PeerId, reason: &str) { + self.link.note_useless_and_restart_sync(who, reason); + } + + fn restart(&self) { + self.link.restart(); + } +} + +pub struct Peer + Clone> { pub is_offline: Arc, pub is_major_syncing: Arc, + pub peers: Arc>>>, + pub peer_id: PeerId, client: Arc, - pub protocol_sender: Sender>, - - network_port: Mutex>, + network_to_protocol_sender: Sender>, + pub protocol_sender: Sender>, + network_link: TestLink, + network_port: Arc>>, pub import_queue: Box>, - network_sender: NetworkChan, pub data: D, best_hash: Mutex>, finalized_hash: Mutex>, } -impl Peer { +impl + Clone> Peer { fn new( is_offline: Arc, is_major_syncing: Arc, + peers: Arc>>>, client: Arc, import_queue: Box>, - protocol_sender: Sender>, + network_to_protocol_sender: Sender>, + protocol_sender: Sender>, network_sender: NetworkChan, network_port: NetworkPort, data: D, ) -> Self { - let network_port = Mutex::new(network_port); + let network_port = Arc::new(Mutex::new(network_port)); + let network_link = TestLink::new(protocol_sender.clone(), network_sender.clone()); + import_queue.start(Box::new(network_link.clone())).expect("Test ImportQueue always starts"); Peer { is_offline, is_major_syncing, + peers, + peer_id: PeerId::random(), client, + network_to_protocol_sender, protocol_sender, import_queue, - network_sender, + network_link, network_port, data, best_hash: Mutex::new(None), @@ -165,12 +244,6 @@ impl Peer { .header(&BlockId::Hash(info.chain.best_hash)) .unwrap() .unwrap(); - let network_link = NetworkLink { - protocol_sender: self.protocol_sender.clone(), - network_sender: self.network_sender.clone(), - }; - - self.import_queue.start(Box::new(network_link)).expect("Test ImportQueue always starts"); let _ = self .protocol_sender .send(ProtocolMsg::BlockImported(info.chain.best_hash, header)); @@ -197,22 +270,22 @@ impl Peer { } /// Called on connection to other indicated peer. - fn on_connect(&self, other: NodeIndex) { - let _ = self.protocol_sender.send(ProtocolMsg::PeerConnected(other, String::new())); + fn on_connect(&self, other: &Self) { + let _ = self.network_to_protocol_sender.send(FromNetworkMsg::PeerConnected(other.peer_id.clone(), String::new())); } /// Called on disconnect from other indicated peer. - fn on_disconnect(&self, other: NodeIndex) { + fn on_disconnect(&self, other: &Self) { let _ = self - .protocol_sender - .send(ProtocolMsg::PeerDisconnected(other, String::new())); + .network_to_protocol_sender + .send(FromNetworkMsg::PeerDisconnected(other.peer_id.clone(), String::new())); } /// Receive a message from another peer. Return a set of peers to disconnect. - fn receive_message(&self, from: NodeIndex, msg: Message) { + fn receive_message(&self, from: &Self, msg: Message) { let _ = self - .protocol_sender - .send(ProtocolMsg::CustomMessage(from, msg)); + .network_to_protocol_sender + .send(FromNetworkMsg::CustomMessage(from.peer_id.clone(), msg)); } /// Produce the next pending message to send to another peer. @@ -231,8 +304,7 @@ impl Peer { /// Whether this peer is done syncing (has no messages to send). fn is_done(&self) -> bool { - self.import_queue.status().importing_count == 0 && - self.network_port.lock().receiver().is_empty() + self.network_port.lock().receiver().is_empty() } /// Execute a "sync step". This is called for each peer after it sends a packet. @@ -285,10 +357,16 @@ impl Peer { /// 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) { + pub fn gossip_message( + &self, + topic: ::Hash, + engine_id: ConsensusEngineId, + data: Vec, + force: bool, + ) { let _ = self .protocol_sender - .send(ProtocolMsg::GossipConsensusMessage(topic, engine_id, data)); + .send(ProtocolMsg::GossipConsensusMessage(topic, engine_id, data, force)); } pub fn consensus_gossip_collect_garbage_for_topic(&self, _topic: ::Hash) { @@ -298,11 +376,12 @@ impl Peer { /// 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(topic); + 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") @@ -356,7 +435,7 @@ impl Peer { ); let header = block.header.clone(); at = hash; - + self.network_link.with_hash(hash); self.import_queue.import_blocks( origin, vec![IncomingBlock { @@ -367,10 +446,8 @@ impl Peer { justification: None, }], ); - // Simulate a synchronous import. - while self.import_queue.status().importing_count > 0 { - thread::sleep(Duration::from_millis(20)); - } + // Simulate a sync import. + self.network_link.wait_for_import(); } at } @@ -388,12 +465,12 @@ impl Peer { if with_tx { self.generate_blocks_at(at, count, BlockOrigin::File, |mut builder| { let transfer = Transfer { - from: Keyring::Alice.to_raw_public().into(), - to: Keyring::Alice.to_raw_public().into(), + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Alice.into(), amount: 1, nonce, }; - let signature = Keyring::from_raw_public(transfer.from.to_fixed_bytes()).unwrap().sign(&transfer.encode()).into(); + let signature = AccountKeyring::from_public(&transfer.from).unwrap().sign(&transfer.encode()).into(); builder.push(Extrinsic::Transfer(transfer, signature)).unwrap(); nonce = nonce + 1; builder.bake().unwrap() @@ -403,7 +480,7 @@ impl Peer { } } - pub fn push_authorities_change_block(&self, new_authorities: Vec) -> H256 { + pub fn push_authorities_change_block(&self, new_authorities: Vec) -> H256 { self.generate_blocks(1, BlockOrigin::File, |mut builder| { builder.push(Extrinsic::AuthoritiesChange(new_authorities.clone())).unwrap(); builder.bake().unwrap() @@ -430,7 +507,18 @@ impl TransactionPool for EmptyTransactionPool { fn on_broadcasted(&self, _: HashMap>) {} } +pub trait SpecializationFactory { + fn create() -> Self; +} + +impl SpecializationFactory for DummySpecialization { + fn create() -> DummySpecialization { + DummySpecialization + } +} + pub trait TestNetFactory: Sized { + type Specialization: NetworkSpecialization + Clone + SpecializationFactory; type Verifier: 'static + Verifier; type PeerData: Default; @@ -439,9 +527,9 @@ pub trait TestNetFactory: Sized { fn make_verifier(&self, client: Arc, 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 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); @@ -474,15 +562,20 @@ pub trait TestNetFactory: Sized { let tx_pool = Arc::new(EmptyTransactionPool); let verifier = self.make_verifier(client.clone(), config); let (block_import, justification_import, data) = self.make_block_import(client.clone()); - let (network_sender, network_port) = network_channel(ProtocolId::default()); + let (network_sender, network_port) = network_channel(); let import_queue = Box::new(BasicQueue::new(verifier, block_import, justification_import)); - let specialization = DummySpecialization {}; + let status_sinks = Arc::new(Mutex::new(Vec::new())); let is_offline = Arc::new(AtomicBool::new(true)); let is_major_syncing = Arc::new(AtomicBool::new(false)); - let protocol_sender = Protocol::new( + let specialization = self::SpecializationFactory::create(); + let peers: Arc>>> = Arc::new(Default::default()); + + let (protocol_sender, network_to_protocol_sender) = Protocol::new( + status_sinks, is_offline.clone(), is_major_syncing.clone(), + peers.clone(), network_sender.clone(), config.clone(), client.clone(), @@ -495,8 +588,10 @@ pub trait TestNetFactory: Sized { let peer = Arc::new(Peer::new( is_offline, is_major_syncing, + peers, client, import_queue, + network_to_protocol_sender, protocol_sender, network_sender, network_port, @@ -504,7 +599,7 @@ pub trait TestNetFactory: Sized { )); self.mut_peers(|peers| { - peers.push(peer.clone()) + peers.push(peer) }); } @@ -513,39 +608,38 @@ pub trait TestNetFactory: Sized { if self.started() { return; } - self.mut_peers(|peers| { - for peer in 0..peers.len() { - peers[peer].start(); - for client in 0..peers.len() { - if peer != client { - peers[peer].on_connect(client as NodeIndex); - } + for peer in self.peers() { + peer.start(); + for client in self.peers() { + if peer.peer_id != client.peer_id { + peer.on_connect(client); } } - }); + } self.route(None); self.set_started(true); } /// Do one step of routing. - fn route(&mut self, disconnected: Option>) { + fn route(&mut self, disconnected: Option>) { self.mut_peers(move |peers| { let mut to_disconnect = HashSet::new(); - for peer in 0..peers.len() { - let packet = peers[peer].pending_message(); + for (peer_pos, peer) in peers.iter().enumerate() { + let packet = peer.pending_message(); match packet { None => continue, Some(NetworkMsg::Outgoing(recipient, packet)) => { + let recipient = peers.iter().position(|p| p.peer_id == recipient).unwrap(); if let Some(disconnected) = disconnected.as_ref() { let mut current = HashSet::new(); - current.insert(peer); + current.insert(peer_pos); current.insert(recipient); // Not routing message between "disconnected" nodes. if disconnected.is_subset(¤t) { continue; } } - peers[recipient].receive_message(peer as NodeIndex, packet) + peers[recipient].receive_message(peer, packet) } Some(NetworkMsg::ReportPeer(who, _)) => { to_disconnect.insert(who); @@ -554,8 +648,10 @@ pub trait TestNetFactory: Sized { } } for d in to_disconnect { - for peer in 0..peers.len() { - peers[peer].on_disconnect(d); + if let Some(d) = peers.iter().find(|p| p.peer_id == d) { + for peer in 0..peers.len() { + peers[peer].on_disconnect(d); + } } } }); @@ -566,7 +662,9 @@ pub trait TestNetFactory: Sized { self.mut_peers(move |peers| { for peer in 0..peers.len() { while let Some(NetworkMsg::Outgoing(recipient, packet)) = peers[peer].pending_message_fast() { - peers[recipient].receive_message(peer as NodeIndex, packet) + if let Some(p) = peers.iter().find(|p| p.peer_id == recipient) { + p.receive_message(&peers[peer], packet) + } } } }); @@ -608,7 +706,7 @@ pub trait TestNetFactory: Sized { /// Perform synchronization until complete, if provided the /// given nodes set are excluded from sync. - fn sync_with(&mut self, disconnected: Option>) -> u32 { + fn sync_with(&mut self, disconnected: Option>) -> u32 { self.start(); let mut total_steps = 0; let mut done = 0; @@ -637,7 +735,7 @@ pub trait TestNetFactory: Sized { /// Perform synchronization until complete, /// excluding sync between certain nodes. - fn sync_with_disconnected(&mut self, disconnected: HashSet) -> u32 { + fn sync_with_disconnected(&mut self, disconnected: HashSet) -> u32 { self.sync_with(Some(disconnected)) } @@ -656,11 +754,12 @@ pub trait TestNetFactory: Sized { } pub struct TestNet { - peers: Vec>>, + peers: Vec>>, started: bool, } impl TestNetFactory for TestNet { + type Specialization = DummySpecialization; type Verifier = PassThroughVerifier; type PeerData = (); @@ -678,15 +777,15 @@ impl TestNetFactory for TestNet { Arc::new(PassThroughVerifier(false)) } - fn peer(&self, i: usize) -> &Peer<()> { + fn peer(&self, i: usize) -> &Peer<(), Self::Specialization> { &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); } @@ -718,6 +817,7 @@ impl JustificationImport for ForceFinalized { pub struct JustificationTestNet(TestNet); impl TestNetFactory for JustificationTestNet { + type Specialization = DummySpecialization; type Verifier = PassThroughVerifier; type PeerData = (); @@ -731,15 +831,15 @@ impl TestNetFactory for JustificationTestNet { self.0.make_verifier(client, config) } - fn peer(&self, i: usize) -> &Peer { + fn peer(&self, i: usize) -> &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) } diff --git a/core/network/src/test/sync.rs b/core/network/src/test/sync.rs index 795ac202f50b96b1c4abb529c649190fdb6ab83d..9bbf0a32b7fd1a993e07f1ea85bd1cb0a7225a99 100644 --- a/core/network/src/test/sync.rs +++ b/core/network/src/test/sync.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -18,12 +18,53 @@ use client::backend::Backend; use client::blockchain::HeaderBackend as BlockchainHeaderBackend; use crate::config::Roles; use consensus::BlockOrigin; -use network_libp2p::NodeIndex; use std::collections::HashSet; use std::thread; use std::time::Duration; use super::*; +fn test_ancestor_search_when_common_is(n: usize) { + let _ = ::env_logger::try_init(); + let mut net = TestNet::new(3); + + net.peer(0).push_blocks(n, false); + net.peer(1).push_blocks(n, false); + net.peer(2).push_blocks(n, false); + + net.peer(0).push_blocks(10, true); + net.peer(1).push_blocks(100, false); + net.peer(2).push_blocks(100, false); + + net.restart_peer(0); + net.sync(); + assert!(net.peer(0).client.backend().as_in_memory().blockchain() + .canon_equals_to(net.peer(1).client.backend().as_in_memory().blockchain())); +} + +#[test] +fn sync_peers_works() { + let _ = ::env_logger::try_init(); + let mut net = TestNet::new(3); + net.sync(); + for peer in 0..3 { + // Assert peers is up to date. + let peers = net.peer(peer).peers.read(); + assert_eq!(peers.len(), 2); + // And then disconnect. + for other in 0..3 { + if other != peer { + net.peer(peer).on_disconnect(net.peer(other)); + } + } + } + net.sync(); + // Now peers are disconnected. + for peer in 0..3 { + let peers = net.peer(peer).peers.read(); + assert_eq!(peers.len(), 0); + } +} + #[test] fn sync_cycle_from_offline_to_syncing_to_offline() { let _ = ::env_logger::try_init(); @@ -58,7 +99,7 @@ fn sync_cycle_from_offline_to_syncing_to_offline() { for peer in 0..3 { for other in 0..3 { if other != peer { - net.peer(peer).on_disconnect(other); + net.peer(peer).on_disconnect(net.peer(other)); } } thread::sleep(Duration::from_millis(100)); @@ -83,8 +124,8 @@ fn syncing_node_not_major_syncing_when_disconnected() { assert!(net.peer(1).is_major_syncing()); // Disconnect peer 1 form everyone else. - net.peer(1).on_disconnect(0); - net.peer(1).on_disconnect(2); + net.peer(1).on_disconnect(net.peer(0)); + net.peer(1).on_disconnect(net.peer(2)); thread::sleep(Duration::from_millis(100)); // Peer 1 is not major-syncing. @@ -116,6 +157,51 @@ fn sync_from_two_peers_with_ancestry_search_works() { .canon_equals_to(net.peer(1).client.backend().as_in_memory().blockchain())); } +#[test] +fn ancestry_search_works_when_backoff_is_one() { + let _ = ::env_logger::try_init(); + 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.restart_peer(0); + net.sync(); + assert!(net.peer(0).client.backend().as_in_memory().blockchain() + .canon_equals_to(net.peer(1).client.backend().as_in_memory().blockchain())); +} + +#[test] +fn ancestry_search_works_when_ancestor_is_genesis() { + let _ = ::env_logger::try_init(); + 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.restart_peer(0); + net.sync(); + assert!(net.peer(0).client.backend().as_in_memory().blockchain() + .canon_equals_to(net.peer(1).client.backend().as_in_memory().blockchain())); +} + +#[test] +fn ancestry_search_works_when_common_is_one() { + test_ancestor_search_when_common_is(1); +} + +#[test] +fn ancestry_search_works_when_common_is_two() { + test_ancestor_search_when_common_is(2); +} + +#[test] +fn ancestry_search_works_when_common_is_hundred() { + test_ancestor_search_when_common_is(100); +} + #[test] fn sync_long_chain_works() { let mut net = TestNet::new(2); @@ -270,13 +356,13 @@ fn blocks_are_not_announced_by_light_nodes() { net.peer(0).start(); net.peer(1).start(); net.peer(2).start(); - net.peer(0).on_connect(1); - net.peer(1).on_connect(2); + 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 as NodeIndex); - disconnected.insert(2 as NodeIndex); + disconnected.insert(0); + disconnected.insert(2); net.sync_with_disconnected(disconnected); // peer 0 has the best chain diff --git a/core/offchain/Cargo.toml b/core/offchain/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..8cd1d2edc557db77fe5b4785e3e514919af4f147 --- /dev/null +++ b/core/offchain/Cargo.toml @@ -0,0 +1,27 @@ +[package] +description = "Substrate offchain workers" +name = "substrate-offchain" +version = "0.1.0" +license = "GPL-3.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +client = { package = "substrate-client", path = "../../core/client" } +consensus = { package = "substrate-consensus-common", path = "../../core/consensus/common" } +futures = "0.1.25" +inherents = { package = "substrate-inherents", path = "../../core/inherents" } +log = "0.4" +offchain-primitives = { package = "substrate-offchain-primitives", path = "./primitives" } +parity-codec = { version = "3.1", features = ["derive"] } +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" +test_client = { package = "substrate-test-client", path = "../../core/test-client" } + +[features] +default = [] diff --git a/core/offchain/primitives/Cargo.toml b/core/offchain/primitives/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..4d10e08f92dd603176b18fc5bc554fe909ae76a6 --- /dev/null +++ b/core/offchain/primitives/Cargo.toml @@ -0,0 +1,18 @@ +[package] +description = "Substrate offchain workers primitives" +name = "substrate-offchain-primitives" +version = "0.1.0" +license = "GPL-3.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +client = { package = "substrate-client", path = "../../client", default-features = false } +runtime_primitives = { package = "sr-primitives", path = "../../sr-primitives", default-features = false } + +[features] +default = ["std"] +std = [ + "client/std", + "runtime_primitives/std" +] diff --git a/core/offchain/primitives/src/lib.rs b/core/offchain/primitives/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..c05e8dceb90cec525835929e92e5c7788ebc05cf --- /dev/null +++ b/core/offchain/primitives/src/lib.rs @@ -0,0 +1,31 @@ +// Copyright 2018 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 . + +//! The Offchain Worker runtime api primitives. + +#![cfg_attr(not(feature = "std"), no_std)] +#![warn(missing_docs)] + +use client::decl_runtime_apis; +use runtime_primitives::traits::NumberFor; + +decl_runtime_apis! { + /// The offchain worker api. + pub trait OffchainWorkerApi { + /// Starts the off-chain task for given block number. + fn offchain_worker(number: NumberFor); + } +} diff --git a/core/offchain/src/api.rs b/core/offchain/src/api.rs new file mode 100644 index 0000000000000000000000000000000000000000..5d2a636be3924d82a18453750ae94130fdc95aa5 --- /dev/null +++ b/core/offchain/src/api.rs @@ -0,0 +1,99 @@ +// 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::sync::Arc; +use futures::{Stream, Future, sync::mpsc}; +use inherents::pool::InherentsPool; +use log::{info, debug, warn}; +use parity_codec::Decode; +use primitives::OffchainExt; +use runtime_primitives::{ + generic::BlockId, + traits::{self, Extrinsic}, +}; +use transaction_pool::txpool::{Pool, ChainApi}; + +/// A message between the offchain extension and the processing thread. +enum ExtMessage { + SubmitExtrinsic(Vec), +} + +/// 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); + +impl OffchainExt for AsyncApi { + fn submit_extrinsic(&mut self, ext: Vec) { + let _ = self.0.unbounded_send(ExtMessage::SubmitExtrinsic(ext)); + } +} + +/// Offchain extensions implementation API +pub(crate) struct Api { + receiver: Option>, + transaction_pool: Arc>, + inherents_pool: Arc::Extrinsic>>, + at: BlockId, +} + +impl Api { + pub fn new( + transaction_pool: Arc>, + inherents_pool: Arc::Extrinsic>>, + at: BlockId, + ) -> (AsyncApi, Self) { + let (tx, rx) = mpsc::unbounded(); + let api = Self { + receiver: Some(rx), + transaction_pool, + inherents_pool, + at, + }; + (AsyncApi(tx), api) + } + + /// Run a processing task for the API + pub fn process(mut self) -> impl Future { + let receiver = self.receiver.take().expect("Take invoked only once."); + + receiver.for_each(move |msg| { + match msg { + ExtMessage::SubmitExtrinsic(ext) => self.submit_extrinsic(ext), + } + Ok(()) + }) + } + + fn submit_extrinsic(&mut self, ext: Vec) { + let xt = match ::Extrinsic::decode(&mut &*ext) { + Some(xt) => xt, + None => { + warn!("Unable to decode extrinsic: {:?}", ext); + return + }, + }; + + info!("Submitting to the pool: {:?} (isSigned: {:?})", xt, xt.is_signed()); + match self.transaction_pool.submit_one(&self.at, xt.clone()) { + Ok(hash) => debug!("[{:?}] Offchain transaction added to the pool.", hash), + Err(_) => { + debug!("Offchain inherent added to the pool."); + self.inherents_pool.add(xt); + }, + } + } +} diff --git a/core/offchain/src/lib.rs b/core/offchain/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..cac960f2506f26ec409791065b68efdd8d565407 --- /dev/null +++ b/core/offchain/src/lib.rs @@ -0,0 +1,132 @@ +// 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 . + +//! Substrate offchain workers. +//! +//! The offchain workers is a special function of the runtime that +//! gets executed after block is imported. During execution +//! it's able to asynchronously submit extrinsics that will either +//! be propagated to other nodes (transactions) or will be +//! added to the next block produced by the node as inherents. +//! +//! Offchain workers can be used for computation-heavy tasks +//! that are not feasible for execution during regular block processing. +//! It can either be tasks that no consensus is required for, +//! or some form of consensus over the data can be built on-chain +//! for instance via: +//! 1. Challenge period for incorrect computations +//! 2. Majority voting for results +//! 3. etc + +#![warn(missing_docs)] + +use std::{ + marker::PhantomData, + sync::Arc, +}; + +use client::runtime_api::ApiExt; +use inherents::pool::InherentsPool; +use log::{debug, warn}; +use primitives::ExecutionContext; +use runtime_primitives::{ + generic::BlockId, + traits::{self, ProvideRuntimeApi}, +}; +use tokio::runtime::TaskExecutor; +use transaction_pool::txpool::{Pool, ChainApi}; + +mod api; + +pub use offchain_primitives::OffchainWorkerApi; + +/// An offchain workers manager. +#[derive(Debug)] +pub struct OffchainWorkers { + client: Arc, + inherents_pool: Arc::Extrinsic>>, + executor: TaskExecutor, + _block: PhantomData, +} + +impl OffchainWorkers { + /// Creates new `OffchainWorkers`. + pub fn new( + client: Arc, + inherents_pool: Arc::Extrinsic>>, + executor: TaskExecutor, + ) -> Self { + Self { + client, + inherents_pool, + executor, + _block: PhantomData, + } + } +} + +impl OffchainWorkers where + Block: traits::Block, + C: ProvideRuntimeApi, + C::Api: OffchainWorkerApi, +{ + /// Start the offchain workers after given block. + pub fn on_block_imported( + &self, + number: &::Number, + pool: &Arc>, + ) where + A: ChainApi + 'static, + { + let runtime = self.client.runtime_api(); + let at = BlockId::number(*number); + let has_api = runtime.has_api::>(&at); + debug!("Checking offchain workers at {:?}: {:?}", at, has_api); + + if has_api.unwrap_or(false) { + let (api, runner) = api::Api::new(pool.clone(), self.inherents_pool.clone(), at.clone()); + self.executor.spawn(runner.process()); + + debug!("Running offchain workers at {:?}", at); + let api = Box::new(api); + runtime.offchain_worker_with_context(&at, ExecutionContext::OffchainWorker(api), *number).unwrap(); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use futures::Future; + + #[test] + fn should_call_into_runtime_and_produce_extrinsic() { + // given + let _ = env_logger::try_init(); + 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 inherents = Arc::new(InherentsPool::default()); + + // when + let offchain = OffchainWorkers::new(client, inherents.clone(), runtime.executor()); + offchain.on_block_imported(&0u64, &pool); + + // then + runtime.shutdown_on_idle().wait().unwrap(); + assert_eq!(inherents.drain().len(), 1); + } +} diff --git a/core/panic-handler/src/lib.rs b/core/panic-handler/src/lib.rs index 91f7c0af97dd3c685b569a1b994bd923fdb3646c..b2fd7238e0d2e77621af4a0c345ed4433b931bab 100644 --- a/core/panic-handler/src/lib.rs +++ b/core/panic-handler/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/peerset/Cargo.toml b/core/peerset/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..3eaf1d974790d9982dd18beb2862090fe76cf33c --- /dev/null +++ b/core/peerset/Cargo.toml @@ -0,0 +1,20 @@ +[package] +description = "Connectivity manager based on reputation" +homepage = "http://parity.io" +license = "GPL-3.0" +name = "substrate-peerset" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +fnv = "1.0" +futures = "0.1" +libp2p = { git = "https://github.com/tomaka/libp2p-rs", branch = "substrate-tmp-2019-03-20", default-features = false } +log = "0.4" +parking_lot = "0.7" +rand = "0.6" +serde = "1.0.70" +serde_derive = "1.0.70" +serde_json = "1.0.24" +tokio-io = "0.1" diff --git a/core/peerset/src/lib.rs b/core/peerset/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..b64cafc3e564fa5d3c452f2618bbb102485caf68 --- /dev/null +++ b/core/peerset/src/lib.rs @@ -0,0 +1,316 @@ +// Copyright 2018-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 . + +//! Peer Set Manager (PSM). Contains the strategy for choosing which nodes the network should be +//! connected to. + +use std::collections::HashSet; +use futures::{prelude::*, sync::mpsc}; +use libp2p::PeerId; +use parking_lot::Mutex; +use std::sync::Arc; + +pub use serde_json::Value; + +/// Shared part of the peer set manager (PSM). Distributed around the code. +pub struct Peerset { + tx: mpsc::UnboundedSender, + inner: Mutex, +} + +struct Inner { + /// List of nodes that we know exist but we are not connected to. + /// Elements in this list must never be in `out_slots` or `in_slots`. + discovered: Vec, + /// List of reserved nodes. + reserved: HashSet, + /// If true, we only accept reserved nodes. + reserved_only: bool, + /// Node slots for outgoing connections. Each slot contains either `None` if the node is free, + /// or `Some` if it is assigned to a peer. + out_slots: Vec>, + /// Node slots for incoming connections. Each slot contains either `None` if the node is free, + /// or `Some` if it is assigned to a peer. + in_slots: Vec>, +} + +/// Message that can be sent by the peer set manager (PSM). +#[derive(Debug)] +pub enum Message { + /// Request to open a connection to the given peer. From the point of view of the PSM, we are + /// immediately connected. + Connect(PeerId), + + /// Drop the connection to the given peer, or cancel the connection attempt after a `Connect`. + Drop(PeerId), + + /// Equivalent to `Connect` for the peer corresponding to this incoming index. + Accept(IncomingIndex), + + /// Equivalent to `Drop` for the peer corresponding to this incoming index. + Reject(IncomingIndex), +} + +/// Opaque identifier for an incoming connection. Allocated by the network. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct IncomingIndex(pub u64); + +impl From for IncomingIndex { + fn from(val: u64) -> IncomingIndex { + IncomingIndex(val) + } +} + +/// Configuration to pass when creating the peer set manager. +#[derive(Debug)] +pub struct PeersetConfig { + /// Maximum number of ingoing links to peers. + pub in_peers: u32, + + /// Maximum number of outgoing links to peers. + pub out_peers: u32, + + /// List of bootstrap nodes to initialize the peer with. + /// + /// > **Note**: Keep in mind that the networking has to know an address for these nodes, + /// > otherwise it will not be able to connect to them. + pub bootnodes: Vec, + + /// If true, we only accept reserved nodes. + pub reserved_only: bool, + + /// List of nodes that we should always be connected to. + /// + /// > **Note**: Keep in mind that the networking has to know an address for these nodes, + /// > otherwise it will not be able to connect to them. + pub reserved_nodes: Vec, +} + +/// Side of the peer set manager owned by the network. In other words, the "receiving" side. +/// +/// Implements the `Stream` trait and can be polled for messages. The `Stream` never ends and never +/// errors. +pub struct PeersetMut { + parent: Arc, + rx: mpsc::UnboundedReceiver, +} + +impl Peerset { + /// Builds a new peerset from the given configuration. + pub fn from_config(config: PeersetConfig) -> (Arc, PeersetMut) { + let (tx, rx) = mpsc::unbounded(); + + let mut inner = Inner { + discovered: config.bootnodes.into_iter().collect(), + reserved: Default::default(), + reserved_only: config.reserved_only, + out_slots: (0 .. config.out_peers).map(|_| None).collect(), + in_slots: (0 .. config.in_peers).map(|_| None).collect(), + }; + + alloc_slots(&mut inner, &tx); + + let peerset = Arc::new(Peerset { + tx, + inner: Mutex::new(inner), + }); + + let rx = PeersetMut { + parent: peerset.clone(), + rx, + }; + + for reserved in config.reserved_nodes { + peerset.add_reserved_peer(reserved); + } + + (peerset, rx) + } + + /// Adds a new reserved peer. The peerset will make an effort to always remain connected to + /// this peer. + /// + /// Has no effect if the node was already a reserved peer. + /// + /// > **Note**: Keep in mind that the networking has to know an address for this node, + /// > otherwise it will not be able to connect to it. + pub fn add_reserved_peer(&self, peer_id: PeerId) { + let mut inner = self.inner.lock(); + if !inner.reserved.insert(peer_id.clone()) { + // Immediately return if this peer was already in the list. + return; + } + + // Nothing more to do if we're already connected. + if inner.out_slots.iter().chain(inner.in_slots.iter()).any(|s| s.as_ref() == Some(&peer_id)) { + return; + } + + // Assign a slot for this reserved peer. + if let Some(pos) = inner.out_slots.iter().position(|s| s.as_ref().map(|n| !inner.reserved.contains(n)).unwrap_or(true)) { + let _ = self.tx.unbounded_send(Message::Connect(peer_id.clone())); + inner.out_slots[pos] = Some(peer_id); + + } else { + // All slots are filled with reserved peers. + if inner.discovered.iter().all(|p| *p != peer_id) { + inner.discovered.push(peer_id); + } + } + } + + /// Remove a previously-added reserved peer. + /// + /// Has no effect if the node was not a reserved peer. + pub fn remove_reserved_peer(&self, peer_id: &PeerId) { + let mut inner = self.inner.lock(); + inner.reserved.remove(peer_id); + } + + /// Sets whether or not the peerset only has connections . + pub fn set_reserved_only(&self, reserved_only: bool) { + let mut inner = self.inner.lock(); + let inner = &mut *inner; // Fixes a borrowing issue. + inner.reserved_only = reserved_only; + + // Disconnect non-reserved nodes. + if reserved_only { + for slot in inner.out_slots.iter_mut().chain(inner.in_slots.iter_mut()) { + if let Some(peer) = slot.as_ref() { + if inner.reserved.contains(peer) { + continue; + } + + let _ = self.tx.unbounded_send(Message::Drop(peer.clone())); + } + + *slot = None; + } + } + } + + /// Reports an adjustement to the reputation of the given peer. + pub fn report_peer(&self, _peer_id: &PeerId, _score_diff: i32) { + // This is not implemented in this dummy implementation. + } +} + +fn alloc_slots(inner: &mut Inner, tx: &mpsc::UnboundedSender) { + if inner.reserved_only { + return; + } + + for slot in inner.out_slots.iter_mut() { + if slot.is_some() { + continue; + } + + if !inner.discovered.is_empty() { + let elem = inner.discovered.remove(0); + *slot = Some(elem.clone()); + let _ = tx.unbounded_send(Message::Connect(elem)); + } + } +} + +impl PeersetMut { + /// Indicate that we received an incoming connection. Must be answered either with + /// 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 `Accept`, but incoming connections aren't cancelled by + /// `dropped`. + /// + /// Because of concurrency issues, it is acceptable to call `incoming` with a `PeerId` the + /// peerset is already connected to, in which case it must not answer. + pub fn incoming(&self, peer_id: PeerId, index: IncomingIndex) { + let mut inner = self.parent.inner.lock(); + if inner.out_slots.iter().chain(inner.in_slots.iter()).any(|s| s.as_ref() == Some(&peer_id)) { + return + } + + if let Some(pos) = inner.in_slots.iter().position(|s| s.is_none()) { + inner.in_slots[pos] = Some(peer_id); + let _ = self.parent.tx.unbounded_send(Message::Accept(index)); + } else { + if inner.discovered.iter().all(|p| *p != peer_id) { + inner.discovered.push(peer_id); + } + let _ = self.parent.tx.unbounded_send(Message::Reject(index)); + } + } + + /// Indicate that we dropped an active connection with a peer, or that we failed to connect. + /// + /// Must only be called after the PSM has either generated a `Connect` message with this + /// `PeerId`, or accepted an incoming connection with this `PeerId`. + pub fn dropped(&self, peer_id: &PeerId) { + let mut inner = self.parent.inner.lock(); + let inner = &mut *inner; // Fixes a borrowing issue. + + // Automatically connect back if reserved. + if inner.reserved.contains(peer_id) { + let _ = self.parent.tx.unbounded_send(Message::Connect(peer_id.clone())); + return + } + + // Otherwise, free the slot. + for slot in inner.out_slots.iter_mut().chain(inner.in_slots.iter_mut()) { + if slot.as_ref() == Some(peer_id) { + *slot = None; + break; + } + } + + // Note: in this dummy implementation we consider that peers never expire. As soon as we + // are disconnected from a peer, we try again. + if inner.discovered.iter().all(|p| p != peer_id) { + inner.discovered.push(peer_id.clone()); + } + alloc_slots(inner, &self.parent.tx); + } + + /// Adds a discovered peer id to the PSM. + /// + /// > **Note**: There is no equivalent "expired" message, meaning that it is the responsibility + /// > of the PSM to remove `PeerId`s that fail to dial too often. + pub fn discovered(&self, peer_id: PeerId) { + let mut inner = self.parent.inner.lock(); + + if inner.out_slots.iter().chain(inner.in_slots.iter()).any(|p| p.as_ref() == Some(&peer_id)) { + return; + } + + if inner.discovered.iter().all(|p| *p != peer_id) { + inner.discovered.push(peer_id); + } + alloc_slots(&mut inner, &self.parent.tx); + } + + /// Produces a JSON object containing the state of the peerset manager, for debugging purposes. + pub fn debug_info(&self) -> serde_json::Value { + serde_json::Value::Null + } +} + +impl Stream for PeersetMut { + type Item = Message; + type Error = (); + + fn poll(&mut self) -> Poll, Self::Error> { + self.rx.poll() + } +} diff --git a/core/primitives/Cargo.toml b/core/primitives/Cargo.toml index 2cc687fdb567c4e87f28e1ef6769f8e334edfd1e..fb4893613858bb8f9ec62952fe75259214e4fdd8 100644 --- a/core/primitives/Cargo.toml +++ b/core/primitives/Cargo.toml @@ -6,26 +6,29 @@ edition = "2018" [dependencies] rstd = { package = "sr-std", path = "../sr-std", default-features = false } -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", default-features = false, features = ["derive"] } rustc-hex = { version = "2.0", default-features = false } -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } twox-hash = { version = "1.1.0", optional = true } byteorder = { version = "1.1", default-features = false } primitive-types = { version = "0.2", default-features = false, features = ["codec"] } impl-serde = { version = "0.1", optional = true } wasmi = { version = "0.4.3", optional = true } -hash-db = { version = "0.11", default-features = false } -hash256-std-hasher = { version = "0.11", default-features = false } +hash-db = { version = "0.12", default-features = false } +hash256-std-hasher = { version = "0.12", default-features = false } ring = { version = "0.14", optional = true } untrusted = { version = "0.6", optional = true } hex-literal = { version = "0.1", optional = true } base58 = { version = "0.1", optional = true } blake2-rfc = { version = "0.2.18", optional = true } -schnorrkel = { version = "0.0", optional = true } +schnorrkel = { version = "0.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 } +tiny-bip39 = { version = "0.6.0", optional = true } +hex = { version = "0.3", optional = true } +regex = {version = "1.1", optional = true } [dev-dependencies] substrate-serializer = { path = "../serializer" } @@ -47,17 +50,21 @@ std = [ "hash256-std-hasher/std", "hash-db/std", "rstd/std", - "serde/std", + "serde", "rustc-hex/std", "twox-hash", "blake2-rfc", "ring", "untrusted", "hex-literal", + "hex", "base58", + "substrate-bip39", + "tiny-bip39", "serde_derive", "byteorder/std", "rand", "sha2", "schnorrkel", + "regex", ] diff --git a/core/primitives/src/authority_id.rs b/core/primitives/src/authority_id.rs deleted file mode 100644 index c7f8fd6958b6411493e930e986f8df77e0e21551..0000000000000000000000000000000000000000 --- a/core/primitives/src/authority_id.rs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2017-2018 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 . - -#[cfg(feature = "std")] -use serde::{Serialize, Serializer, Deserialize, Deserializer}; -use parity_codec_derive::{Encode, Decode}; -use crate::H256; - -/// An identifier for an authority in the consensus algorithm. The same size as ed25519::Public. -#[derive(Clone, Copy, PartialEq, Eq, Default, Encode, Decode)] -pub struct Ed25519AuthorityId(pub [u8; 32]); - -#[cfg(feature = "std")] -impl ::std::fmt::Display for Ed25519AuthorityId { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "{}", crate::ed25519::Public(self.0).to_ss58check()) - } -} - -#[cfg(feature = "std")] -impl ::std::fmt::Debug for Ed25519AuthorityId { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - let h = format!("{}", crate::hexdisplay::HexDisplay::from(&self.0)); - write!(f, "{} ({}…{})", crate::ed25519::Public(self.0).to_ss58check(), &h[0..8], &h[60..]) - } -} - -#[cfg(feature = "std")] -impl ::std::hash::Hash for Ed25519AuthorityId { - fn hash(&self, state: &mut H) { - self.0.hash(state); - } -} - -impl AsRef<[u8; 32]> for Ed25519AuthorityId { - fn as_ref(&self) -> &[u8; 32] { - &self.0 - } -} - -impl AsRef<[u8]> for Ed25519AuthorityId { - fn as_ref(&self) -> &[u8] { - &self.0[..] - } -} - -impl Into<[u8; 32]> for Ed25519AuthorityId { - fn into(self) -> [u8; 32] { - self.0 - } -} - -impl From<[u8; 32]> for Ed25519AuthorityId { - fn from(a: [u8; 32]) -> Self { - Ed25519AuthorityId(a) - } -} - -impl AsRef for Ed25519AuthorityId { - fn as_ref(&self) -> &Ed25519AuthorityId { - &self - } -} - -impl Into for Ed25519AuthorityId { - fn into(self) -> H256 { - self.0.into() - } -} - -#[cfg(feature = "std")] -impl Serialize for Ed25519AuthorityId { - fn serialize(&self, serializer: S) -> Result where S: Serializer { - crate::ed25519::serialize(&self, serializer) - } -} - -#[cfg(feature = "std")] -impl<'de> Deserialize<'de> for Ed25519AuthorityId { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { - crate::ed25519::deserialize(deserializer) - } -} diff --git a/core/primitives/src/changes_trie.rs b/core/primitives/src/changes_trie.rs index 8ccd3eb4c0a5b7945ca265f10825aa2d1cdf9f71..c8776a6f0873f210f2fac9c246aada2661960fbb 100644 --- a/core/primitives/src/changes_trie.rs +++ b/core/primitives/src/changes_trie.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -18,7 +18,7 @@ #[cfg(any(feature = "std", test))] use serde_derive::{Serialize, Deserialize}; -use parity_codec_derive::{Encode, Decode}; +use parity_codec::{Encode, Decode}; /// Substrate changes trie configuration. #[cfg_attr(any(feature = "std", test), derive(Serialize, Deserialize))] diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs new file mode 100644 index 0000000000000000000000000000000000000000..fe7c1fabb8eccdacb99040b2adf443ff61cd109e --- /dev/null +++ b/core/primitives/src/crypto.rs @@ -0,0 +1,497 @@ +// 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 . + +// tag::description[] +//! Cryptographic utilities. +// end::description[] + +#[cfg(feature = "std")] +use parity_codec::{Encode, Decode}; +#[cfg(feature = "std")] +use regex::Regex; +#[cfg(feature = "std")] +use base58::{FromBase58, ToBase58}; + +/// The root phrase for our publically known keys. +pub const DEV_PHRASE: &str = "bottom drive obey lake curtain smoke basket hold race lonely fit walk"; + +/// The address of the associated root phrase for our publically known keys. +pub const DEV_ADDRESS: &str = "5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqAS7"; + +/// The infallible type. +#[derive(Debug)] +pub enum Infallible {} + +/// The length of the junction identifier. Note that this is also referred to as the +/// `CHAIN_CODE_LENGTH` in the context of Schnorrkel. +#[cfg(feature = "std")] +pub const JUNCTION_ID_LEN: usize = 32; + +/// Similar to `From`, except that the onus is on the part of the caller to ensure +/// that data passed in makes sense. Basically, you're not guaranteed to get anything +/// sensible out. +pub trait UncheckedFrom { + /// Convert from an instance of `T` to Self. This is not guaranteed to be + /// whatever counts as a valid instance of `T` and it's up to the caller to + /// ensure that it makes sense. + fn unchecked_from(t: T) -> Self; +} + +/// The counterpart to `UncheckedFrom`. +pub trait UncheckedInto { + /// The counterpart to `unchecked_from`. + fn unchecked_into(self) -> T; +} + +impl> UncheckedInto for S { + fn unchecked_into(self) -> T { + T::unchecked_from(self) + } +} + +/// An error with the interpretation of a secret. +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg(feature = "std")] +pub enum SecretStringError { + /// The overall format was invalid (e.g. the seed phrase contained symbols). + InvalidFormat, + /// The seed phrase provided is not a valid BIP39 phrase. + InvalidPhrase, + /// The supplied password was invalid. + InvalidPassword, + /// The seed is invalid (bad content). + InvalidSeed, + /// The seed has an invalid length. + InvalidSeedLength, + /// The derivation path was invalid (e.g. contains soft junctions when they are not supported). + InvalidPath, +} + +/// A since derivation junction description. It is the single parameter used when creating +/// a new secret key from an existing secret key and, in the case of `SoftRaw` and `SoftIndex` +/// a new public key from an existing public key. +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Encode, Decode)] +#[cfg(feature = "std")] +pub enum DeriveJunction { + /// Soft (vanilla) derivation. Public keys have a correspondent derivation. + Soft([u8; JUNCTION_ID_LEN]), + /// Hard ("hardened") derivation. Public keys do not have a correspondent derivation. + Hard([u8; JUNCTION_ID_LEN]), +} + +#[cfg(feature = "std")] +impl DeriveJunction { + /// Consume self to return a soft derive junction with the same chain code. + pub fn soften(self) -> Self { DeriveJunction::Soft(self.unwrap_inner()) } + + /// Consume self to return a hard derive junction with the same chain code. + pub fn harden(self) -> Self { DeriveJunction::Hard(self.unwrap_inner()) } + + /// Create a new soft (vanilla) DeriveJunction from a given, encodable, value. + /// + /// If you need a hard junction, use `hard()`. + pub fn soft(index: T) -> Self { + let mut cc: [u8; JUNCTION_ID_LEN] = Default::default(); + index.using_encoded(|data| if data.len() > JUNCTION_ID_LEN { + let hash_result = blake2_rfc::blake2b::blake2b(JUNCTION_ID_LEN, &[], data); + let hash = hash_result.as_bytes(); + cc.copy_from_slice(hash); + } else { + cc[0..data.len()].copy_from_slice(data); + }); + DeriveJunction::Soft(cc) + } + + /// Create a new hard (hardened) DeriveJunction from a given, encodable, value. + /// + /// If you need a soft junction, use `soft()`. + pub fn hard(index: T) -> Self { + Self::soft(index).harden() + } + + /// Consume self to return the chain code. + pub fn unwrap_inner(self) -> [u8; JUNCTION_ID_LEN] { + match self { + DeriveJunction::Hard(c) | DeriveJunction::Soft(c) => c, + } + } + + /// Get a reference to the inner junction id. + pub fn inner(&self) -> &[u8; JUNCTION_ID_LEN] { + match self { + DeriveJunction::Hard(ref c) | DeriveJunction::Soft(ref c) => c, + } + } + + /// Return `true` if the junction is soft. + pub fn is_soft(&self) -> bool { + match *self { + DeriveJunction::Soft(_) => true, + _ => false, + } + } + + /// Return `true` if the junction is hard. + pub fn is_hard(&self) -> bool { + match *self { + DeriveJunction::Hard(_) => true, + _ => false, + } + } +} + +#[cfg(feature = "std")] +impl> From for DeriveJunction { + fn from(j: T) -> DeriveJunction { + let j = j.as_ref(); + let (code, hard) = if j.starts_with("/") { + (&j[1..], true) + } else { + (j, false) + }; + + let res = if let Ok(n) = str::parse::(code) { + // number + DeriveJunction::soft(n) + } else { + // something else + DeriveJunction::soft(code) + }; + + if hard { + res.harden() + } else { + res + } + } +} + +/// An error type for SS58 decoding. +#[cfg(feature = "std")] +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub enum PublicError { + /// Bad alphabet. + BadBase58, + /// Bad length. + BadLength, + /// Unknown version. + UnknownVersion, + /// Invalid checksum. + InvalidChecksum, + /// Invalid format. + InvalidFormat, + /// Invalid derivation path. + InvalidPath, +} + +/// Key that can be encoded to/from SS58. +#[cfg(feature = "std")] +pub trait Ss58Codec: Sized { + /// Some if the string is a properly encoded SS58Check address. + fn from_ss58check(s: &str) -> Result; + /// Some if the string is a properly encoded SS58Check address, optionally with + /// a derivation path following. + fn from_string(s: &str) -> Result { Self::from_ss58check(s) } + /// Return the ss58-check string for this key. + fn to_ss58check(&self) -> String; +} + +#[cfg(feature = "std")] +/// Derivable key trait. +pub trait Derive: Sized { + /// Derive a child key from a series of given junctions. + /// + /// Will be `None` for public keys if there are any hard junctions in there. + fn derive>(&self, _path: Iter) -> Option { None } +} + +#[cfg(feature = "std")] +impl + AsRef<[u8]> + Default + Derive> Ss58Codec for T { + fn from_ss58check(s: &str) -> Result { + let mut res = T::default(); + let len = res.as_mut().len(); + let d = s.from_base58().map_err(|_| PublicError::BadBase58)?; // failure here would be invalid encoding. + if d.len() != len + 3 { + // Invalid length. + return Err(PublicError::BadLength); + } + if d[0] != 42 { + // Invalid version. + return Err(PublicError::UnknownVersion); + } + if d[len+1..len+3] != blake2_rfc::blake2b::blake2b(64, &[], &d[0..len+1]).as_bytes()[0..2] { + // Invalid checksum. + return Err(PublicError::InvalidChecksum); + } + res.as_mut().copy_from_slice(&d[1..len+1]); + Ok(res) + } + + fn to_ss58check(&self) -> String { + let mut v = vec![42u8]; + v.extend(self.as_ref()); + let r = blake2_rfc::blake2b::blake2b(64, &[], &v); + v.extend(&r.as_bytes()[0..2]); + v.to_base58() + } + + fn from_string(s: &str) -> Result { + let re = Regex::new(r"^(?P[\w\d]+)?(?P(//?[^/]+)*)$") + .expect("constructed from known-good static value; qed"); + let cap = re.captures(s).ok_or(PublicError::InvalidFormat)?; + let re_junction = Regex::new(r"/(/?[^/]+)") + .expect("constructed from known-good static value; qed"); + let path = re_junction.captures_iter(&cap["path"]) + .map(|f| DeriveJunction::from(&f[1])); + Self::from_ss58check(cap.name("ss58").map(|r| r.as_str()).unwrap_or(DEV_ADDRESS))? + .derive(path) + .ok_or(PublicError::InvalidPath) + } +} + +/// 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 { + /// TThe type which is used to encode a public key. + type Public; + + /// The type used to (minimally) encode the data required to securely create + /// a new key pair. + type Seed; + + /// 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; + + /// Error returned from the `derive` function. + type DeriveError; + + /// Generate new secure (random) key pair. + /// + /// This is only for ephemeral keys really, since you won't have access to the secret key + /// for storage. If you want a persistent key pair, use `generate_with_phrase` instead. + fn generate() -> Self; + + /// Generate new secure (random) key pair and provide the recovery phrase. + /// + /// You can recover the same key later with `from_phrase`. + /// + /// This is generally slower than `generate()`, so prefer that unless you need to persist + /// the key from the current session. + fn generate_with_phrase(password: Option<&str>) -> (Self, String); + + /// Returns the KeyPair from the English BIP39 seed `phrase`, or `None` if it's invalid. + fn from_phrase(phrase: &str, password: Option<&str>) -> Result; + + /// Derive a child key from a series of given junctions. + fn derive>(&self, path: Iter) -> Result; + + /// Generate new key pair from the provided `seed`. + /// + /// @WARNING: THIS WILL ONLY BE SECURE IF THE `seed` IS SECURE. If it can be guessed + /// by an attacker then they can also derive your key. + fn from_seed(seed: Self::Seed) -> Self; + + /// Make a new key pair from secret seed material. The slice must be the correct size or + /// it will return `None`. + /// + /// @WARNING: THIS WILL ONLY BE SECURE IF THE `seed` IS SECURE. If it can be guessed + /// by an attacker then they can also derive your key. + fn from_seed_slice(seed: &[u8]) -> Result; + + /// Construct a key from a phrase, password and path. + fn from_standard_components< + I: Iterator + >(phrase: &str, password: Option<&str>, path: I) -> Result; + + /// Sign a message. + fn sign(&self, message: &[u8]) -> Self::Signature; + + /// Verify a signature on a message. Returns true if the signature is good. + fn verify, M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: P) -> bool; + + /// Verify a signature on a message. Returns true if the signature is good. + fn verify_weak, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool; + + /// Get the public key. + fn public(&self) -> Self::Public; + + /// Interprets the string `s` in order to generate a key Pair. + /// + /// This takes a helper function to do the key generation from a phrase, password and + /// junction iterator. + /// + /// - If `s` is a possibly `0x` prefixed 64-digit hex string, then it will be interpreted + /// directly as a `MiniSecretKey` (aka "seed" in `subkey`). + /// - If `s` is a valid BIP-39 key phrase of 12, 15, 18, 21 or 24 words, then the key will + /// be derived from it. In this case: + /// - the phrase may be followed by one or more items delimited by `/` characters. + /// - the path may be followed by `///`, in which case everything after the `///` is treated + /// as a password. + /// - If `s` begins with a `/` character it is prefixed with the Substrate public `DEV_PHRASE` and + /// interpreted as above. + /// + /// In this case they are interpreted as HDKD junctions; purely numeric items are interpreted as + /// integers, non-numeric items as strings. Junctions prefixed with `/` are interpreted as soft + /// junctions, and with `//` as hard junctions. + /// + /// There is no correspondence mapping between SURI strings and the keys they represent. + /// Two different non-identical strings can actually lead to the same secret being derived. + /// Notably, integer junction indices may be legally prefixed with arbitrary number of zeros. + /// Similarly an empty password (ending the SURI with `///`) is perfectly valid and will generally + /// be equivalent to no password at all. + /// + /// `None` is returned if no matches are found. + fn from_string(s: &str, password_override: Option<&str>) -> Result { + let hex_seed = if s.starts_with("0x") { + &s[2..] + } else { + s + }; + + if let Ok(d) = hex::decode(hex_seed) { + if let Ok(r) = Self::from_seed_slice(&d) { + return Ok(r) + } + } + + let re = Regex::new(r"^(?P\w+( \w+)*)?(?P(//?[^/]+)*)(///(?P.*))?$") + .expect("constructed from known-good static value; qed"); + let cap = re.captures(s).ok_or(SecretStringError::InvalidFormat)?; + let re_junction = Regex::new(r"/(/?[^/]+)") + .expect("constructed from known-good static value; qed"); + let path = re_junction.captures_iter(&cap["path"]) + .map(|f| DeriveJunction::from(&f[1])); + Self::from_standard_components( + cap.name("phrase").map(|r| r.as_str()).unwrap_or(DEV_PHRASE), + password_override.or_else(|| cap.name("password").map(|m| m.as_str())), + path, + ) + } +} + +#[cfg(test)] +mod tests { + use crate::DeriveJunction; + use hex_literal::{hex, hex_impl}; + use super::*; + + #[derive(Eq, PartialEq, Debug)] + enum TestPair { + Generated, + GeneratedWithPhrase, + GeneratedFromPhrase{phrase: String, password: Option}, + Standard{phrase: String, password: Option, path: Vec}, + Seed(Vec), + } + + impl Pair for TestPair { + type Public = (); + type Seed = (); + type Signature = (); + type DeriveError = (); + + fn generate() -> Self { TestPair::Generated } + fn generate_with_phrase(_password: Option<&str>) -> (Self, String) { (TestPair::GeneratedWithPhrase, "".into()) } + fn from_phrase(phrase: &str, password: Option<&str>) -> Result { + Ok(TestPair::GeneratedFromPhrase{ phrase: phrase.to_owned(), password: password.map(Into::into) }) + } + fn derive>(&self, _path: Iter) -> Result { + Err(()) + } + fn from_seed(_seed: Self::Seed) -> Self { TestPair::Seed(vec![]) } + fn sign(&self, _message: &[u8]) -> Self::Signature { () } + fn verify, M: AsRef<[u8]>>(_sig: &Self::Signature, _message: M, _pubkey: P) -> bool { true } + fn verify_weak, M: AsRef<[u8]>>(_sig: &[u8], _message: M, _pubkey: P) -> bool { true } + fn public(&self) -> Self::Public { () } + fn from_standard_components>(phrase: &str, password: Option<&str>, path: I) -> Result { + Ok(TestPair::Standard { phrase: phrase.to_owned(), password: password.map(ToOwned::to_owned), path: path.collect() }) + } + fn from_seed_slice(seed: &[u8]) -> Result { + Ok(TestPair::Seed(seed.to_owned())) + } + } + + #[test] + fn interpret_std_seed_should_work() { + assert_eq!( + TestPair::from_string("0x0123456789abcdef", None), + Ok(TestPair::Seed(hex!["0123456789abcdef"][..].to_owned())) + ); + assert_eq!( + TestPair::from_string("0123456789abcdef", None), + Ok(TestPair::Seed(hex!["0123456789abcdef"][..].to_owned())) + ); + } + + #[test] + fn password_override_should_work() { + assert_eq!( + TestPair::from_string("hello world///password", None), + TestPair::from_string("hello world", Some("password")), + ); + assert_eq!( + TestPair::from_string("hello world///password", None), + TestPair::from_string("hello world///other password", Some("password")), + ); + } + + #[test] + fn interpret_std_secret_string_should_work() { + assert_eq!( + TestPair::from_string("hello world", None), + Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![]}) + ); + assert_eq!( + TestPair::from_string("hello world/1", None), + Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::soft(1)]}) + ); + assert_eq!( + TestPair::from_string("hello world/DOT", None), + Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::soft("DOT")]}) + ); + assert_eq!( + TestPair::from_string("hello world//1", None), + Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::hard(1)]}) + ); + assert_eq!( + TestPair::from_string("hello world//DOT", None), + Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::hard("DOT")]}) + ); + assert_eq!( + TestPair::from_string("hello world//1/DOT", None), + Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::hard(1), DeriveJunction::soft("DOT")]}) + ); + assert_eq!( + TestPair::from_string("hello world//DOT/1", None), + Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::hard("DOT"), DeriveJunction::soft(1)]}) + ); + assert_eq!( + TestPair::from_string("hello world///password", None), + Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: Some("password".to_owned()), path: vec![]}) + ); + assert_eq!( + TestPair::from_string("hello world//1/DOT///password", None), + Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: Some("password".to_owned()), path: vec![DeriveJunction::hard(1), DeriveJunction::soft("DOT")]}) + ); + assert_eq!( + TestPair::from_string("hello world/1//DOT///password", None), + Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: Some("password".to_owned()), path: vec![DeriveJunction::soft(1), DeriveJunction::hard("DOT")]}) + ); + } +} diff --git a/core/primitives/src/ed25519.rs b/core/primitives/src/ed25519.rs index 313952ed2fe2d73c670dc64ad3fc05bbc78acedc..8b55300df45f65a7b9482b74572c7a3197130583 100644 --- a/core/primitives/src/ed25519.rs +++ b/core/primitives/src/ed25519.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -18,58 +18,251 @@ //! Simple Ed25519 API. // end::description[] + +use crate::{hash::H256, hash::H512}; +use parity_codec::{Encode, Decode}; + +#[cfg(feature = "std")] use untrusted; +#[cfg(feature = "std")] use blake2_rfc; -use ring::{rand, signature, signature::KeyPair}; -use crate::{hash::H512, Ed25519AuthorityId}; +#[cfg(feature = "std")] +use ring::{signature, signature::KeyPair, rand::{SecureRandom, SystemRandom}}; +#[cfg(feature = "std")] use base58::{ToBase58, FromBase58}; -use parity_codec_derive::{Encode, Decode}; +#[cfg(feature = "std")] +use substrate_bip39::seed_from_entropy; +#[cfg(feature = "std")] +use bip39::{Mnemonic, Language, MnemonicType}; +#[cfg(feature = "std")] +use crate::crypto::{Pair as TraitPair, DeriveJunction, SecretStringError, Derive}; +#[cfg(feature = "std")] +use serde::{de, Serializer, Serialize, Deserializer, Deserialize}; +use crate::crypto::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 +/// will need it later (such as for HDKD). #[cfg(feature = "std")] -use serde::{de, Serializer, Deserializer, Deserialize}; +type Seed = [u8; 32]; -/// Alias to 512-bit hash when used in the context of a signature on the relay chain. -pub type Signature = H512; +/// A public key. +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Default)] +pub struct Public(pub [u8; 32]); -/// Length of the PKCS#8 encoding of the key. -pub const PKCS_LEN: usize = 85; +/// A key pair. +#[cfg(feature = "std")] +pub struct Pair(signature::Ed25519KeyPair, Seed); -/// A localized signature also contains sender information. -#[derive(PartialEq, Eq, Clone, Debug, Encode, Decode)] -pub struct LocalizedSignature { - /// The signer of the signature. - pub signer: Public, - /// The signature itself. - pub signature: Signature, +#[cfg(feature = "std")] +impl Clone for Pair { + fn clone(&self) -> Self { + Pair::from_seed(self.1.clone()) + } } -/// Verify a message without type checking the parameters' types for the right size. -/// Returns true if the signature is good. -pub fn verify>(sig: &[u8], message: &[u8], public: P) -> bool { - let public_key = untrusted::Input::from(public.as_ref()); - let msg = untrusted::Input::from(message); - let sig = untrusted::Input::from(sig); +impl AsRef<[u8; 32]> for Public { + fn as_ref(&self) -> &[u8; 32] { + &self.0 + } +} - match signature::verify(&signature::ED25519, public_key, msg, sig) { - Ok(_) => true, - _ => false, +impl AsRef<[u8]> for Public { + fn as_ref(&self) -> &[u8] { + &self.0[..] } } -/// A public key. -#[derive(PartialEq, Eq, Clone, Encode, Decode)] -pub struct Public(pub [u8; 32]); +impl AsMut<[u8]> for Public { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0[..] + } +} -/// A key pair. -pub struct Pair(signature::Ed25519KeyPair); +impl From for [u8; 32] { + fn from(x: Public) -> Self { + x.0 + } +} + +#[cfg(feature = "std")] +impl From for Public { + fn from(x: Pair) -> Self { + x.public() + } +} + +impl AsRef for Public { + fn as_ref(&self) -> &Public { + &self + } +} + +impl From for H256 { + fn from(x: Public) -> Self { + x.0.into() + } +} + +impl UncheckedFrom<[u8; 32]> for Public { + fn unchecked_from(x: [u8; 32]) -> Self { + Public::from_raw(x) + } +} + +impl UncheckedFrom for Public { + fn unchecked_from(x: H256) -> Self { + Public::from_h256(x) + } +} + +#[cfg(feature = "std")] +impl ::std::fmt::Display for Public { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "{}", self.to_ss58check()) + } +} + +#[cfg(feature = "std")] +impl ::std::fmt::Debug for Public { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + let s = self.to_ss58check(); + write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8]) + } +} + +#[cfg(feature = "std")] +impl Serialize for Public { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + serializer.serialize_str(&self.to_ss58check()) + } +} +#[cfg(feature = "std")] +impl<'de> Deserialize<'de> for Public { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { + Public::from_ss58check(&String::deserialize(deserializer)?) + .map_err(|e| de::Error::custom(format!("{:?}", e))) + } +} + +#[cfg(feature = "std")] impl ::std::hash::Hash for Public { fn hash(&self, state: &mut H) { self.0.hash(state); } } +/// A signature (a 512-bit value). +#[derive(Encode, Decode)] +pub struct Signature(pub [u8; 64]); + +impl Clone for Signature { + fn clone(&self) -> Self { + let mut r = [0u8; 64]; + r.copy_from_slice(&self.0[..]); + Signature(r) + } +} + +impl Default for Signature { + fn default() -> Self { + Signature([0u8; 64]) + } +} + +impl PartialEq for Signature { + fn eq(&self, b: &Self) -> bool { + &self.0[..] == &b.0[..] + } +} + +impl Eq for Signature {} + +impl From for H512 { + fn from(v: Signature) -> H512 { + H512::from(v.0) + } +} + +impl From for [u8; 64] { + fn from(v: Signature) -> [u8; 64] { + v.0 + } +} + +impl AsRef<[u8; 64]> for Signature { + fn as_ref(&self) -> &[u8; 64] { + &self.0 + } +} + +impl AsRef<[u8]> for Signature { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl AsMut<[u8]> for Signature { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0[..] + } +} + +#[cfg(feature = "std")] +impl ::std::fmt::Debug for Signature { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0)) + } +} + +#[cfg(feature = "std")] +impl ::std::hash::Hash for Signature { + fn hash(&self, state: &mut H) { + ::std::hash::Hash::hash(&self.0[..], state); + } +} + +impl Signature { + /// A new instance from the given 64-byte `data`. + /// + /// NOTE: No checking goes on to ensure this is a real signature. Only use it if + /// you are certain that the array actually is a signature. GIGO! + pub fn from_raw(data: [u8; 64]) -> Signature { + Signature(data) + } + + /// A new instance from the given slice that should be 64 bytes long. + /// + /// NOTE: No checking goes on to ensure this is a real signature. Only use it if + /// you are certain that the array actually is a signature. GIGO! + pub fn from_slice(data: &[u8]) -> Self { + let mut r = [0u8; 64]; + r.copy_from_slice(data); + Signature(r) + } + + /// A new instance from an H512. + /// + /// NOTE: No checking goes on to ensure this is a real signature. Only use it if + /// you are certain that the array actually is a signature. GIGO! + pub fn from_h512(v: H512) -> Signature { + Signature(v.into()) + } +} + +/// A localized signature also contains sender information. +#[cfg(feature = "std")] +#[derive(PartialEq, Eq, Clone, Debug, Encode, Decode)] +pub struct LocalizedSignature { + /// The signer of the signature. + pub signer: Public, + /// The signature itself. + pub signature: Signature, +} + /// An error type for SS58 decoding. +#[cfg(feature = "std")] #[derive(Clone, Copy, Eq, PartialEq, Debug)] pub enum PublicError { /// Bad alphabet. @@ -84,36 +277,33 @@ pub enum PublicError { impl Public { /// A new instance from the given 32-byte `data`. + /// + /// 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_raw(data: [u8; 32]) -> Self { Public(data) } /// 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_slice(data: &[u8]) -> Self { let mut r = [0u8; 32]; r.copy_from_slice(data); Public(r) } - /// Some if the string is a properly encoded SS58Check address. - pub fn from_ss58check(s: &str) -> Result { - let d = s.from_base58().map_err(|_| PublicError::BadBase58)?; // failure here would be invalid encoding. - if d.len() != 35 { - // Invalid length. - return Err(PublicError::BadLength); - } - if d[0] != 42 { - // Invalid version. - return Err(PublicError::UnknownVersion); - } - if d[33..35] != blake2_rfc::blake2b::blake2b(64, &[], &d[0..33]).as_bytes()[0..2] { - // Invalid checksum. - return Err(PublicError::InvalidChecksum); - } - Ok(Self::from_slice(&d[1..33])) + /// 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_h256(x: H256) -> Self { + Public(x.into()) } /// Return a `Vec` filled with raw data. + #[cfg(feature = "std")] pub fn to_raw_vec(self) -> Vec { let r: &[u8; 32] = self.as_ref(); r.to_vec() @@ -129,6 +319,30 @@ impl Public { pub fn as_array_ref(&self) -> &[u8; 32] { self.as_ref() } +} + +#[cfg(feature = "std")] +impl Derive for Public {} + +#[cfg(feature = "std")] +impl Public { + /// Some if the string is a properly encoded SS58Check address. + pub fn from_ss58check(s: &str) -> Result { + let d = s.from_base58().map_err(|_| PublicError::BadBase58)?; // failure here would be invalid encoding. + if d.len() != 35 { + // Invalid length. + return Err(PublicError::BadLength); + } + if d[0] != 42 { + // Invalid version. + return Err(PublicError::UnknownVersion); + } + if d[33..35] != blake2_rfc::blake2b::blake2b(64, &[], &d[0..33]).as_bytes()[0..2] { + // Invalid checksum. + return Err(PublicError::InvalidChecksum); + } + Ok(Self::from_slice(&d[1..33])) + } /// Return the ss58-check string for this key. pub fn to_ss58check(&self) -> String { @@ -140,178 +354,205 @@ impl Public { } } -impl AsRef<[u8; 32]> for Public { - fn as_ref(&self) -> &[u8; 32] { - &self.0 - } -} - -impl AsRef<[u8]> for Public { - fn as_ref(&self) -> &[u8] { - &self.0[..] - } -} - -impl Into<[u8; 32]> for Public { - fn into(self) -> [u8; 32] { - self.0 - } -} - -impl AsRef for Public { - fn as_ref(&self) -> &Public { - &self - } -} - +#[cfg(feature = "std")] impl AsRef for Pair { fn as_ref(&self) -> &Pair { &self } } -impl Into for Public { - fn into(self) -> Ed25519AuthorityId { - Ed25519AuthorityId(self.0) - } -} - -impl From for Public { - fn from(id: Ed25519AuthorityId) -> Self { - Public(id.0) - } -} - -impl ::std::fmt::Display for Public { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "{}", self.to_ss58check()) - } +/// Derive a single hard junction. +#[cfg(feature = "std")] +fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { + ("Ed25519HDKD", secret_seed, cc).using_encoded(|data| { + let mut res = [0u8; 32]; + res.copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], data).as_bytes()); + res + }) } -impl ::std::fmt::Debug for Public { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - let s = self.to_ss58check(); - write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8]) - } +/// An error when deriving a key. +#[cfg(feature = "std")] +pub enum DeriveError { + /// A soft key was found in the path (and is unsupported). + SoftKeyInPath, } -impl Pair { - /// Generate new secure (random) key pair, yielding it and the corresponding pkcs#8 bytes. - pub fn generate_with_pkcs8() -> (Self, [u8; PKCS_LEN]) { - let rng = rand::SystemRandom::new(); - let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(&rng).expect("system randomness is available; qed"); - let pair = Self::from_pkcs8(&pkcs8_bytes.as_ref()).expect("just-generated pkcs#8 data is valid; qed"); - - let mut out = [0; PKCS_LEN]; - out.copy_from_slice(pkcs8_bytes.as_ref()); - (pair, out) - } +#[cfg(feature = "std")] +impl TraitPair for Pair { + type Public = Public; + type Seed = Seed; + type Signature = Signature; + type DeriveError = DeriveError; /// Generate new secure (random) key pair. - pub fn generate() -> Pair { - let (pair, _) = Self::generate_with_pkcs8(); - pair - } - - /// Generate from pkcs#8 bytes. - pub fn from_pkcs8(pkcs8_bytes: &[u8]) -> Result { - signature::Ed25519KeyPair::from_pkcs8(untrusted::Input::from(&pkcs8_bytes)).map(Pair) - } - - /// Make a new key pair from a seed phrase. - /// NOTE: prefer pkcs#8 unless security doesn't matter -- this is used primarily for tests. - pub fn from_seed(seed: &[u8; 32]) -> Pair { + /// + /// This is only for ephemeral keys really, since you won't have access to the secret key + /// for storage. If you want a persistent key pair, use `generate_with_phrase` instead. + fn generate() -> Pair { + let mut seed: Seed = Default::default(); + SystemRandom::new().fill(seed.as_mut()).expect("system random source should always work! qed"); + Self::from_seed(seed) + } + + /// Generate new secure (random) key pair and provide the recovery phrase. + /// + /// You can recover the same key later with `from_phrase`. + fn generate_with_phrase(password: Option<&str>) -> (Pair, String) { + let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English); + let phrase = mnemonic.phrase(); + ( + Self::from_phrase(phrase, password).expect("All phrases generated by Mnemonic are valid; qed"), + phrase.to_owned(), + ) + } + + /// Generate key pair from given recovery phrase and password. + fn from_phrase(phrase: &str, password: Option<&str>) -> Result { + let big_seed = seed_from_entropy( + Mnemonic::from_phrase(phrase, Language::English) + .map_err(|_| SecretStringError::InvalidPhrase)?.entropy(), + password.unwrap_or(""), + ).map_err(|_| SecretStringError::InvalidSeed)?; + Self::from_seed_slice(&big_seed[0..32]) + } + + /// Make a new key pair from secret seed material. + /// + /// You should never need to use this; generate(), generate_with_phrasee + fn from_seed(seed: Seed) -> Pair { let key = signature::Ed25519KeyPair::from_seed_unchecked(untrusted::Input::from(&seed[..])) .expect("seed has valid length; qed"); + Pair(key, seed) + } + + /// Make a new key pair from secret seed material. The slice must be 32 bytes long or it + /// will return `None`. + /// + /// You should never need to use this; generate(), generate_with_phrase + fn from_seed_slice(seed_slice: &[u8]) -> Result { + if seed_slice.len() != 32 { + Err(SecretStringError::InvalidSeedLength) + } else { + let mut seed = [0u8; 32]; + seed.copy_from_slice(&seed_slice); + Ok(Self::from_seed(seed)) + } + } - Pair(key) + /// Derive a child key from a series of given junctions. + fn derive>(&self, path: Iter) -> Result { + let mut acc = self.1.clone(); + for j in path { + match j { + DeriveJunction::Soft(_cc) => return Err(DeriveError::SoftKeyInPath), + DeriveJunction::Hard(cc) => acc = derive_hard_junction(&acc, &cc), + } + } + Ok(Self::from_seed(acc)) } - /// Sign a message. - pub fn sign(&self, message: &[u8]) -> Signature { - let mut r = [0u8; 64]; - r.copy_from_slice(self.0.sign(message).as_ref()); - Signature::from(r) + /// Generate a key from the phrase, password and derivation path. + fn from_standard_components>(phrase: &str, password: Option<&str>, path: I) -> Result { + Self::from_phrase(phrase, password)?.derive(path).map_err(|_| SecretStringError::InvalidPath) } /// Get the public key. - pub fn public(&self) -> Public { + fn public(&self) -> Public { let mut r = [0u8; 32]; let pk = self.0.public_key().as_ref(); r.copy_from_slice(pk); Public(r) } -} -/// Verify a signature on a message. Returns true if the signature is good. -pub fn verify_strong>(sig: &Signature, message: &[u8], pubkey: P) -> bool { - let public_key = untrusted::Input::from(&pubkey.as_ref().0[..]); - let msg = untrusted::Input::from(message); - let sig = untrusted::Input::from(&sig.as_bytes()); - - match signature::verify(&signature::ED25519, public_key, msg, sig) { - Ok(_) => true, - _ => false, + /// Sign a message. + fn sign(&self, message: &[u8]) -> Signature { + let mut r = [0u8; 64]; + r.copy_from_slice(self.0.sign(message).as_ref()); + Signature::from_raw(r) } -} -/// Something that acts as a signature allowing a message to be verified. -pub trait Verifiable { - /// Verify something that acts like a signature. - fn verify>(&self, message: &[u8], pubkey: P) -> bool; -} + /// Verify a signature on a message. Returns true if the signature is good. + fn verify, M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: P) -> bool { + let public_key = untrusted::Input::from(&pubkey.as_ref().0[..]); + let msg = untrusted::Input::from(message.as_ref()); + let sig = untrusted::Input::from(&sig.0[..]); -impl Verifiable for Signature { - /// Verify something that acts like a signature. - fn verify>(&self, message: &[u8], pubkey: P) -> bool { - verify_strong(&self, message, pubkey) + match signature::verify(&signature::ED25519, public_key, msg, sig) { + Ok(_) => true, + _ => false, + } } -} -impl Verifiable for LocalizedSignature { - fn verify>(&self, message: &[u8], pubkey: P) -> bool { - pubkey.as_ref() == &self.signer && self.signature.verify(message, pubkey) + /// Verify a signature on a message. Returns true if the signature is good. + /// + /// This doesn't use the type system to ensure that `sig` and `pubkey` are the correct + /// size. Use it only if you're coming from byte buffers and need the speed. + fn verify_weak, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool { + let public_key = untrusted::Input::from(pubkey.as_ref()); + let msg = untrusted::Input::from(message.as_ref()); + let sig = untrusted::Input::from(sig); + + match signature::verify(&signature::ED25519, public_key, msg, sig) { + Ok(_) => true, + _ => false, + } } } -/// Deserialize from `ss58` into something that can be constructed from `[u8; 32]`. #[cfg(feature = "std")] -pub fn deserialize<'de, D, T: From<[u8; 32]>>(deserializer: D) -> Result where - D: Deserializer<'de>, -{ - let ss58 = String::deserialize(deserializer)?; - Public::from_ss58check(&ss58) - .map_err(|e| de::Error::custom(format!("{:?}", e))) - .map(|v| v.0.into()) -} +impl Pair { + /// Get the seed for this key. + pub fn seed(&self) -> &Seed { + &self.1 + } -/// Serializes something that implements `AsRef<[u8; 32]>` into `ss58`. -#[cfg(feature = "std")] -pub fn serialize>(data: &T, serializer: S) -> Result where - S: Serializer, -{ - serializer.serialize_str(&Public(*data.as_ref()).to_ss58check()) + /// Exactly as `from_string` except that if no matches are found then, the the first 32 + /// characters are taken (padded with spaces as necessary) and used as the MiniSecretKey. + pub fn from_legacy_string(s: &str, password_override: Option<&str>) -> Pair { + Self::from_string(s, password_override).unwrap_or_else(|_| { + let mut padded_seed: Seed = [' ' as u8; 32]; + let len = s.len().min(32); + padded_seed[..len].copy_from_slice(&s.as_bytes()[..len]); + Self::from_seed(padded_seed) + }) + } } #[cfg(test)] mod test { use super::*; use hex_literal::{hex, hex_impl}; + use crate::{Pair as PairT, crypto::DEV_PHRASE}; - fn _test_primitives_signature_and_local_the_same() { - fn takes_two(_: T, _: T) { } - takes_two(Signature::default(), crate::Signature::default()) + #[test] + fn default_phrase_should_be_used() { + assert_eq!( + Pair::from_string("//Alice///password", None).unwrap().public(), + Pair::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password")).unwrap().public(), + ); } #[test] fn test_vector_should_work() { - let pair: Pair = Pair::from_seed(&hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")); + let pair: Pair = Pair::from_seed(hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")); let public = pair.public(); assert_eq!(public, Public::from_raw(hex!("d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a"))); let message = b""; - let signature: Signature = hex!("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b").into(); + let signature = Signature::from_raw(hex!("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b")); assert!(&pair.sign(&message[..]) == &signature); - assert!(verify_strong(&signature, &message[..], &public)); + assert!(Pair::verify(&signature, &message[..], &public)); + } + + #[test] + fn test_vector_by_string_should_work() { + let pair: Pair = Pair::from_string("0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", None).unwrap(); + let public = pair.public(); + assert_eq!(public, Public::from_raw(hex!("d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a"))); + let message = b""; + let signature = Signature::from_raw(hex!("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b")); + assert!(&pair.sign(&message[..]) == &signature); + assert!(Pair::verify(&signature, &message[..], &public)); } #[test] @@ -320,33 +561,47 @@ mod test { let public = pair.public(); let message = b"Something important"; let signature = pair.sign(&message[..]); - assert!(verify_strong(&signature, &message[..], &public)); + assert!(Pair::verify(&signature, &message[..], &public)); } #[test] fn seeded_pair_should_work() { - use crate::hexdisplay::HexDisplay; - - let pair = Pair::from_seed(b"12345678901234567890123456789012"); + let pair = Pair::from_seed(*b"12345678901234567890123456789012"); let public = pair.public(); assert_eq!(public, Public::from_raw(hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee"))); let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"); let signature = pair.sign(&message[..]); - println!("Correct signature: {}", HexDisplay::from(&signature.as_bytes())); - assert!(verify_strong(&signature, &message[..], &public)); + println!("Correct signature: {:?}", signature); + assert!(Pair::verify(&signature, &message[..], &public)); + } + + #[test] + fn generate_with_phrase_recovery_possible() { + let (pair1, phrase) = Pair::generate_with_phrase(None); + let pair2 = Pair::from_phrase(&phrase, None).unwrap(); + + assert_eq!(pair1.public(), pair2.public()); } #[test] - fn generate_with_pkcs8_recovery_possible() { - let (pair1, pkcs8) = Pair::generate_with_pkcs8(); - let pair2 = Pair::from_pkcs8(&pkcs8).unwrap(); + fn generate_with_password_phrase_recovery_possible() { + let (pair1, phrase) = Pair::generate_with_phrase(Some("password")); + let pair2 = Pair::from_phrase(&phrase, Some("password")).unwrap(); assert_eq!(pair1.public(), pair2.public()); } + #[test] + fn password_does_something() { + let (pair1, phrase) = Pair::generate_with_phrase(Some("password")); + let pair2 = Pair::from_phrase(&phrase, None).unwrap(); + + assert_ne!(pair1.public(), pair2.public()); + } + #[test] fn ss58check_roundtrip_works() { - let pair = Pair::from_seed(b"12345678901234567890123456789012"); + let pair = Pair::from_seed(*b"12345678901234567890123456789012"); let public = pair.public(); let s = public.to_ss58check(); println!("Correct: {}", s); diff --git a/core/primitives/src/hash.rs b/core/primitives/src/hash.rs index e4ebbe4b1e880e797136b7e16b336a4c5a313a49..f3e3583be5771b3d0569753393cf232ad9a68cf4 100644 --- a/core/primitives/src/hash.rs +++ b/core/primitives/src/hash.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/primitives/src/hasher.rs b/core/primitives/src/hasher.rs index 7c540039ec24cf7642867109add221d5d4d5673b..4562180a1a454c5ba0ebe5e1cb8faffde1744ee9 100644 --- a/core/primitives/src/hasher.rs +++ b/core/primitives/src/hasher.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/primitives/src/hashing.rs b/core/primitives/src/hashing.rs index 1a149529781633b3f6415e49ec8c46940ffa4daf..814048fea848da3bdc9732b6521ace0220708da1 100644 --- a/core/primitives/src/hashing.rs +++ b/core/primitives/src/hashing.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/primitives/src/hexdisplay.rs b/core/primitives/src/hexdisplay.rs index b202fdf2e3fa955dfff43c7e355a30cb1a007ca9..d748208d0e09ff911be9245a4588ece343191d59 100644 --- a/core/primitives/src/hexdisplay.rs +++ b/core/primitives/src/hexdisplay.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/primitives/src/lib.rs b/core/primitives/src/lib.rs index cb1f7220439f36cd4c0d80c245c031954c180add..38ecec0fa4e06aeec0ab371f4f70b42075e792b4 100644 --- a/core/primitives/src/lib.rs +++ b/core/primitives/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -34,7 +34,7 @@ macro_rules! map { use rstd::prelude::*; use rstd::ops::Deref; -use parity_codec_derive::{Encode, Decode}; +use parity_codec::{Encode, Decode}; #[cfg(feature = "std")] use std::borrow::Cow; #[cfg(feature = "std")] @@ -49,19 +49,17 @@ pub mod hashing; pub use hashing::{blake2_256, twox_128, twox_256}; #[cfg(feature = "std")] pub mod hexdisplay; -#[cfg(feature = "std")] -pub mod ed25519; -#[cfg(feature = "std")] -pub mod sr25519; +pub mod crypto; pub mod u32_trait; +pub mod ed25519; +pub mod sr25519; pub mod hash; mod hasher; pub mod sandbox; pub mod storage; pub mod uint; -mod authority_id; mod changes_trie; #[cfg(test)] @@ -69,16 +67,43 @@ mod tests; pub use self::hash::{H160, H256, H512, convert_hash}; pub use self::uint::U256; -pub use authority_id::Ed25519AuthorityId; pub use changes_trie::ChangesTrieConfiguration; +#[cfg(feature = "std")] +pub use crypto::{DeriveJunction, Pair}; pub use hash_db::Hasher; // Switch back to Blake after PoC-3 is out // pub use self::hasher::blake::BlakeHasher; pub use self::hasher::blake2::Blake2Hasher; -/// A 512-bit value interpreted as a signature. -pub type Signature = hash::H512; +/// Context for executing a call into the runtime. +#[repr(u8)] +pub enum ExecutionContext { + /// Context for general importing (including own blocks). + Importing, + /// Context used when syncing the blockchain. + Syncing, + /// Context used for block construction. + BlockConstruction, + /// Offchain worker context. + OffchainWorker(Box), + /// Context used for other calls. + Other, +} + +/// An extended externalities for offchain workers. +pub trait OffchainExt { + /// Submits an extrinsics. + /// + /// The extrinsic will either go to the pool (signed) + /// or to the next produced block (inherent). + fn submit_extrinsic(&mut self, extrinsic: Vec); +} +impl OffchainExt for Box { + fn submit_extrinsic(&mut self, ex: Vec) { + (&mut **self).submit_extrinsic(ex) + } +} /// Hex-serialised shim for `Vec`. #[derive(PartialEq, Eq, Clone)] diff --git a/core/primitives/src/sandbox.rs b/core/primitives/src/sandbox.rs index 71f9199cf561496d7097a7b7431c7c9103c9f143..773a6b489330986c2e60a91c182a6bdd2ab187a0 100644 --- a/core/primitives/src/sandbox.rs +++ b/core/primitives/src/sandbox.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -16,9 +16,7 @@ //! Definition of a sandbox environment. -#[cfg(test)] -use parity_codec::Encode; -use parity_codec_derive::{Encode, Decode}; +use parity_codec::{Encode, Decode}; use rstd::vec::Vec; /// Error error that can be returned from host function. @@ -166,7 +164,7 @@ pub const MEM_UNLIMITED: u32 = -1i32 as u32; /// For FFI purposes. pub const ERR_OK: u32 = 0; -/// Validation or instantiation error occured when creating new +/// Validation or instantiation error occurred when creating new /// sandboxed module instance. /// /// For FFI purposes. diff --git a/core/primitives/src/sr25519.rs b/core/primitives/src/sr25519.rs index 842de7c682d61a2e58bda851736272790685ff05..a60ee94b7f4cdc03a615521955de6b2898706181 100644 --- a/core/primitives/src/sr25519.rs +++ b/core/primitives/src/sr25519.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -16,27 +16,210 @@ // tag::description[] //! Simple sr25519 (Schnorr-Ristretto) API. +//! +//! Note: `CHAIN_CODE_LENGTH` must be equal to `crate::crypto::JUNCTION_ID_LEN` +//! for this to work. // end::description[] -use base58::{FromBase58, ToBase58}; -use blake2_rfc; +#[cfg(feature = "std")] use rand::rngs::OsRng; -use schnorrkel::{signing_context, Keypair, MiniSecretKey, PublicKey}; -use sha2::Sha512; -use parity_codec_derive::{Encode, Decode}; -use crate::hash::H512; +#[cfg(feature = "std")] +use schnorrkel::{signing_context, Keypair, SecretKey, MiniSecretKey, PublicKey, + derive::{Derivation, ChainCode, CHAIN_CODE_LENGTH} +}; +#[cfg(feature = "std")] +use substrate_bip39::mini_secret_from_entropy; +#[cfg(feature = "std")] +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 parity_codec::{Encode, Decode}; #[cfg(feature = "std")] -use serde::{de, Deserialize, Deserializer, Serializer}; +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; +#[cfg(feature = "std")] +use schnorrkel::keys::MINI_SECRET_KEY_LENGTH; // signing context -const SIGNING_CTX: &'static [u8] = b"substrate transaction"; +#[cfg(feature = "std")] +const SIGNING_CTX: &[u8] = b"substrate"; + +/// An Schnorrkel/Ristretto x25519 ("sr25519") public key. +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Default)] +pub struct Public(pub [u8; 32]); + +/// An Schnorrkel/Ristretto x25519 ("sr25519") key pair. +#[cfg(feature = "std")] +pub struct Pair(Keypair); + +impl AsRef for Public { + fn as_ref(&self) -> &Public { + &self + } +} + +impl AsRef<[u8; 32]> for Public { + fn as_ref(&self) -> &[u8; 32] { + &self.0 + } +} + +impl AsRef<[u8]> for Public { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl AsMut<[u8]> for Public { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0[..] + } +} + +impl From for [u8; 32] { + fn from(x: Public) -> [u8; 32] { + x.0 + } +} + +impl From for H256 { + fn from(x: Public) -> H256 { + x.0.into() + } +} + +impl UncheckedFrom<[u8; 32]> for Public { + fn unchecked_from(x: [u8; 32]) -> Self { + Public::from_raw(x) + } +} + +impl UncheckedFrom for Public { + fn unchecked_from(x: H256) -> Self { + Public::from_h256(x) + } +} + +#[cfg(feature = "std")] +impl ::std::fmt::Display for Public { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "{}", self.to_ss58check()) + } +} + +#[cfg(feature = "std")] +impl ::std::fmt::Debug for Public { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + let s = self.to_ss58check(); + write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8]) + } +} +#[cfg(feature = "std")] +impl Serialize for Public { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + serializer.serialize_str(&self.to_ss58check()) + } +} + +#[cfg(feature = "std")] +impl<'de> Deserialize<'de> for Public { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { + Public::from_ss58check(&String::deserialize(deserializer)?) + .map_err(|e| de::Error::custom(format!("{:?}", e))) + } +} + +#[cfg(feature = "std")] +impl ::std::hash::Hash for Public { + fn hash(&self, state: &mut H) { + self.0.hash(state); + } +} + +/// An Schnorrkel/Ristretto x25519 ("sr25519") signature. +/// /// Instead of importing it for the local module, alias it to be available as a public type -pub type Signature = H512; +#[derive(Encode, Decode)] +pub struct Signature(pub [u8; 64]); + +impl Clone for Signature { + fn clone(&self) -> Self { + let mut r = [0u8; 64]; + r.copy_from_slice(&self.0[..]); + Signature(r) + } +} + +impl Default for Signature { + fn default() -> Self { + Signature([0u8; 64]) + } +} + +impl PartialEq for Signature { + fn eq(&self, b: &Self) -> bool { + &self.0[..] == &b.0[..] + } +} + +impl Eq for Signature {} + +impl From for [u8; 64] { + fn from(v: Signature) -> [u8; 64] { + v.0 + } +} + +impl From for H512 { + fn from(v: Signature) -> H512 { + H512::from(v.0) + } +} + +impl AsRef<[u8; 64]> for Signature { + fn as_ref(&self) -> &[u8; 64] { + &self.0 + } +} + +impl AsRef<[u8]> for Signature { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl AsMut<[u8]> for Signature { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0[..] + } +} + +#[cfg(feature = "std")] +impl From for Signature { + fn from(s: schnorrkel::Signature) -> Signature { + Signature(s.to_bytes()) + } +} + +#[cfg(feature = "std")] +impl ::std::fmt::Debug for Signature { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0)) + } +} + +#[cfg(feature = "std")] +impl ::std::hash::Hash for Signature { + fn hash(&self, state: &mut H) { + ::std::hash::Hash::hash(&self.0[..], state); + } +} /// A localized signature also contains sender information. /// NOTE: Encode and Decode traits are supported in ed25519 but not possible for now here. +#[cfg(feature = "std")] #[derive(PartialEq, Eq, Clone, Debug)] pub struct LocalizedSignature { /// The signer of the signature. @@ -45,64 +228,80 @@ pub struct LocalizedSignature { pub signature: Signature, } -/// A public key. -#[derive(PartialEq, Eq, Clone, Encode, Decode)] -pub struct Public(pub [u8; 32]); +impl Signature { + /// A new instance from the given 64-byte `data`. + /// + /// NOTE: No checking goes on to ensure this is a real signature. Only use it if + /// you are certain that the array actually is a signature. GIGO! + pub fn from_raw(data: [u8; 64]) -> Signature { + Signature(data) + } -/// A schnorrkel key pair. -pub struct Pair(Keypair); + /// A new instance from the given slice that should be 64 bytes long. + /// + /// NOTE: No checking goes on to ensure this is a real signature. Only use it if + /// you are certain that the array actually is a signature. GIGO! + pub fn from_slice(data: &[u8]) -> Self { + let mut r = [0u8; 64]; + r.copy_from_slice(data); + Signature(r) + } -impl ::std::hash::Hash for Public { - fn hash(&self, state: &mut H) { - self.0.hash(state); + /// A new instance from an H512. + /// + /// NOTE: No checking goes on to ensure this is a real signature. Only use it if + /// you are certain that the array actually is a signature. GIGO! + pub fn from_h512(v: H512) -> Signature { + Signature(v.into()) } } -/// An error type for SS58 decoding. -#[derive(Clone, Copy, Eq, PartialEq, Debug)] -pub enum PublicError { - /// Bad alphabet. - BadBase58, - /// Bad length. - BadLength, - /// Unknown version. - UnknownVersion, - /// Invalid checksum. - InvalidChecksum, +#[cfg(feature = "std")] +impl Derive for Public { + /// Derive a child key from a series of given junctions. + /// + /// `None` if there are any hard junctions in there. + fn derive>(&self, path: Iter) -> Option { + let mut acc = PublicKey::from_bytes(self.as_ref()).ok()?; + for j in path { + match j { + DeriveJunction::Soft(cc) => acc = acc.derived_key_simple(ChainCode(cc), &[]).0, + DeriveJunction::Hard(_cc) => return None, + } + } + Some(Self(acc.to_bytes())) + } } impl Public { /// A new instance from the given 32-byte `data`. + /// + /// 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_raw(data: [u8; 32]) -> Self { Public(data) } /// 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_slice(data: &[u8]) -> Self { let mut r = [0u8; 32]; r.copy_from_slice(data); Public(r) } - /// Some if the string is a properly encoded SS58Check address. - pub fn from_ss58check(s: &str) -> Result { - let d = s.from_base58().map_err(|_| PublicError::BadBase58)?; // failure here would be invalid encoding. - if d.len() != 35 { - // Invalid length. - return Err(PublicError::BadLength); - } - if d[0] != 42 { - // Invalid version. - return Err(PublicError::UnknownVersion); - } - if d[33..35] != blake2_rfc::blake2b::blake2b(64, &[], &d[0..33]).as_bytes()[0..2] { - // Invalid checksum. - return Err(PublicError::InvalidChecksum); - } - Ok(Self::from_slice(&d[1..33])) + /// 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_h256(x: H256) -> Self { + Public(x.into()) } /// Return a `Vec` filled with raw data. + #[cfg(feature = "std")] pub fn to_raw_vec(self) -> Vec { let r: &[u8; 32] = self.as_ref(); r.to_vec() @@ -118,165 +317,272 @@ impl Public { pub fn as_array_ref(&self) -> &[u8; 32] { self.as_ref() } - - /// Return the ss58-check string for this key. - pub fn to_ss58check(&self) -> String { - let mut v = vec![42u8]; - v.extend(self.as_slice()); - let r = blake2_rfc::blake2b::blake2b(64, &[], &v); - v.extend(&r.as_bytes()[0..2]); - v.to_base58() - } } -impl AsRef<[u8; 32]> for Public { - fn as_ref(&self) -> &[u8; 32] { - &self.0 +#[cfg(feature = "std")] +impl AsRef for Pair { + fn as_ref(&self) -> &Pair { + &self } } -impl AsRef<[u8]> for Public { - fn as_ref(&self) -> &[u8] { - &self.0[..] +#[cfg(feature = "std")] +impl From for Pair { + fn from(sec: MiniSecretKey) -> Pair { + Pair(sec.expand_to_keypair()) } } -impl Into<[u8; 32]> for Public { - fn into(self) -> [u8; 32] { - self.0 +#[cfg(feature = "std")] +impl From for Pair { + fn from(sec: SecretKey) -> Pair { + Pair(Keypair::from(sec)) } } -impl AsRef for Public { - fn as_ref(&self) -> &Public { - &self +#[cfg(feature = "std")] +impl From for Pair { + fn from(p: schnorrkel::Keypair) -> Pair { + Pair(p) } } -impl AsRef for Pair { - fn as_ref(&self) -> &Pair { - &self +#[cfg(feature = "std")] +impl From for schnorrkel::Keypair { + fn from(p: Pair) -> schnorrkel::Keypair { + p.0 } } -impl ::std::fmt::Display for Public { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "{}", self.to_ss58check()) +#[cfg(feature = "std")] +impl AsRef for Pair { + fn as_ref(&self) -> &schnorrkel::Keypair { + &self.0 } } -impl ::std::fmt::Debug for Public { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - let s = self.to_ss58check(); - write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8]) - } +/// Derive a single hard junction. +#[cfg(feature = "std")] +fn derive_hard_junction(secret: &SecretKey, cc: &[u8; CHAIN_CODE_LENGTH]) -> SecretKey { + secret.hard_derive_mini_secret_key(Some(ChainCode(cc.clone())), b"").0.expand() } -impl Pair { +#[cfg(feature = "std")] +type Seed = [u8; MINI_SECRET_KEY_LENGTH]; + +#[cfg(feature = "std")] +impl TraitPair for Pair { + type Public = Public; + type Seed = Seed; + type Signature = Signature; + type DeriveError = Infallible; + /// Generate new secure (random) key pair. - pub fn generate() -> Pair { + fn generate() -> Pair { let mut csprng: OsRng = OsRng::new().expect("os random generator works; qed"); - let keypair: Keypair = Keypair::generate(&mut csprng); - Pair(keypair) + let key_pair: Keypair = Keypair::generate(&mut csprng); + Pair(key_pair) } - /// Make a new key pair from a seed phrase. + /// Make a new key pair from raw secret seed material. + /// /// This is generated using schnorrkel's Mini-Secret-Keys. + /// /// A MiniSecretKey is literally what Ed25519 calls a SecretKey, which is just 32 random bytes. - pub fn from_seed(seed: &[u8; 32]) -> Pair { - let mini_key: MiniSecretKey = MiniSecretKey::from_bytes(seed) + fn from_seed(seed: Seed) -> Pair { + let mini_key: MiniSecretKey = MiniSecretKey::from_bytes(&seed[..]) .expect("32 bytes can always build a key; qed"); - let kp = mini_key.expand_to_keypair::(); + let kp = mini_key.expand_to_keypair(); Pair(kp) } - /// Sign a message. - pub fn sign(&self, message: &[u8]) -> Signature { - let context = signing_context(SIGNING_CTX); - Signature::from(self.0.sign(context.bytes(message)).to_bytes()) - } - /// Get the public key. - pub fn public(&self) -> Public { + fn public(&self) -> Public { let mut pk = [0u8; 32]; pk.copy_from_slice(&self.0.public.to_bytes()); Public(pk) } -} -/// Verify a signature on a message. Returns true if the signature is good. -pub fn verify_strong>(sig: &Signature, message: &[u8], pubkey: P) -> bool { - let signature: schnorrkel::Signature = match schnorrkel::Signature::from_bytes(&sig[..]) { - Ok(some_signature) => some_signature, - Err(_) => return false - }; - match PublicKey::from_bytes(pubkey.as_ref().as_slice()) { - Ok(pk) => pk.verify(signing_context(SIGNING_CTX).bytes(message), &signature), - Err(_) => false, + /// Make a new key pair from secret seed material. The slice must be 32 bytes long or it + /// will return `None`. + /// + /// 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() + )) + } } -} -/// Verify a message without type checking the parameters' types for the right size. -/// Returns true if both the pubkey and the signature is good. -pub fn verify>(sig: &[u8], message: &[u8], pubkey: P) -> bool { - let signature = match schnorrkel::Signature::from_bytes(&sig[..]) { - Ok(sig) => sig, - Err(_) => return false, - }; - match PublicKey::from_bytes(pubkey.as_ref()) { - Ok(pk) => pk.verify_simple(SIGNING_CTX, message, &signature), - Err(_) => false, + /// Generate a key from the phrase, password and derivation path. + fn from_standard_components>(phrase: &str, password: Option<&str>, path: I) -> Result { + Self::from_phrase(phrase, password)? + .derive(path) + .map_err(|_| SecretStringError::InvalidPath) } -} -/// Something that acts as a signature allowing a message to be verified. -pub trait Verifiable { - /// Verify something that acts like a signature. - fn verify>(&self, message: &[u8], pubkey: P) -> bool; -} + fn generate_with_phrase(password: Option<&str>) -> (Pair, String) { + let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English); + let phrase = mnemonic.phrase(); + ( + Self::from_phrase(phrase, password).expect("All phrases generated by Mnemonic are valid; qed"), + phrase.to_owned(), + ) + } -impl Verifiable for Signature { - /// Verify something that acts like a signature. - fn verify>(&self, message: &[u8], pubkey: P) -> bool { - verify_strong(&self, message, pubkey) + fn from_phrase(phrase: &str, password: Option<&str>) -> Result { + Mnemonic::from_phrase(phrase, Language::English) + .map_err(|_| SecretStringError::InvalidPhrase) + .map(|m| Self::from_entropy(m.entropy(), password)) } -} -impl Verifiable for LocalizedSignature { - fn verify>(&self, message: &[u8], pubkey: P) -> bool { - pubkey.as_ref() == &self.signer && self.signature.verify(message, pubkey) + fn derive>(&self, path: Iter) -> Result { + let init = self.0.secret.clone(); + let result = path.fold(init, |acc, j| match j { + DeriveJunction::Soft(cc) => acc.derived_key_simple(ChainCode(cc), &[]).0, + DeriveJunction::Hard(cc) => derive_hard_junction(&acc, &cc), + }); + Ok(Self(result.into())) } -} -/// Deserialize from `ss58` into something that can be constructed from `[u8; 32]`. -#[cfg(feature = "std")] -pub fn deserialize<'de, D, T: From<[u8; 32]>>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let ss58 = String::deserialize(deserializer)?; - Public::from_ss58check(&ss58) - .map_err(|e| de::Error::custom(format!("{:?}", e))) - .map(|v| v.0.into()) + fn sign(&self, message: &[u8]) -> Signature { + let context = signing_context(SIGNING_CTX); + self.0.sign(context.bytes(message)).into() + } + + /// Verify a signature on a message. Returns true if the signature is good. + fn verify, M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: P) -> bool { + let signature: schnorrkel::Signature = match schnorrkel::Signature::from_bytes(&sig.as_ref()) { + Ok(some_signature) => some_signature, + Err(_) => return false + }; + match PublicKey::from_bytes(pubkey.as_ref().as_slice()) { + Ok(pk) => pk.verify( + signing_context(SIGNING_CTX).bytes(message.as_ref()), &signature + ), + Err(_) => false, + } + } + + /// Verify a signature on a message. Returns true if the signature is good. + fn verify_weak, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool { + let signature: schnorrkel::Signature = match schnorrkel::Signature::from_bytes(sig) { + Ok(some_signature) => some_signature, + Err(_) => return false + }; + match PublicKey::from_bytes(pubkey.as_ref()) { + Ok(pk) => pk.verify( + signing_context(SIGNING_CTX).bytes(message.as_ref()), &signature + ), + Err(_) => false, + } + } } -/// Serializes something that implements `AsRef<[u8; 32]>` into `ss58`. #[cfg(feature = "std")] -pub fn serialize>(data: &T, serializer: S) -> Result -where - S: Serializer, -{ - serializer.serialize_str(&Public(*data.as_ref()).to_ss58check()) +impl Pair { + /// Make a new key pair from binary data derived from a valid seed phrase. + /// + /// This uses a key derivation function to convert the entropy into a seed, then returns + /// the pair generated from it. + pub fn from_entropy(entropy: &[u8], password: Option<&str>) -> Pair { + let mini_key: MiniSecretKey = mini_secret_from_entropy(entropy, password.unwrap_or("")) + .expect("32 bytes can always build a key; qed"); + let kp = mini_key.expand_to_keypair(); + Pair(kp) + } } #[cfg(test)] mod test { use super::*; + use crate::crypto::{Ss58Codec, DEV_PHRASE, DEV_ADDRESS}; use hex_literal::{hex, hex_impl}; + #[test] + fn default_phrase_should_be_used() { + assert_eq!( + Pair::from_string("//Alice///password", None).unwrap().public(), + Pair::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password")).unwrap().public(), + ); + assert_eq!( + Pair::from_string(&format!("{}/Alice", DEV_PHRASE), None).as_ref().map(Pair::public), + Pair::from_string("/Alice", None).as_ref().map(Pair::public) + ); + } + + #[test] + fn default_address_should_be_used() { + assert_eq!( + Public::from_string(&format!("{}/Alice", DEV_ADDRESS)), + Public::from_string("/Alice") + ); + } + + #[test] + fn default_phrase_should_correspond_to_default_address() { + assert_eq!( + Pair::from_string(&format!("{}/Alice", DEV_PHRASE), None).unwrap().public(), + Public::from_string(&format!("{}/Alice", DEV_ADDRESS)).unwrap(), + ); + assert_eq!( + Pair::from_string("/Alice", None).unwrap().public(), + Public::from_string("/Alice").unwrap() + ); + } + + #[test] + fn derive_soft_should_work() { + let pair: Pair = Pair::from_seed(hex!( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + )); + let derive_1 = pair.derive(Some(DeriveJunction::soft(1)).into_iter()).unwrap(); + let derive_1b = pair.derive(Some(DeriveJunction::soft(1)).into_iter()).unwrap(); + let derive_2 = pair.derive(Some(DeriveJunction::soft(2)).into_iter()).unwrap(); + assert_eq!(derive_1.public(), derive_1b.public()); + assert_ne!(derive_1.public(), derive_2.public()); + } + + #[test] + fn derive_hard_should_work() { + let pair: Pair = Pair::from_seed(hex!( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + )); + let derive_1 = pair.derive(Some(DeriveJunction::hard(1)).into_iter()).unwrap(); + let derive_1b = pair.derive(Some(DeriveJunction::hard(1)).into_iter()).unwrap(); + let derive_2 = pair.derive(Some(DeriveJunction::hard(2)).into_iter()).unwrap(); + assert_eq!(derive_1.public(), derive_1b.public()); + assert_ne!(derive_1.public(), derive_2.public()); + } + + #[test] + fn derive_soft_public_should_work() { + let pair: Pair = Pair::from_seed(hex!( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + )); + let path = Some(DeriveJunction::soft(1)); + let pair_1 = pair.derive(path.clone().into_iter()).unwrap(); + let public_1 = pair.public().derive(path.into_iter()).unwrap(); + assert_eq!(pair_1.public(), public_1); + } + + #[test] + fn derive_hard_public_should_fail() { + let pair: Pair = Pair::from_seed(hex!( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + )); + let path = Some(DeriveJunction::hard(1)); + assert!(pair.public().derive(path.into_iter()).is_none()); + } + #[test] fn sr_test_vector_should_work() { - let pair: Pair = Pair::from_seed(&hex!( + let pair: Pair = Pair::from_seed(hex!( "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" )); let public = pair.public(); @@ -288,8 +594,7 @@ mod test { ); let message = b""; let signature = pair.sign(message); - assert!(verify(&signature[..], message, &public.0)); - assert!(verify_strong(&signature, &message[..], &public)); + assert!(Pair::verify(&signature, &message[..], &public)); } #[test] @@ -298,13 +603,13 @@ mod test { let public = pair.public(); let message = b"Something important"; let signature = pair.sign(&message[..]); - assert!(verify_strong(&signature, &message[..], &public)); + assert!(Pair::verify(&signature, &message[..], &public)); } #[test] fn seeded_pair_should_work() { - let pair = Pair::from_seed(b"12345678901234567890123456789012"); + let pair = Pair::from_seed(*b"12345678901234567890123456789012"); let public = pair.public(); assert_eq!( public, @@ -314,7 +619,7 @@ mod test { ); let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"); let signature = pair.sign(&message[..]); - assert!(verify_strong(&signature, &message[..], &public)); + assert!(Pair::verify(&signature, &message[..], &public)); } #[test] @@ -333,4 +638,15 @@ mod test { let enc = hex!["090fa15cb5b1666222fff584b4cc2b1761fe1e238346b340491b37e25ea183ff"]; assert_eq!(Public::from_ss58check(k).unwrap(), Public::from_raw(enc)); } + + #[test] + fn verify_from_wasm_works() { + // The values in this test case are compared to the output of `node-test.js` in schnorrkel-js. + // + // This is to make sure that the wasm library is compatible. + let pk = Pair::from_seed(hex!("0000000000000000000000000000000000000000000000000000000000000000")); + let public = pk.public(); + let js_signature = Signature::from_raw(hex!("28a854d54903e056f89581c691c1f7d2ff39f8f896c9e9c22475e60902cc2b3547199e0e91fa32902028f2ca2355e8cdd16cfe19ba5e8b658c94aa80f3b81a00")); + assert!(Pair::verify(&js_signature, b"SUBSTRATE", public)); + } } diff --git a/core/primitives/src/storage.rs b/core/primitives/src/storage.rs index 36639fd88214fad32cace166c8e67f5ad30d14b3..79652a8d4ce3a211ac3490e57ebe4fa27164aabf 100644 --- a/core/primitives/src/storage.rs +++ b/core/primitives/src/storage.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/primitives/src/tests.rs b/core/primitives/src/tests.rs index 2205e4ac7ac808ee1226f3cd040966068e42ec49..2dbaed2b0faabdf2910f4b91f8b626dc5220c542 100644 --- a/core/primitives/src/tests.rs +++ b/core/primitives/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/primitives/src/u32_trait.rs b/core/primitives/src/u32_trait.rs index 88ee6bf29b277a88c264871dbeb1bad8ce85970d..3fcdceac4cbbfacea532c498648ccee980a0e36c 100644 --- a/core/primitives/src/u32_trait.rs +++ b/core/primitives/src/u32_trait.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/primitives/src/uint.rs b/core/primitives/src/uint.rs index 866d21c8a30c0056af874b199b480a3b773c18d8..dfea51921dc331ef5936fac83746da014fa0b5b1 100644 --- a/core/primitives/src/uint.rs +++ b/core/primitives/src/uint.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/rpc-servers/src/lib.rs b/core/rpc-servers/src/lib.rs index 7497fa39060bdc45ba31e573dcf31e936cc917e4..939b2b93aa58abd511d665a50162b252d76cad0e 100644 --- a/core/rpc-servers/src/lib.rs +++ b/core/rpc-servers/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/rpc/Cargo.toml b/core/rpc/Cargo.toml index 7048fc804d9c6205f29acf6c4feb80b6af813538..8998ebe81f5e4b08217838a3e090f0c0e040a1ae 100644 --- a/core/rpc/Cargo.toml +++ b/core/rpc/Cargo.toml @@ -11,7 +11,7 @@ jsonrpc-pubsub = "10.0.1" jsonrpc-derive = "10.0.2" log = "0.4" parking_lot = "0.7.1" -parity-codec = "3.0" +parity-codec = "3.2" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" @@ -27,7 +27,10 @@ tokio = "0.1.7" [dev-dependencies] assert_matches = "1.1" +futures = "0.1.17" +sr-io = { path = "../sr-io" } test_client = { package = "substrate-test-client", path = "../test-client" } +test_runtime = { package = "substrate-test-runtime", path = "../test-runtime" } consensus = { package = "substrate-consensus-common", path = "../consensus/common" } rustc-hex = "2.0" hex-literal = "0.1" diff --git a/core/rpc/src/author/error.rs b/core/rpc/src/author/error.rs index 5024aba5fff8ef6dcc9b3884c6b433a732bc4221..9c1ec232252001e10640e655f091cd970417559b 100644 --- a/core/rpc/src/author/error.rs +++ b/core/rpc/src/author/error.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -47,22 +47,77 @@ error_chain! { } } -const ERROR: i64 = 1000; +/// Base code for all authorship errors. +const BASE_ERROR: i64 = 1000; +/// Extrinsic has an invalid format. +const BAD_FORMAT: i64 = BASE_ERROR + 1; +/// Error during transaction verification in runtime. +const VERIFICATION_ERROR: i64 = BASE_ERROR + 2; + +/// Pool rejected the transaction as invalid +const POOL_INVALID_TX: i64 = BASE_ERROR + 10; +/// Cannot determine transaction validity. +const POOL_UNKNOWN_VALIDITY: i64 = POOL_INVALID_TX + 1; +/// The transaction is temporarily banned. +const POOL_TEMPORARILY_BANNED: i64 = POOL_INVALID_TX + 2; +/// The transaction is already in the pool +const POOL_ALREADY_IMPORTED: i64 = POOL_INVALID_TX + 3; +/// Transaction has too low priority to replace existing one in the pool. +const POOL_TOO_LOW_PRIORITY: i64 = POOL_INVALID_TX + 4; +/// Including this transaction would cause a dependency cycle. +const POOL_CYCLE_DETECTED: i64 = POOL_INVALID_TX + 5; +/// The transaction was not included to the pool because of the limits. +const POOL_IMMEDIATELY_DROPPED: i64 = POOL_INVALID_TX + 6; impl From for rpc::Error { fn from(e: Error) -> Self { match e { Error(ErrorKind::Unimplemented, _) => errors::unimplemented(), Error(ErrorKind::BadFormat, _) => rpc::Error { - code: rpc::ErrorCode::ServerError(ERROR + 1), + code: rpc::ErrorCode::ServerError(BAD_FORMAT), message: "Extrinsic has invalid format.".into(), data: None, }, Error(ErrorKind::Verification(e), _) => rpc::Error { - code: rpc::ErrorCode::ServerError(ERROR + 2), + code: rpc::ErrorCode::ServerError(VERIFICATION_ERROR), message: e.description().into(), data: Some(format!("{:?}", e).into()), }, + Error(ErrorKind::Pool(txpool::error::ErrorKind::InvalidTransaction(code)), _) => rpc::Error { + code: rpc::ErrorCode::ServerError(POOL_INVALID_TX), + message: "Invalid Transaction".into(), + data: Some(code.into()), + }, + Error(ErrorKind::Pool(txpool::error::ErrorKind::UnknownTransactionValidity(code)), _) => rpc::Error { + code: rpc::ErrorCode::ServerError(POOL_UNKNOWN_VALIDITY), + message: "Unknown Transaction Validity".into(), + data: Some(code.into()), + }, + Error(ErrorKind::Pool(txpool::error::ErrorKind::TemporarilyBanned), _) => rpc::Error { + code: rpc::ErrorCode::ServerError(POOL_TEMPORARILY_BANNED), + message: "Transaction is temporarily banned".into(), + data: None, + }, + Error(ErrorKind::Pool(txpool::error::ErrorKind::AlreadyImported(hash)), _) => rpc::Error { + code: rpc::ErrorCode::ServerError(POOL_ALREADY_IMPORTED), + message: "Transaction Already Imported".into(), + data: Some(format!("{:?}", hash).into()), + }, + Error(ErrorKind::Pool(txpool::error::ErrorKind::TooLowPriority(old, new)), _) => rpc::Error { + code: rpc::ErrorCode::ServerError(POOL_TOO_LOW_PRIORITY), + message: format!("Priority is too low: ({} vs {})", old, new), + data: Some("The transaction has too low priority to replace another transaction already in the pool.".into()), + }, + Error(ErrorKind::Pool(txpool::error::ErrorKind::CycleDetected), _) => rpc::Error { + code: rpc::ErrorCode::ServerError(POOL_CYCLE_DETECTED), + message: "Cycle Detected".into(), + data: None, + }, + Error(ErrorKind::Pool(txpool::error::ErrorKind::ImmediatelyDropped), _) => rpc::Error { + code: rpc::ErrorCode::ServerError(POOL_IMMEDIATELY_DROPPED), + message: "Immediately Dropped" .into(), + data: Some("The transaction couldn't enter the pool because of the limit".into()), + }, e => errors::internal(e), } } diff --git a/core/rpc/src/author/mod.rs b/core/rpc/src/author/mod.rs index e9e527f9cbef1fde2fd57d9dd3e9df75cc28c9e0..acd500ba0bfe309ddec5c36c698f0cb5a71473e0 100644 --- a/core/rpc/src/author/mod.rs +++ b/core/rpc/src/author/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/rpc/src/author/tests.rs b/core/rpc/src/author/tests.rs index b71a20f38de9a856d98c778027b203584599af1c..53166e76f82ea01f48395472b47e48c5d49c79a0 100644 --- a/core/rpc/src/author/tests.rs +++ b/core/rpc/src/author/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -17,27 +17,24 @@ use super::*; use std::sync::Arc; -use hex_literal::{hex, hex_impl}; use assert_matches::assert_matches; use parity_codec::Encode; use transaction_pool::{ txpool::Pool, ChainApi, }; -use primitives::H256; -use test_client::keyring::Keyring; -use test_client::runtime::{Extrinsic, Transfer}; -use test_client; +use primitives::{H256, blake2_256, hexdisplay::HexDisplay}; +use test_client::{self, AccountKeyring, runtime::{Extrinsic, Transfer}}; use tokio::runtime; -fn uxt(sender: Keyring, nonce: u64) -> Extrinsic { +fn uxt(sender: AccountKeyring, nonce: u64) -> Extrinsic { let tx = Transfer { amount: Default::default(), nonce, - from: sender.to_raw_public().into(), + from: sender.into(), to: Default::default(), }; - let signature = Keyring::from_raw_public(tx.from.to_fixed_bytes()).unwrap().sign(&tx.encode()).into(); + let signature = AccountKeyring::from_public(&tx.from).unwrap().sign(&tx.encode()).into(); Extrinsic::Transfer(tx, signature) } @@ -50,14 +47,15 @@ fn submit_transaction_should_not_cause_error() { pool: Arc::new(Pool::new(Default::default(), ChainApi::new(client))), subscriptions: Subscriptions::new(runtime.executor()), }; - let h: H256 = hex!("81897a4890fb7554e7f77c533a865846a11583a56a8ad5e307543188d55e64f1").into(); + let xt = uxt(AccountKeyring::Alice, 1).encode(); + let h: H256 = blake2_256(&xt).into(); assert_matches!( - AuthorApi::submit_extrinsic(&p, uxt(Keyring::Alice, 1).encode().into()), + AuthorApi::submit_extrinsic(&p, xt.clone().into()), Ok(h2) if h == h2 ); assert!( - AuthorApi::submit_extrinsic(&p, uxt(Keyring::Alice, 1).encode().into()).is_err() + AuthorApi::submit_extrinsic(&p, xt.into()).is_err() ); } @@ -70,14 +68,15 @@ fn submit_rich_transaction_should_not_cause_error() { pool: Arc::new(Pool::new(Default::default(), ChainApi::new(client.clone()))), subscriptions: Subscriptions::new(runtime.executor()), }; - let h: H256 = hex!("9ec8469b5dcfe29cc274ac1d07ad73d80be57566ace0fcdbe51ebcf4b51e925b").into(); + let xt = uxt(AccountKeyring::Alice, 0).encode(); + let h: H256 = blake2_256(&xt).into(); assert_matches!( - AuthorApi::submit_extrinsic(&p, uxt(Keyring::Alice, 0).encode().into()), + AuthorApi::submit_extrinsic(&p, xt.clone().into()), Ok(h2) if h == h2 ); assert!( - AuthorApi::submit_extrinsic(&p, uxt(Keyring::Alice, 0).encode().into()).is_err() + AuthorApi::submit_extrinsic(&p, xt.into()).is_err() ); } @@ -95,7 +94,7 @@ fn should_watch_extrinsic() { let (subscriber, id_rx, data) = ::jsonrpc_pubsub::typed::Subscriber::new_test("test"); // when - p.watch_extrinsic(Default::default(), subscriber, uxt(Keyring::Alice, 0).encode().into()); + p.watch_extrinsic(Default::default(), subscriber, uxt(AccountKeyring::Alice, 0).encode().into()); // then assert_eq!(runtime.block_on(id_rx), Ok(Ok(1.into()))); @@ -104,10 +103,10 @@ fn should_watch_extrinsic() { let tx = Transfer { amount: 5, nonce: 0, - from: Keyring::Alice.to_raw_public().into(), + from: AccountKeyring::Alice.into(), to: Default::default(), }; - let signature = Keyring::from_raw_public(tx.from.to_fixed_bytes()).unwrap().sign(&tx.encode()).into(); + let signature = AccountKeyring::from_public(&tx.from).unwrap().sign(&tx.encode()).into(); Extrinsic::Transfer(tx, signature) }; AuthorApi::submit_extrinsic(&p, replacement.encode().into()).unwrap(); @@ -116,9 +115,10 @@ fn should_watch_extrinsic() { res, Some(r#"{"jsonrpc":"2.0","method":"test","params":{"result":"ready","subscription":1}}"#.into()) ); + let h = blake2_256(&replacement.encode()); assert_eq!( runtime.block_on(data.into_future()).unwrap().0, - Some(r#"{"jsonrpc":"2.0","method":"test","params":{"result":{"usurped":"0x53daed816610aa6b22dedbcee43aba44a7ca7155cc71f2919c5e79ebbc7de58c"},"subscription":1}}"#.into()) + Some(format!(r#"{{"jsonrpc":"2.0","method":"test","params":{{"result":{{"usurped":"0x{}"}},"subscription":1}}}}"#, HexDisplay::from(&h))) ); } @@ -132,7 +132,7 @@ fn should_return_pending_extrinsics() { pool: pool.clone(), subscriptions: Subscriptions::new(runtime.executor()), }; - let ex = uxt(Keyring::Alice, 0); + let ex = uxt(AccountKeyring::Alice, 0); AuthorApi::submit_extrinsic(&p, ex.encode().into()).unwrap(); assert_matches!( p.pending_extrinsics(), diff --git a/core/rpc/src/chain/error.rs b/core/rpc/src/chain/error.rs index 4fd098ca7214b494007215eab98fb6eb3366cb4e..c52d44eddc3392d6a35fa4ec2dc292cb677b2a58 100644 --- a/core/rpc/src/chain/error.rs +++ b/core/rpc/src/chain/error.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/rpc/src/chain/mod.rs b/core/rpc/src/chain/mod.rs index 885159231b40352c9bea44c73aabf6361edeaa02..9b7f5a909e449098c917cc5485e0fb531dc668c8 100644 --- a/core/rpc/src/chain/mod.rs +++ b/core/rpc/src/chain/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/rpc/src/chain/tests.rs b/core/rpc/src/chain/tests.rs index becc57f2a9e1c4378e43ad9b327b5cf958e5e0e2..bad3c5aeb8735de4196507711de2550577703175 100644 --- a/core/rpc/src/chain/tests.rs +++ b/core/rpc/src/chain/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/rpc/src/errors.rs b/core/rpc/src/errors.rs index 9a4928440d64a0f53641e9487ddac79effc8094e..a709013ad26801a471f7dd99d94c6ed10390b78b 100644 --- a/core/rpc/src/errors.rs +++ b/core/rpc/src/errors.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/rpc/src/helpers.rs b/core/rpc/src/helpers.rs index b9c665191d92833c71e42c7c160a13e964510e30..e579c743acdad202caedfd39e760559129c6109f 100644 --- a/core/rpc/src/helpers.rs +++ b/core/rpc/src/helpers.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/rpc/src/lib.rs b/core/rpc/src/lib.rs index d9e9b18146260c73004bcbf528b0d9beaebb9c9f..6488ea5f49c54120f5a77dbd1c23e8e16004b3d9 100644 --- a/core/rpc/src/lib.rs +++ b/core/rpc/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/rpc/src/metadata.rs b/core/rpc/src/metadata.rs index 728abe1de7269302eee29aeda233f006f6c94128..e6af4ef94bc1adf6fee90eb520630da09ed18942 100644 --- a/core/rpc/src/metadata.rs +++ b/core/rpc/src/metadata.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/rpc/src/state/error.rs b/core/rpc/src/state/error.rs index 6cbe7eba9664bbbd2df1af4317df7d3fbab1e31b..bd85664099a5bbed55a79884c764b7e37e255c2a 100644 --- a/core/rpc/src/state/error.rs +++ b/core/rpc/src/state/error.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/rpc/src/state/mod.rs b/core/rpc/src/state/mod.rs index 4e51151e509107fe5fe0b135145ba231b85e69ba..168c0bd692732dbc564f04a511f11d0f288da3ec 100644 --- a/core/rpc/src/state/mod.rs +++ b/core/rpc/src/state/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -35,7 +35,7 @@ use crate::rpc::futures::{stream, Future, Sink, Stream}; use runtime_primitives::generic::BlockId; use runtime_primitives::traits::{Block as BlockT, Header, ProvideRuntimeApi, As, NumberFor}; use runtime_version::RuntimeVersion; -use state_machine::ExecutionStrategy; +use state_machine::{self, ExecutionStrategy}; use crate::subscriptions::Subscriptions; @@ -298,7 +298,7 @@ impl StateApi for State where .executor() .call( &BlockId::Hash(block), - &method, &data.0, ExecutionStrategy::NativeElseWasm + &method, &data.0, ExecutionStrategy::NativeElseWasm, state_machine::NeverOffchainExt::new(), )?; Ok(Bytes(return_data)) } diff --git a/core/rpc/src/state/tests.rs b/core/rpc/src/state/tests.rs index 354ef0ed2825ac834543c32dbaac6377763873d1..f28e63b15d62c3a8479bd22aa3a80f9d5490290b 100644 --- a/core/rpc/src/state/tests.rs +++ b/core/rpc/src/state/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -17,10 +17,10 @@ use super::*; use self::error::{Error, ErrorKind}; +use sr_io::twox_128; use assert_matches::assert_matches; use consensus::BlockOrigin; -use rustc_hex::FromHex; -use test_client::{self, runtime, keyring::Keyring, TestClient, BlockBuilderExt}; +use test_client::{self, runtime, AccountKeyring, TestClient, BlockBuilderExt}; #[test] fn should_return_storage() { @@ -64,8 +64,8 @@ fn should_notify_about_storage_changes() { let mut builder = api.client.new_block().unwrap(); builder.push_transfer(runtime::Transfer { - from: Keyring::Alice.to_raw_public().into(), - to: Keyring::Ferdie.to_raw_public().into(), + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), amount: 42, nonce: 0, }).unwrap(); @@ -88,8 +88,10 @@ fn should_send_initial_storage_changes_and_notifications() { { let api = State::new(Arc::new(test_client::new()), Subscriptions::new(remote)); + let alice_balance_key = twox_128(&test_runtime::system::balance_of_key(AccountKeyring::Alice.into())); + api.subscribe_storage(Default::default(), subscriber, Some(vec![ - StorageKey("a52da2b7c269da1366b3ed1cdb7299ce".from_hex().unwrap()), + StorageKey(alice_balance_key.to_vec()), ]).into()); // assert id assigned @@ -97,8 +99,8 @@ fn should_send_initial_storage_changes_and_notifications() { let mut builder = api.client.new_block().unwrap(); builder.push_transfer(runtime::Transfer { - from: Keyring::Alice.to_raw_public().into(), - to: Keyring::Ferdie.to_raw_public().into(), + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), amount: 42, nonce: 0, }).unwrap(); @@ -131,8 +133,8 @@ fn should_query_storage() { let add_block = |nonce| { let mut builder = client.new_block().unwrap(); builder.push_transfer(runtime::Transfer { - from: Keyring::Alice.to_raw_public().into(), - to: Keyring::Ferdie.to_raw_public().into(), + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), amount: 42, nonce, }).unwrap(); @@ -145,13 +147,14 @@ fn should_query_storage() { let block2_hash = add_block(1); let genesis_hash = client.genesis_hash(); + let alice_balance_key = twox_128(&test_runtime::system::balance_of_key(AccountKeyring::Alice.into())); let mut expected = vec![ StorageChangeSet { block: genesis_hash, changes: vec![ ( - StorageKey("a52da2b7c269da1366b3ed1cdb7299ce".from_hex().unwrap()), + StorageKey(alice_balance_key.to_vec()), Some(StorageData(vec![232, 3, 0, 0, 0, 0, 0, 0])) ), ], @@ -160,7 +163,7 @@ fn should_query_storage() { block: block1_hash, changes: vec![ ( - StorageKey("a52da2b7c269da1366b3ed1cdb7299ce".from_hex().unwrap()), + StorageKey(alice_balance_key.to_vec()), Some(StorageData(vec![190, 3, 0, 0, 0, 0, 0, 0])) ), ], @@ -169,7 +172,7 @@ fn should_query_storage() { // Query changes only up to block1 let result = api.query_storage( - vec![StorageKey("a52da2b7c269da1366b3ed1cdb7299ce".from_hex().unwrap())], + vec![StorageKey(alice_balance_key.to_vec())], genesis_hash, Some(block1_hash).into(), ); @@ -178,7 +181,7 @@ fn should_query_storage() { // Query all changes let result = api.query_storage( - vec![StorageKey("a52da2b7c269da1366b3ed1cdb7299ce".from_hex().unwrap())], + vec![StorageKey(alice_balance_key.to_vec())], genesis_hash, None.into(), ); @@ -187,7 +190,7 @@ fn should_query_storage() { block: block2_hash, changes: vec![ ( - StorageKey("a52da2b7c269da1366b3ed1cdb7299ce".from_hex().unwrap()), + StorageKey(alice_balance_key.to_vec()), Some(StorageData(vec![148, 3, 0, 0, 0, 0, 0, 0])) ), ], @@ -218,7 +221,7 @@ fn should_return_runtime_version() { assert_eq!( ::serde_json::to_string(&api.runtime_version(None.into()).unwrap()).unwrap(), - r#"{"specName":"test","implName":"parity-test","authoringVersion":1,"specVersion":1,"implVersion":1,"apis":[["0xdf6acb689907609b",1],["0x37e397fc7c91f5e4",1],["0xd2bc9897eed08f15",1],["0x40fe3ad401f8959a",2],["0xc6e9a76309f39b09",1],["0xdd718d5cc53262d4",1]]}"# + r#"{"specName":"test","implName":"parity-test","authoringVersion":1,"specVersion":1,"implVersion":1,"apis":[["0xdf6acb689907609b",1],["0x37e397fc7c91f5e4",1],["0xd2bc9897eed08f15",1],["0x40fe3ad401f8959a",2],["0xc6e9a76309f39b09",1],["0xdd718d5cc53262d4",1],["0xf78b278be53f454c",1]]}"# ); } diff --git a/core/rpc/src/subscriptions.rs b/core/rpc/src/subscriptions.rs index 5e9f6c5caccfd5587661acac69e9dcab7a19b179..500f3dac4545ccf966cf558f0dc94ccbb6f192de 100644 --- a/core/rpc/src/subscriptions.rs +++ b/core/rpc/src/subscriptions.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/rpc/src/system/error.rs b/core/rpc/src/system/error.rs index 04890b05871f8e7b68c27e4c1ee1bf5d764378a8..d3c7e8b33387048385abcad3e620a615646f0dc5 100644 --- a/core/rpc/src/system/error.rs +++ b/core/rpc/src/system/error.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/rpc/src/system/helpers.rs b/core/rpc/src/system/helpers.rs index ba4d9c8f1671d2ab55da0c262899fd5817278134..9f64318d5db114b94c0dda4ed4e713c528502bfc 100644 --- a/core/rpc/src/system/helpers.rs +++ b/core/rpc/src/system/helpers.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -54,8 +54,6 @@ pub struct Health { #[derive(Debug, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct PeerInfo { - /// Peer Node Index - pub index: usize, /// Peer ID pub peer_id: String, /// Roles @@ -96,14 +94,13 @@ mod tests { fn should_serialize_peer_info() { assert_eq!( ::serde_json::to_string(&PeerInfo { - index: 1, peer_id: "2".into(), roles: "a".into(), protocol_version: 2, best_hash: 5u32, best_number: 6u32, }).unwrap(), - r#"{"index":1,"peerId":"2","roles":"a","protocolVersion":2,"bestHash":5,"bestNumber":6}"#, + r#"{"peerId":"2","roles":"a","protocolVersion":2,"bestHash":5,"bestNumber":6}"#, ); } } diff --git a/core/rpc/src/system/mod.rs b/core/rpc/src/system/mod.rs index e3856fac9fd98fde3bcd0618204b653e0928df0e..331d9cd85ba61739c3833c5ec2497f2cf2331988 100644 --- a/core/rpc/src/system/mod.rs +++ b/core/rpc/src/system/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -60,6 +60,13 @@ pub trait SystemApi { /// Returns currently connected peers #[rpc(name = "system_peers")] fn system_peers(&self) -> Result>>; + + /// Returns current state of the network. + /// + /// **Warning**: This API is not stable. + // TODO: make this stable and move structs https://github.com/paritytech/substrate/issues/1890 + #[rpc(name = "system_networkState")] + fn system_network_state(&self) -> Result; } /// System API implementation @@ -102,22 +109,24 @@ impl SystemApi::Number> for Sy } fn system_health(&self) -> Result { - let status = self.sync.status(); Ok(Health { - peers: status.num_peers, - is_syncing: status.sync.is_major_syncing(), + peers: self.sync.peers().len(), + is_syncing: self.sync.is_major_syncing(), should_have_peers: self.should_have_peers, }) } fn system_peers(&self) -> Result::Number>>> { - Ok(self.sync.peers().into_iter().map(|(idx, peer_id, p)| PeerInfo { - index: idx, - peer_id: peer_id.map_or_else(Default::default, |p| p.to_base58()), + Ok(self.sync.peers().into_iter().map(|(peer_id, p)| 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()) } + + fn system_network_state(&self) -> Result { + Ok(self.sync.network_state()) + } } diff --git a/core/rpc/src/system/tests.rs b/core/rpc/src/system/tests.rs index d28fa202af202f08a9974e5862a5324e2d01c756..b4b71a7937af16e988e6e156a1bdecde1b05ecca 100644 --- a/core/rpc/src/system/tests.rs +++ b/core/rpc/src/system/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -16,38 +16,66 @@ use super::*; -use network::{self, SyncState, SyncStatus, ProtocolStatus, NodeIndex, PeerId, PeerInfo as NetworkPeerInfo, PublicKey}; +use network::{self, ProtocolStatus, PeerId, PeerInfo as NetworkPeerInfo}; use network::config::Roles; use test_client::runtime::Block; use assert_matches::assert_matches; +use futures::sync::mpsc; -#[derive(Default)] struct Status { pub peers: usize, pub is_syncing: bool, pub is_dev: bool, + pub peer_id: PeerId, +} + +impl Default for Status { + fn default() -> Status { + Status { + peer_id: PeerId::random(), + peers: 0, + is_syncing: false, + is_dev: false, + } + } } impl network::SyncProvider for Status { - fn status(&self) -> ProtocolStatus { - ProtocolStatus { - sync: SyncStatus { - state: if self.is_syncing { SyncState::Downloading } else { SyncState::Idle }, - best_seen_block: None, - num_peers: self.peers as u32, - }, - num_peers: self.peers, - num_active_peers: 0, + fn status(&self) -> mpsc::UnboundedReceiver> { + let (_sink, stream) = mpsc::unbounded(); + stream + } + + fn network_state(&self) -> network::NetworkState { + network::NetworkState { + peer_id: String::new(), + listened_addresses: Default::default(), + external_addresses: Default::default(), + connected_peers: Default::default(), + not_connected_peers: Default::default(), + average_download_per_sec: 0, + average_upload_per_sec: 0, + peerset: serde_json::Value::Null, } } - fn peers(&self) -> Vec<(NodeIndex, Option, NetworkPeerInfo)> { - vec![(1, Some(PublicKey::Ed25519((0 .. 32).collect::>()).into()), NetworkPeerInfo { - roles: Roles::FULL, - protocol_version: 1, - best_hash: Default::default(), - best_number: 1 - })] + fn peers(&self) -> Vec<(PeerId, NetworkPeerInfo)> { + let mut peers = vec![]; + for _peer in 0..self.peers { + peers.push( + (self.peer_id.clone(), NetworkPeerInfo { + roles: Roles::FULL, + protocol_version: 1, + best_hash: Default::default(), + best_number: 1 + }) + ); + } + peers + } + + fn is_major_syncing(&self) -> bool { + self.is_syncing } } @@ -108,6 +136,7 @@ fn system_health() { assert_matches!( api(Status { + peer_id: PeerId::random(), peers: 5, is_syncing: true, is_dev: true, @@ -121,6 +150,7 @@ fn system_health() { assert_eq!( api(Status { + peer_id: PeerId::random(), peers: 5, is_syncing: false, is_dev: false, @@ -134,6 +164,7 @@ fn system_health() { assert_eq!( api(Status { + peer_id: PeerId::random(), peers: 0, is_syncing: false, is_dev: true, @@ -148,11 +179,16 @@ fn system_health() { #[test] fn system_peers() { + let peer_id = PeerId::random(); assert_eq!( - api(None).system_peers().unwrap(), + api(Status { + peer_id: peer_id.clone(), + peers: 1, + is_syncing: false, + is_dev: true, + }).system_peers().unwrap(), vec![PeerInfo { - index: 1, - peer_id: "QmS5oyTmdjwBowwAH1D9YQnoe2HyWpVemH8qHiU5RqWPh4".into(), + peer_id: peer_id.to_base58(), roles: "FULL".into(), protocol_version: 1, best_hash: Default::default(), @@ -160,3 +196,20 @@ fn system_peers() { }] ); } + +#[test] +fn system_network_state() { + assert_eq!( + api(None).system_network_state().unwrap(), + network::NetworkState { + peer_id: String::new(), + listened_addresses: Default::default(), + external_addresses: Default::default(), + connected_peers: Default::default(), + not_connected_peers: Default::default(), + average_download_per_sec: 0, + average_upload_per_sec: 0, + peerset: serde_json::Value::Null, + } + ); +} diff --git a/core/serializer/Cargo.toml b/core/serializer/Cargo.toml index d25c8ce0742d2e78ee56f17908cd63b138a2694c..8788f776e5a2842abfb375f3d9023b84a9abbba0 100644 --- a/core/serializer/Cargo.toml +++ b/core/serializer/Cargo.toml @@ -5,5 +5,5 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -serde = { version = "1.0", default-features = false } +serde = "1.0" serde_json = "1.0" diff --git a/core/serializer/src/lib.rs b/core/serializer/src/lib.rs index a357d5ad2b31999106a9632b0158b4fb03ca79e2..2586d49f00599ea919ce635092048a9c0f039dd7 100644 --- a/core/serializer/src/lib.rs +++ b/core/serializer/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/service/Cargo.toml b/core/service/Cargo.toml index 1a9ead67560f2cf32b477d6ab30d0f557499c469..b2f431a5db3361d76b2b68e43945132d7e2e3928 100644 --- a/core/service/Cargo.toml +++ b/core/service/Cargo.toml @@ -17,6 +17,7 @@ serde = "1.0" serde_json = "1.0" serde_derive = "1.0" target_info = "0.1" +inherents = { package = "substrate-inherents", path = "../../core/inherents" } keystore = { package = "substrate-keystore", path = "../../core/keystore" } sr-io = { path = "../../core/sr-io" } runtime_primitives = { package = "sr-primitives", path = "../../core/sr-primitives" } @@ -25,11 +26,12 @@ 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" } -parity-codec = "3.0" +parity-codec = "3.2" substrate-executor = { path = "../../core/executor" } transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" } rpc = { package = "substrate-rpc-servers", path = "../../core/rpc-servers" } tel = { package = "substrate-telemetry", path = "../../core/telemetry" } +offchain = { package = "substrate-offchain", path = "../../core/offchain" } [dev-dependencies] substrate-test-client = { path = "../test-client" } diff --git a/core/service/src/chain_ops.rs b/core/service/src/chain_ops.rs index 487c7ac0a614656f85ece36163eb648945ccde5f..36cbee9039395737edb62df50fa0d54d4a80fac3 100644 --- a/core/service/src/chain_ops.rs +++ b/core/service/src/chain_ops.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/service/src/chain_spec.rs b/core/service/src/chain_spec.rs index 5351bc96fdf22c552c9b795e0a37bbcaa91e077c..78aad64dd0730a708dffe83a619d65c953fc4529 100644 --- a/core/service/src/chain_spec.rs +++ b/core/service/src/chain_spec.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -25,6 +25,7 @@ use runtime_primitives::{BuildStorage, StorageOverlay, ChildrenStorageOverlay}; use serde_json as json; use crate::components::RuntimeGenesis; use network::Multiaddr; +use tel::TelemetryEndpoints; enum GenesisSource { File(PathBuf), @@ -71,6 +72,9 @@ impl<'a, G: RuntimeGenesis> BuildStorage for &'a ChainSpec { Genesis::Raw(map) => Ok((map.into_iter().map(|(k, v)| (k.0, v.0)).collect(), Default::default())), } } + fn assimilate_storage(self, _: &mut StorageOverlay, _: &mut ChildrenStorageOverlay) -> Result<(), String> { + Err("`assimilate_storage` not implemented for `ChainSpec`.".into()) + } } #[derive(Serialize, Deserialize)] @@ -87,7 +91,7 @@ struct ChainSpecFile { pub name: String, pub id: String, pub boot_nodes: Vec, - pub telemetry_url: Option, + pub telemetry_endpoints: Option, pub protocol_id: Option, pub consensus_engine: Option, pub properties: Option, @@ -112,35 +116,43 @@ impl Clone for ChainSpec { } impl ChainSpec { + /// A list of bootnode addresses. pub fn boot_nodes(&self) -> &[String] { &self.spec.boot_nodes } + /// Spec name. pub fn name(&self) -> &str { &self.spec.name } + /// Spec id. pub fn id(&self) -> &str { &self.spec.id } - pub fn telemetry_url(&self) -> Option<&str> { - self.spec.telemetry_url.as_ref().map(String::as_str) + /// Telemetry endpoints (if any) + pub fn telemetry_endpoints(&self) -> &Option { + &self.spec.telemetry_endpoints } + /// Network protocol id. pub fn protocol_id(&self) -> Option<&str> { self.spec.protocol_id.as_ref().map(String::as_str) } + /// Name of the consensus engine. pub fn consensus_engine(&self) -> Option<&str> { self.spec.consensus_engine.as_ref().map(String::as_str) } + /// Additional loosly-typed properties of the chain. pub fn properties(&self) -> Properties { // Return an empty JSON object if 'properties' not defined in config self.spec.properties.as_ref().unwrap_or(&json::map::Map::new()).clone() } + /// Add a bootnode to the list. pub fn add_boot_node(&mut self, addr: Multiaddr) { self.spec.boot_nodes.push(addr.to_string()) } @@ -170,7 +182,7 @@ impl ChainSpec { id: &str, constructor: fn() -> G, boot_nodes: Vec, - telemetry_url: Option<&str>, + telemetry_endpoints: Option, protocol_id: Option<&str>, consensus_engine: Option<&str>, properties: Option, @@ -180,7 +192,7 @@ impl ChainSpec { name: name.to_owned(), id: id.to_owned(), boot_nodes: boot_nodes, - telemetry_url: telemetry_url.map(str::to_owned), + telemetry_endpoints, protocol_id: protocol_id.map(str::to_owned), consensus_engine: consensus_engine.map(str::to_owned), properties, diff --git a/core/service/src/components.rs b/core/service/src/components.rs index 44793c69f26b996620830145836b82b373a30f07..e89921742bca72db875d981f7bb4ec173980aa83 100644 --- a/core/service/src/components.rs +++ b/core/service/src/components.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -21,7 +21,7 @@ use serde::{Serialize, de::DeserializeOwned}; use tokio::runtime::TaskExecutor; use crate::chain_spec::ChainSpec; use client_db; -use client::{self, Client, runtime_api::{Metadata, TaggedTransactionQueue}}; +use client::{self, Client, runtime_api}; use crate::{error, Service, maybe_start_server}; use consensus_common::import_queue::ImportQueue; use network::{self, OnDemand}; @@ -150,7 +150,7 @@ pub trait StartRPC { impl StartRPC for C where ComponentClient: ProvideRuntimeApi, - as ProvideRuntimeApi>::Api: Metadata>, + as ProvideRuntimeApi>::Api: runtime_api::Metadata>, { type ServersHandle = (Option, Option>); @@ -192,14 +192,14 @@ impl StartRPC for C where /// Something that can maintain transaction pool on every imported block. pub trait MaintainTransactionPool { - fn on_block_imported( + fn maintain_transaction_pool( id: &BlockId>, client: &ComponentClient, transaction_pool: &TransactionPool, ) -> error::Result<()>; } -fn on_block_imported( +fn maintain_transaction_pool( id: &BlockId, client: &Client, transaction_pool: &TransactionPool, @@ -207,7 +207,7 @@ fn on_block_imported( Block: BlockT::Out>, Backend: client::backend::Backend, Client: ProvideRuntimeApi, - as ProvideRuntimeApi>::Api: TaggedTransactionQueue, + as ProvideRuntimeApi>::Api: runtime_api::TaggedTransactionQueue, Executor: client::CallExecutor, PoolApi: txpool::ChainApi, { @@ -227,14 +227,35 @@ fn on_block_imported( impl MaintainTransactionPool for C where ComponentClient: ProvideRuntimeApi, - as ProvideRuntimeApi>::Api: TaggedTransactionQueue>, + as ProvideRuntimeApi>::Api: runtime_api::TaggedTransactionQueue>, { - fn on_block_imported( + fn maintain_transaction_pool( id: &BlockId>, client: &ComponentClient, transaction_pool: &TransactionPool, ) -> error::Result<()> { - on_block_imported(id, client, transaction_pool) + maintain_transaction_pool(id, client, transaction_pool) + } +} + +pub trait OffchainWorker { + fn offchain_workers( + number: &FactoryBlockNumber, + offchain: &offchain::OffchainWorkers, ComponentBlock>, + pool: &Arc>, + ) -> error::Result<()>; +} + +impl OffchainWorker for C where + ComponentClient: ProvideRuntimeApi, + as ProvideRuntimeApi>::Api: offchain::OffchainWorkerApi>, +{ + fn offchain_workers( + number: &FactoryBlockNumber, + offchain: &offchain::OffchainWorkers, ComponentBlock>, + pool: &Arc>, + ) -> error::Result<()> { + Ok(offchain.on_block_imported(number, pool)) } } @@ -246,9 +267,16 @@ pub trait ServiceTrait: + 'static + StartRPC + MaintainTransactionPool + + OffchainWorker {} impl ServiceTrait for T where - T: Deref> + Send + Sync + 'static + StartRPC + MaintainTransactionPool + T: Deref> + + Send + + Sync + + 'static + + StartRPC + + MaintainTransactionPool + + OffchainWorker {} /// A collection of types and methods to build a service on top of the substrate service. @@ -338,17 +366,14 @@ pub trait Components: Sized + 'static { type Executor: 'static + client::CallExecutor, Blake2Hasher> + Send + Sync + Clone; /// The type that implements the runtime API. type RuntimeApi: Send + Sync; - /// A type that can start the RPC. - type RPC: StartRPC; + /// A type that can start all runtime-dependent services. + type RuntimeServices: ServiceTrait; // TODO: Traitify transaction pool and allow people to implement their own. (#1242) - /// A type that can maintain transaction pool. - type TransactionPool: MaintainTransactionPool; /// Extrinsic pool type. type TransactionPoolApi: 'static + txpool::ChainApi< Hash = as BlockT>::Hash, Block = FactoryBlock >; - /// Our Import Queue type ImportQueue: ImportQueue> + 'static; @@ -382,6 +407,7 @@ pub struct FullComponents { } impl FullComponents { + /// Create new `FullComponents` pub fn new( config: FactoryFullConfiguration, task_executor: TaskExecutor @@ -416,8 +442,7 @@ impl Components for FullComponents { type TransactionPoolApi = ::FullTransactionPoolApi; type ImportQueue = Factory::FullImportQueue; type RuntimeApi = Factory::RuntimeApi; - type RPC = Factory::FullService; - type TransactionPool = Factory::FullService; + type RuntimeServices = Factory::FullService; fn build_client( config: &FactoryFullConfiguration, @@ -462,6 +487,7 @@ pub struct LightComponents { } impl LightComponents { + /// Create new `LightComponents` pub fn new( config: FactoryFullConfiguration, task_executor: TaskExecutor @@ -490,8 +516,7 @@ impl Components for LightComponents { type TransactionPoolApi = ::LightTransactionPoolApi; type ImportQueue = ::LightImportQueue; type RuntimeApi = Factory::RuntimeApi; - type RPC = Factory::LightService; - type TransactionPool = Factory::LightService; + type RuntimeServices = Factory::LightService; fn build_client( config: &FactoryFullConfiguration, @@ -536,12 +561,7 @@ mod tests { use super::*; use parity_codec::Encode; use consensus_common::BlockOrigin; - use substrate_test_client::{ - self, - TestClient, - keyring::Keyring, - runtime::{Extrinsic, Transfer}, - }; + use substrate_test_client::{self, TestClient, AccountKeyring, runtime::{Extrinsic, Transfer}}; #[test] fn should_remove_transactions_from_the_pool() { @@ -551,10 +571,10 @@ mod tests { let transfer = Transfer { amount: 5, nonce: 0, - from: Keyring::Alice.to_raw_public().into(), + from: AccountKeyring::Alice.into(), to: Default::default(), }; - let signature = Keyring::from_raw_public(transfer.from.to_fixed_bytes()).unwrap().sign(&transfer.encode()).into(); + let signature = AccountKeyring::from_public(&transfer.from).unwrap().sign(&transfer.encode()).into(); Extrinsic::Transfer(transfer, signature) }; // store the transaction in the pool @@ -569,7 +589,7 @@ mod tests { // fire notification - this should clean up the queue assert_eq!(pool.status().ready, 1); - on_block_imported( + maintain_transaction_pool( &id, &client, &pool, diff --git a/core/service/src/config.rs b/core/service/src/config.rs index 84dfe599e2fcc96cb5ad6a084595438c5732ae49..b7a3b8ba141a547f13321e0cc453532a067494df 100644 --- a/core/service/src/config.rs +++ b/core/service/src/config.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -25,6 +25,7 @@ pub use network::config::{NetworkConfiguration, Roles}; use runtime_primitives::BuildStorage; use serde::{Serialize, de::DeserializeOwned}; use target_info::Target; +use tel::TelemetryEndpoints; /// Service configuration. #[derive(Clone)] @@ -64,9 +65,15 @@ pub struct Configuration { /// RPC over Websockets binding address. `None` if disabled. pub rpc_ws: Option, /// Telemetry service URL. `None` if disabled. - pub telemetry_url: Option, + pub telemetry_endpoints: Option, /// The default number of 64KB pages to allocate for Wasm execution pub default_heap_pages: Option, + /// Should offchain workers be executed. + pub offchain_worker: bool, + /// Enable authoring even when offline. + pub force_authoring: bool, + /// Disable GRANDPA when running in validator mode + pub disable_grandpa: bool, } impl Configuration { @@ -90,11 +97,16 @@ impl Configuration { client: Arc>, network: Option>>, transaction_pool: Arc>, + inherents_pool: Arc>>, keystore: Keystore, exit: ::exit_future::Exit, signal: Option, @@ -76,6 +80,7 @@ pub struct Service { pub config: FactoryFullConfiguration, _rpc: Box<::std::any::Any + Send + Sync>, _telemetry: Option>, + _offchain_workers: Option, ComponentBlock>>>, } /// Creates bare client without any networking. @@ -95,9 +100,7 @@ impl Service { pub fn new( mut config: FactoryFullConfiguration, task_executor: TaskExecutor, - ) - -> Result - { + ) -> Result { let (signal, exit) = ::exit_future::signal(); // Create client @@ -128,7 +131,7 @@ impl Service { let version = config.full_version(); info!("Best block: #{}", best_header.number()); - telemetry!("node.start"; "height" => best_header.number().as_(), "best" => ?best_header.hash()); + telemetry!(SUBSTRATE_INFO; "node.start"; "height" => best_header.number().as_(), "best" => ?best_header.hash()); let network_protocol = ::build_network_protocol(&config)?; let transaction_pool = Arc::new( @@ -168,24 +171,48 @@ impl Service { )?; on_demand.map(|on_demand| on_demand.set_network_sender(network_chan)); + let inherents_pool = Arc::new(InherentsPool::default()); + let offchain_workers = if config.offchain_worker { + Some(Arc::new(offchain::OffchainWorkers::new( + client.clone(), + inherents_pool.clone(), + task_executor.clone(), + ))) + } else { + 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 events = client.import_notification_stream() .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::TransactionPool::on_block_imported( + Components::RuntimeServices::maintain_transaction_pool( &BlockId::hash(notification.hash), &*client, &*txpool, ).map_err(|e| warn!("Pool error processing new block: {:?}", e))?; } + + if let (Some(txpool), Some(offchain)) = (txpool.upgrade(), offchain.as_ref().and_then(|o| o.upgrade())) { + Components::RuntimeServices::offchain_workers( + &number, + &offchain, + &txpool, + ).map_err(|e| warn!("Offchain workers error processing new block: {:?}", e))?; + } + Ok(()) }) .select(exit.clone()) @@ -263,13 +290,13 @@ impl Service { impl_version: config.impl_version.into(), properties: config.chain_spec.properties(), }; - let rpc = Components::RPC::start_rpc( + let rpc = Components::RuntimeServices::start_rpc( client.clone(), network.clone(), has_bootnodes, system_info, config.rpc_http, config.rpc_ws, task_executor.clone(), transaction_pool.clone(), )?; // Telemetry - let telemetry = config.telemetry_url.clone().map(|url| { + let telemetry = config.telemetry_endpoints.clone().map(|endpoints| { let is_authority = config.roles == Roles::AUTHORITY; let network_id = network.local_peer_id().to_base58(); let pubkey = format!("{}", public_key); @@ -278,9 +305,9 @@ impl Service { let version = version.clone(); let chain_name = config.chain_spec.name().to_owned(); Arc::new(tel::init_telemetry(tel::TelemetryConfig { - url: url, + endpoints, on_connect: Box::new(move || { - telemetry!("system.connected"; + telemetry!(SUBSTRATE_INFO; "system.connected"; "name" => name.clone(), "implementation" => impl_name.clone(), "version" => version.clone(), @@ -298,12 +325,14 @@ impl Service { client, network: Some(network), transaction_pool, + inherents_pool, signal: Some(signal), keystore, config, exit, _rpc: Box::new(rpc), _telemetry: telemetry, + _offchain_workers: offchain_workers, }) } @@ -320,6 +349,7 @@ impl Service { } } + /// return a shared instance of Telemtry (if enabled) pub fn telemetry(&self) -> Option> { self._telemetry.as_ref().map(|t| t.clone()) } @@ -336,11 +366,16 @@ impl Service where Components: components::Components { self.network.as_ref().expect("self.network always Some").clone() } - /// Get shared extrinsic pool instance. + /// Get shared transaction pool instance. pub fn transaction_pool(&self) -> Arc> { self.transaction_pool.clone() } + /// Get shared inherents pool instance. + pub fn inherents_pool(&self) -> Arc>> { + self.inherents_pool.clone() + } + /// Get shared keystore. pub fn keystore(&self) -> &Keystore { &self.keystore diff --git a/core/service/test/src/lib.rs b/core/service/test/src/lib.rs index 10cac1608ad28c74465dff86d9ceb0575e78cfa7..1735382bb23caf57debe8f47253939794bf41311 100644 --- a/core/service/test/src/lib.rs +++ b/core/service/test/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -25,7 +25,6 @@ use futures::{Future, Stream}; use tempdir::TempDir; use tokio::runtime::Runtime; use tokio::timer::Interval; -use primitives::blake2_256; use service::{ ServiceFactory, Configuration, @@ -34,8 +33,8 @@ use service::{ Roles, FactoryExtrinsic, }; -use network::{Protocol, SyncProvider, ManageNetwork}; -use network::config::{NetworkConfiguration, NonReservedPeerMode}; +use network::{multiaddr, SyncProvider, ManageNetwork}; +use network::config::{NetworkConfiguration, NodeKeyConfig, Secret, NonReservedPeerMode}; use sr_primitives::traits::As; use sr_primitives::generic::BlockId; use consensus::{ImportBlock, BlockImport}; @@ -64,10 +63,6 @@ impl TestNet { } } -fn node_private_key_string(index: u32) -> String { - format!("N{}", index) -} - fn node_config ( index: u32, spec: &FactoryChainSpec, @@ -83,17 +78,20 @@ fn node_config ( keys.push(seed); } + let config_path = Some(String::from(root.join("network").to_str().unwrap())); + let net_config_path = config_path.clone(); + let network_config = NetworkConfiguration { - config_path: Some(root.join("network").to_str().unwrap().into()), - net_config_path: Some(root.join("network").to_str().unwrap().into()), + config_path, + net_config_path, listen_addresses: vec! [ - iter::once(Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1))) - .chain(iter::once(Protocol::Tcp(base_port + index as u16))) + iter::once(multiaddr::Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1))) + .chain(iter::once(multiaddr::Protocol::Tcp(base_port + index as u16))) .collect() ], public_addresses: vec![], boot_nodes: vec![], - use_secret: Some(blake2_256(node_private_key_string(index).as_bytes())), + node_key: NodeKeyConfig::Ed25519(Secret::New), in_peers: 50, out_peers: 450, reserved_nodes: vec![], @@ -120,8 +118,11 @@ fn node_config ( execution_strategies: Default::default(), rpc_http: None, rpc_ws: None, - telemetry_url: None, + telemetry_endpoints: None, default_heap_pages: None, + offchain_worker: false, + force_authoring: false, + disable_grandpa: false, } } @@ -181,7 +182,7 @@ pub fn connectivity(spec: FactoryChainSpec) { service.network().add_reserved_peer(first_address.clone()).expect("Error adding reserved peer"); } network.run_until_all_full(|_index, service| - service.network().status().num_peers == NUM_NODES as usize - 1 + service.network().peers().len() == NUM_NODES as usize - 1 ); network.runtime }; @@ -201,7 +202,7 @@ pub fn connectivity(spec: FactoryChainSpec) { address = service.network().node_id().expect("No node address"); } network.run_until_all_full(|_index, service| { - service.network().status().num_peers == NUM_NODES as usize - 1 + service.network().peers().len() == NUM_NODES as usize - 1 }); } temp.close().expect("Error removing temp dir"); diff --git a/core/sr-api-macros/benches/bench.rs b/core/sr-api-macros/benches/bench.rs index 85ea3d6f88dd3046893617570eba761be89b6724..f4677217897924ef532adca0f2bac520f569c2ee 100644 --- a/core/sr-api-macros/benches/bench.rs +++ b/core/sr-api-macros/benches/bench.rs @@ -14,9 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use criterion::Criterion; +use criterion::{Criterion, criterion_group, criterion_main}; use test_client::runtime::TestAPI; use runtime_primitives::{generic::BlockId, traits::ProvideRuntimeApi}; +use state_machine::ExecutionStrategy; fn sr_api_benchmark(c: &mut Criterion) { c.bench_function("add one with same runtime api", |b| { @@ -50,6 +51,18 @@ fn sr_api_benchmark(c: &mut Criterion) { b.iter_with_large_drop(|| client.runtime_api().benchmark_vector_add_one(&block_id, &data)) }); + + c.bench_function("calling function by function pointer in wasm", |b| { + let client = test_client::new_with_execution_strategy(ExecutionStrategy::AlwaysWasm); + let block_id = BlockId::Number(client.info().unwrap().chain.best_number); + b.iter(|| client.runtime_api().benchmark_indirect_call(&block_id).unwrap()) + }); + + c.bench_function("calling function in wasm", |b| { + let client = test_client::new_with_execution_strategy(ExecutionStrategy::AlwaysWasm); + let block_id = BlockId::Number(client.info().unwrap().chain.best_number); + b.iter(|| client.runtime_api().benchmark_direct_call(&block_id).unwrap()) + }); } criterion_group!(benches, sr_api_benchmark); diff --git a/core/sr-api-macros/src/compile_fail_tests.rs b/core/sr-api-macros/src/compile_fail_tests.rs index 4f92e541285f72a9092a2a6dfbc2d2ccb8380c98..e562f8b2fe598a7e7a994b3c46748ec0952a0ad6 100644 --- a/core/sr-api-macros/src/compile_fail_tests.rs +++ b/core/sr-api-macros/src/compile_fail_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/sr-api-macros/src/decl_runtime_apis.rs b/core/sr-api-macros/src/decl_runtime_apis.rs index b320f4e06d7f9c411291205567e7ad053808d708..9e4c38f0878e5dad195db76d5a121448c9cb830b 100644 --- a/core/sr-api-macros/src/decl_runtime_apis.rs +++ b/core/sr-api-macros/src/decl_runtime_apis.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -21,7 +21,6 @@ use crate::utils::{ generate_method_runtime_api_impl_name }; -use proc_macro; use proc_macro2::{TokenStream, Span}; use quote::quote; @@ -52,7 +51,7 @@ const API_VERSION_ATTRIBUTE: &str = "api_version"; /// Is used when the function signature changed between different versions of a trait. /// This attribute should be placed on the old signature of the function. const CHANGED_IN_ATTRIBUTE: &str = "changed_in"; -/// All attributes that we support in the declaratio of a runtime api trait. +/// All attributes that we support in the declaration of a runtime api trait. const SUPPORTED_ATTRIBUTE_NAMES: &[&str] = &[ CORE_TRAIT_ATTRIBUTE, API_VERSION_ATTRIBUTE, CHANGED_IN_ATTRIBUTE ]; @@ -128,7 +127,7 @@ fn return_type_is_using_block(ty: &ReturnType) -> bool { visitor.result } -/// Replace all occurences of `Block` with `NodeBlock` +/// Replace all occurrences of `Block` with `NodeBlock` struct ReplaceBlockWithNodeBlock {} impl Fold for ReplaceBlockWithNodeBlock { @@ -141,13 +140,13 @@ impl Fold for ReplaceBlockWithNodeBlock { } } -/// Replace all occurences of `Block` with `NodeBlock` +/// Replace all occurrences of `Block` with `NodeBlock` fn fn_arg_replace_block_with_node_block(fn_arg: FnArg) -> FnArg { let mut replace = ReplaceBlockWithNodeBlock {}; fold::fold_fn_arg(&mut replace, fn_arg) } -/// Replace all occurences of `Block` with `NodeBlock` +/// Replace all occurrences of `Block` with `NodeBlock` fn return_type_replace_block_with_node_block(return_type: ReturnType) -> ReturnType { let mut replace = ReplaceBlockWithNodeBlock {}; fold::fold_return_type(&mut replace, return_type) @@ -163,7 +162,7 @@ fn generate_native_call_generators(decl: &ItemTrait) -> Result { let trait_ = &decl.ident; let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID); - // Auxilariy function that is used to convert between types that use different block types. + // Auxiliary function that is used to convert between types that use different block types. // The function expects that both a convertable by encoding the one and decoding the other. result.push(quote!( #[cfg(any(feature = "std", test))] diff --git a/core/sr-api-macros/src/impl_runtime_apis.rs b/core/sr-api-macros/src/impl_runtime_apis.rs index c6fb28b8020e89b50e8fd36228932afc9947f880..8bdf977303bcd0e27091d3a50ead43c4a72930c7 100644 --- a/core/sr-api-macros/src/impl_runtime_apis.rs +++ b/core/sr-api-macros/src/impl_runtime_apis.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -21,7 +21,6 @@ use crate::utils::{ return_type_extract_type }; -use proc_macro; use proc_macro2::{Span, TokenStream}; use quote::quote; @@ -408,7 +407,7 @@ fn generate_api_impl_for_runtime(impls: &[ItemImpl]) -> Result { } -/// Auxilariy data structure that is used to convert `impl Api for Runtime` to +/// Auxiliary data structure that is used to convert `impl Api for Runtime` to /// `impl Api for RuntimeApi`. /// This requires us to replace the runtime `Block` with the node `Block`, /// `impl Api for Runtime` with `impl Api for RuntimeApi` and replace the method implementations @@ -470,7 +469,7 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> { }; let context_arg: syn::FnArg = parse_quote!( context: #crate_::runtime_api::ExecutionContext ); - + // Rewrite the input parameters. input.sig.decl.inputs = parse_quote! { &self, at: &#block_id, #context_arg, params: Option<( #( #param_types ),* )>, params_encoded: Vec @@ -484,7 +483,7 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> { -> #crate_::error::Result<#crate_::runtime_api::NativeOrEncoded<#ret_type>> ); - // Generate the new method implementation that calls into the runime. + // Generate the new method implementation that calls into the runtime. parse_quote!( { // Get the error to the user (if we have one). @@ -616,7 +615,7 @@ fn generate_runtime_api_versions(impls: &[ItemImpl]) -> Result { pub fn impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream { // Parse all impl blocks let RuntimeApiImpls { impls: api_impls } = parse_macro_input!(input as RuntimeApiImpls); - + let dispatch_impl = unwrap_or_error(generate_dispatch_function(&api_impls)); let api_impls_for_runtime = unwrap_or_error(generate_api_impl_for_runtime(&api_impls)); let base_runtime_api = unwrap_or_error(generate_runtime_api_base_structures(&api_impls)); diff --git a/core/sr-api-macros/src/lib.rs b/core/sr-api-macros/src/lib.rs index 7c042eef250340ce9089a422ae66f77f2b1ded9b..72e143eb1a0088a2e16dcae9ae955b6c4a3faf43 100644 --- a/core/sr-api-macros/src/lib.rs +++ b/core/sr-api-macros/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -155,7 +155,7 @@ pub fn impl_runtime_apis(input: TokenStream) -> TokenStream { /// /// To support versioning of the traits, the macro supports the attribute `#[api_version(1)]`. /// The attribute supports any `u32` as version. By default, each trait is at version `1`, if no -/// version is provided. We also support chaning the signature of a method. This signature +/// version is provided. We also support changing the signature of a method. This signature /// change is highlighted with the `#[changed_in(2)]` attribute above a method. A method that is /// tagged with this attribute is callable by the name `METHOD_before_version_VERSION`. This /// method will only support calling into wasm, trying to call into native will fail (change the diff --git a/core/sr-api-macros/src/utils.rs b/core/sr-api-macros/src/utils.rs index fd9964b59f39c11c1a75a305445111d08d723631..e593e41ebedd4519f4bc2773d20bcd34df8a914b 100644 --- a/core/sr-api-macros/src/utils.rs +++ b/core/sr-api-macros/src/utils.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -54,7 +54,7 @@ pub fn generate_hidden_includes(unique_id: &'static str) -> TokenStream { }.into() } -/// Generates the access to the `subtrate_client` crate. +/// Generates the access to the `substrate_client` crate. pub fn generate_crate_access(unique_id: &'static str) -> TokenStream { if env::var("CARGO_PKG_NAME").unwrap() == "substrate-client" { quote!( crate ) diff --git a/core/sr-io/Cargo.toml b/core/sr-io/Cargo.toml index 2198ec253f565ee178962f2138a2345ae03e6a9e..148b49e039beea815e790288a4b93b684e6e34af 100644 --- a/core/sr-io/Cargo.toml +++ b/core/sr-io/Cargo.toml @@ -11,13 +11,13 @@ rustc_version = "0.2" [dependencies] rstd = { package = "sr-std", path = "../sr-std", default-features = false } primitives = { package = "substrate-primitives", path = "../primitives", default-features = false } -parity-codec = { version = "3.0", default-features = false } -hash-db = { version = "0.11", default-features = false } +parity-codec = { version = "3.2", default-features = false } +hash-db = { version = "0.12", default-features = false } libsecp256k1 = { version = "0.2.1", optional = true } tiny-keccak = { version = "1.4.2", optional = true } -environmental = { version = "~1.0", optional = true } +environmental = { version = "1.0.1", optional = true } substrate-state-machine = { path = "../state-machine", optional = true } -trie = { package = "substrate-trie", path = "../trie", optional = true } +trie = { package = "substrate-trie", path = "../trie", default-features = false } [features] default = ["std"] @@ -25,13 +25,13 @@ std = [ "primitives/std", "parity-codec/std", "rstd/std", - + "trie/std", "hash-db/std", "environmental", "substrate-state-machine", - "trie", "libsecp256k1", "tiny-keccak" ] nightly = [] strict = [] +wasm-nice-panic-message = [] diff --git a/core/sr-io/src/lib.rs b/core/sr-io/src/lib.rs index aa446f74a5f0d2af3aca110a130227e30037845e..6a00e6ca2734d1b73fe7ec6e7063b9bf2e03b3f2 100644 --- a/core/sr-io/src/lib.rs +++ b/core/sr-io/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/sr-io/with_std.rs b/core/sr-io/with_std.rs index 562e349ceda79b6464a96f7df6ee87d771b702a9..1f4ce56fc9b0ed5cda73c6c7513ce34e978cf6fe 100644 --- a/core/sr-io/with_std.rs +++ b/core/sr-io/with_std.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -17,19 +17,30 @@ #[doc(hidden)] pub use parity_codec as codec; // re-export hashing functions. -pub use primitives::{blake2_256, twox_128, twox_256, ed25519, Blake2Hasher, sr25519}; +pub use primitives::{ + blake2_256, twox_128, twox_256, ed25519, Blake2Hasher, sr25519, + Pair +}; pub use tiny_keccak::keccak256 as keccak_256; // Switch to this after PoC-3 // pub use primitives::BlakeHasher; -pub use substrate_state_machine::{Externalities, TestExternalities}; +pub use substrate_state_machine::{Externalities, BasicExternalities, TestExternalities}; -use environmental::{environmental, thread_local_impl}; -use primitives::hexdisplay::HexDisplay; -use primitives::H256; +use environmental::environmental; +use primitives::{hexdisplay::HexDisplay, H256}; use hash_db::Hasher; +#[cfg(feature = "std")] +use std::collections::HashMap; + environmental!(ext: trait Externalities); +/// A set of key value pairs for storage. +pub type StorageOverlay = HashMap, Vec>; + +/// A set of key value pairs for children storage; +pub type ChildrenStorageOverlay = HashMap, StorageOverlay>; + /// Get `key` from storage and return a `Vec`, empty if there's a problem. pub fn storage(key: &[u8]) -> Option> { ext::with(|ext| ext.storage(key).map(|s| s.to_vec())) @@ -153,6 +164,7 @@ pub fn storage_changes_root(parent_hash: [u8; 32], parent_num: u64) -> Option

(input: &[&[u8]]) -> H::Out where H: Hasher, @@ -186,17 +198,17 @@ where /// Verify a ed25519 signature. pub fn ed25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool { - ed25519::verify(sig, msg, pubkey) + ed25519::Pair::verify_weak(sig, msg, pubkey) } /// Verify an sr25519 signature. pub fn sr25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool { - sr25519::verify(sig, msg, pubkey) + sr25519::Pair::verify_weak(sig, msg, pubkey) } /// Verify and recover a SECP256k1 ECDSA signature. /// - `sig` is passed in RSV format. V should be either 0/1 or 27/28. -/// - returns `Err` if the signatue is bad, otherwise the 64-byte pubkey (doesn't include the 0x04 prefix). +/// - returns `Err` if the signature is bad, otherwise the 64-byte pubkey (doesn't include the 0x04 prefix). pub fn secp256k1_ecdsa_recover(sig: &[u8; 65], msg: &[u8; 32]) -> Result<[u8; 64], EcdsaVerifyError> { let rs = secp256k1::Signature::parse_slice(&sig[0..64]).map_err(|_| EcdsaVerifyError::BadRS)?; let v = secp256k1::RecoveryId::parse(if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8).map_err(|_| EcdsaVerifyError::BadV)?; @@ -206,6 +218,14 @@ pub fn secp256k1_ecdsa_recover(sig: &[u8; 65], msg: &[u8; 32]) -> Result<[u8; 64 Ok(res) } +/// Submit extrinsic. +pub fn submit_extrinsic(data: &T) { + ext::with(|ext| ext + .submit_extrinsic(codec::Encode::encode(data)) + .expect("submit_extrinsic can be called only in offchain worker context") + ).expect("submit_extrinsic cannot be called outside of an Externalities-provided environment.") +} + /// Execute the given closure with global function available whose functionality routes into the /// externalities `ext`. Forwards the value that the closure returns. // NOTE: need a concrete hasher here due to limitations of the `environmental!` macro, otherwise a type param would have been fine I think. @@ -213,6 +233,17 @@ pub fn with_externalities R>(ext: &mut Externalities 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 r = ext::using(&mut ext, f); + *storage = ext.into(); + r +} + /// Trait for things which can be printed. pub trait Printable { fn print(self); @@ -248,7 +279,7 @@ mod std_tests { #[test] fn storage_works() { - let mut t = TestExternalities::::default(); + let mut t = BasicExternalities::default(); assert!(with_externalities(&mut t, || { assert_eq!(storage(b"hello"), None); set_storage(b"hello", b"world"); @@ -258,7 +289,7 @@ mod std_tests { true })); - t = TestExternalities::new(map![b"foo".to_vec() => b"bar".to_vec()]); + t = BasicExternalities::new(map![b"foo".to_vec() => b"bar".to_vec()]); assert!(!with_externalities(&mut t, || { assert_eq!(storage(b"hello"), None); @@ -269,7 +300,7 @@ mod std_tests { #[test] fn read_storage_works() { - let mut t = TestExternalities::::new(map![ + let mut t = BasicExternalities::new(map![ b":test".to_vec() => b"\x0b\0\0\0Hello world".to_vec() ]); @@ -285,7 +316,7 @@ mod std_tests { #[test] fn clear_prefix_works() { - let mut t = TestExternalities::::new(map![ + let mut t = BasicExternalities::new(map![ b":a".to_vec() => b"\x0b\0\0\0Hello world".to_vec(), b":abcd".to_vec() => b"\x0b\0\0\0Hello world".to_vec(), b":abc".to_vec() => b"\x0b\0\0\0Hello world".to_vec(), diff --git a/core/sr-io/without_std.rs b/core/sr-io/without_std.rs index 5687812830bb486146cf2cd26431ca8ed9096c89..a4d62df30b16c671e04b09c8fd8721abb2ff2de8 100644 --- a/core/sr-io/without_std.rs +++ b/core/sr-io/without_std.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -20,19 +20,27 @@ pub use parity_codec as codec; pub use rstd; pub use rstd::{mem, slice}; -use core::intrinsics; -use rstd::vec::Vec; +use core::{intrinsics, panic::PanicInfo}; +use rstd::{vec::Vec, cell::Cell}; use hash_db::Hasher; use primitives::Blake2Hasher; #[panic_handler] #[no_mangle] -pub fn panic(info: &::core::panic::PanicInfo) -> ! { +pub fn panic(info: &PanicInfo) -> ! { unsafe { - if let Some(loc) = info.location() { - ext_print_utf8(loc.file().as_ptr() as *const u8, loc.file().len() as u32); - ext_print_num(loc.line() as u64); - ext_print_num(loc.column() as u64); + #[cfg(feature = "wasm-nice-panic-message")] + { + let message = rstd::alloc::format!("{}", info); + extern_functions_host_impl::ext_print_utf8(message.as_ptr() as *const u8, message.len() as u32); + } + #[cfg(not(feature = "wasm-nice-panic-message"))] + { + if let Some(loc) = info.location() { + extern_functions_host_impl::ext_print_utf8(loc.file().as_ptr() as *const u8, loc.file().len() as u32); + extern_functions_host_impl::ext_print_num(loc.line() as u64); + extern_functions_host_impl::ext_print_num(loc.column() as u64); + } } intrinsics::abort() } @@ -43,41 +51,223 @@ pub extern fn oom(_: ::core::alloc::Layout) -> ! { static OOM_MSG: &str = "Runtime memory exhausted. Aborting"; unsafe { - ext_print_utf8(OOM_MSG.as_ptr(), OOM_MSG.len() as u32); + extern_functions_host_impl::ext_print_utf8(OOM_MSG.as_ptr(), OOM_MSG.len() as u32); intrinsics::abort(); } } +/// The state of an exchangeable function. +#[derive(Clone, Copy)] +enum ExchangeableFunctionState { + Original, + Replaced, +} + +/// A function which implementation can be exchanged. +/// +/// Internally this works by swapping function pointers. +pub struct ExchangeableFunction(Cell<(T, ExchangeableFunctionState)>); + +impl ExchangeableFunction { + /// Create a new instance of `ExchangeableFunction`. + pub const fn new(impl_: T) -> Self { + Self(Cell::new((impl_, ExchangeableFunctionState::Original))) + } +} + +impl ExchangeableFunction { + /// Replace the implementation with `new_impl`. + /// + /// # Panics + /// + /// Panics when trying to replace an already replaced implementation. + /// + /// # Returns + /// + /// Returns the original implementation wrapped in [`RestoreImplementation`]. + pub fn replace_implementation(&'static self, new_impl: T) -> RestoreImplementation { + if let ExchangeableFunctionState::Replaced = self.0.get().1 { + panic!("Trying to replace an already replaced implementation!") + } + + let old = self.0.replace((new_impl, ExchangeableFunctionState::Replaced)); + + RestoreImplementation(self, Some(old.0)) + } + + /// Restore the original implementation. + fn restore_orig_implementation(&self, orig: T) { + self.0.set((orig, ExchangeableFunctionState::Original)); + } + + /// Returns the internal function pointer. + pub fn get(&self) -> T { + self.0.get().0 + } +} + +// WASM does not support threads, so this is safe; qed. +unsafe impl Sync for ExchangeableFunction {} + +/// Restores a function implementation on drop. +/// +/// Stores a static reference to the function object and the original implementation. +pub struct RestoreImplementation(&'static ExchangeableFunction, Option); + +impl Drop for RestoreImplementation { + fn drop(&mut self) { + self.0.restore_orig_implementation(self.1.take().expect("Value is only taken on drop; qed")); + } +} + +/// Declare extern functions +macro_rules! extern_functions { + ( + $( + $( #[$attr:meta] )* + fn $name:ident ( $( $arg:ident : $arg_ty:ty ),* ) $( -> $ret:ty )?; + )* + ) => { + $( + $( #[$attr] )* + #[allow(non_upper_case_globals)] + pub static $name: ExchangeableFunction $ret )?> = + ExchangeableFunction::new(extern_functions_host_impl::$name); + )* + + /// The exchangeable extern functions host implementations. + mod extern_functions_host_impl { + $( + pub unsafe fn $name ( $( $arg : $arg_ty ),* ) $( -> $ret )? { + implementation::$name ( $( $arg ),* ) + } + )* + + mod implementation { + extern "C" { + $( + pub fn $name ( $( $arg : $arg_ty ),* ) $( -> $ret )?; + )* + } + } + } + }; +} + /// Host functions, provided by the executor. /// A WebAssembly runtime module would "import" these to access the execution environment /// (most importantly, storage) or perform heavy hash calculations. /// See also "ext_" functions in sr-sandbox and sr-std -extern "C" { - /// Printing, useful for debugging +extern_functions! { + /// Host functions for printing, useful for debugging. fn ext_print_utf8(utf8_data: *const u8, utf8_len: u32); fn ext_print_hex(data: *const u8, len: u32); fn ext_print_num(value: u64); - /// Host storage access and verification + /// Set value for key in storage. fn ext_set_storage(key_data: *const u8, key_len: u32, value_data: *const u8, value_len: u32); - fn ext_set_child_storage(storage_key_data: *const u8, storage_key_len: u32, key_data: *const u8, key_len: u32, value_data: *const u8, value_len: u32); + /// Remove key and value from storage. fn ext_clear_storage(key_data: *const u8, key_len: u32); - fn ext_clear_child_storage(storage_key_data: *const u8, storage_key_len: u32, key_data: *const u8, key_len: u32); + /// Checks if the given key exists in the storage. + /// + /// # Returns + /// + /// - `1` if the value exists. + /// - `0` if the value does not exists. fn ext_exists_storage(key_data: *const u8, key_len: u32) -> u32; - fn ext_exists_child_storage(storage_key_data: *const u8, storage_key_len: u32, key_data: *const u8, key_len: u32) -> u32; + /// Remove storage entries which key starts with given prefix. fn ext_clear_prefix(prefix_data: *const u8, prefix_len: u32); - fn ext_kill_child_storage(storage_key_data: *const u8, storage_key_len: u32); - /// Host-side result allocation + /// Gets the value of the given key from storage. + /// + /// The host allocates the memory for storing the value. + /// + /// # Returns + /// + /// - `0` if no value exists to the given key. `written_out` is set to `u32::max_value()`. + /// + /// - Otherwise, pointer to the value in memory. `written_out` contains the length of the value. fn ext_get_allocated_storage(key_data: *const u8, key_len: u32, written_out: *mut u32) -> *mut u8; - /// Host-side result allocation - fn ext_get_allocated_child_storage(storage_key_data: *const u8, storage_key_len: u32, key_data: *const u8, key_len: u32, written_out: *mut u32) -> *mut u8; + /// Gets the value of the given key from storage. + /// + /// The value is written into `value` starting at `value_offset`. + /// + /// If the value length is greater than `value_len - value_offset`, the value is written partially. + /// + /// # Returns + /// + /// - `u32::max_value()` if the value does not exists. + /// + /// - Otherwise, the number of bytes written for value. fn ext_get_storage_into(key_data: *const u8, key_len: u32, value_data: *mut u8, value_len: u32, value_offset: u32) -> u32; - fn ext_get_child_storage_into(storage_key_data: *const u8, storage_key_len: u32, key_data: *const u8, key_len: u32, value_data: *mut u8, value_len: u32, value_offset: u32) -> u32; + /// Gets the trie root of the storage. fn ext_storage_root(result: *mut u8); - /// Host-side result allocation - fn ext_child_storage_root(storage_key_data: *const u8, storage_key_len: u32, written_out: *mut u32) -> *mut u8; + /// Get the change trie root of the current storage overlay at a block with given parent. + /// + /// # Returns + /// + /// - `1` if the change trie root was found. + /// - `0` if the change trie root was not found. fn ext_storage_changes_root(parent_hash_data: *const u8, parent_hash_len: u32, parent_num: u64, result: *mut u8) -> u32; + /// A child storage function. + /// + /// See [`ext_set_storage`] for details. + /// + /// A child storage is used e.g. by a contract. + fn ext_set_child_storage(storage_key_data: *const u8, storage_key_len: u32, key_data: *const u8, key_len: u32, value_data: *const u8, value_len: u32); + /// A child storage function. + /// + /// See [`ext_clear_storage`] for details. + /// + /// A child storage is used e.g. by a contract. + fn ext_clear_child_storage(storage_key_data: *const u8, storage_key_len: u32, key_data: *const u8, key_len: u32); + /// A child storage function. + /// + /// See [`ext_exists_storage`] for details. + /// + /// A child storage is used e.g. by a contract. + fn ext_exists_child_storage(storage_key_data: *const u8, storage_key_len: u32, key_data: *const u8, key_len: u32) -> u32; + /// A child storage function. + /// + /// See [`ext_kill_storage`] for details. + /// + /// A child storage is used e.g. by a contract. + fn ext_kill_child_storage(storage_key_data: *const u8, storage_key_len: u32); + /// A child storage function. + /// + /// See [`ext_get_allocated_storage`] for details. + /// + /// A child storage is used e.g. by a contract. + fn ext_get_allocated_child_storage( + storage_key_data: *const u8, + storage_key_len: u32, + key_data: *const u8, + key_len: u32, + written_out: *mut u32 + ) -> *mut u8; + /// A child storage function. + /// + /// See [`ext_get_storage_into`] for details. + /// + /// A child storage is used e.g. by a contract. + fn ext_get_child_storage_into( + storage_key_data: *const u8, + storage_key_len: u32, + key_data: *const u8, + key_len: u32, + value_data: *mut u8, + value_len: u32, + value_offset: u32 + ) -> u32; + /// Commits all changes and calculates the child-storage root. + /// + /// A child storage is used e.g. by a contract. + /// + /// # Returns + /// + /// - The pointer to the result vector and `written_out` contains its length. + fn ext_child_storage_root(storage_key_data: *const u8, storage_key_len: u32, written_out: *mut u32) -> *mut u8; + /// The current relay chain identifier. fn ext_chain_id() -> u64; @@ -93,6 +283,13 @@ extern "C" { fn ext_sr25519_verify(msg_data: *const u8, msg_len: u32, sig_data: *const u8, pubkey_data: *const u8) -> u32; /// Note: ext_secp256k1_ecdsa_recover returns 0 if the signature is correct, nonzero otherwise. fn ext_secp256k1_ecdsa_recover(msg_data: *const u8, sig_data: *const u8, pubkey_data: *mut u8) -> u32; + + //================================ + // Offchain-worker Context + //================================ + + /// Submit extrinsic. + fn ext_submit_extrinsic(data: *const u8, len: u32); } /// Ensures we use the right crypto when calling into native @@ -107,7 +304,7 @@ impl ExternTrieCrypto for Blake2Hasher { let values = values.iter().fold(Vec::new(), |mut acc, sl| { acc.extend_from_slice(sl); acc }); let mut result: [u8; 32] = Default::default(); unsafe { - ext_blake2_256_enumerated_trie_root( + ext_blake2_256_enumerated_trie_root.get()( values.as_ptr(), lengths.as_ptr(), lengths.len() as u32, @@ -122,7 +319,7 @@ impl ExternTrieCrypto for Blake2Hasher { pub fn storage(key: &[u8]) -> Option> { let mut length: u32 = 0; unsafe { - let ptr = ext_get_allocated_storage(key.as_ptr(), key.len() as u32, &mut length); + let ptr = ext_get_allocated_storage.get()(key.as_ptr(), key.len() as u32, &mut length); if length == u32::max_value() { None } else { @@ -138,7 +335,13 @@ pub fn storage(key: &[u8]) -> Option> { pub fn child_storage(storage_key: &[u8], key: &[u8]) -> Option> { let mut length: u32 = 0; unsafe { - let ptr = ext_get_allocated_child_storage(storage_key.as_ptr(), storage_key.len() as u32, key.as_ptr(), key.len() as u32, &mut length); + let ptr = ext_get_allocated_child_storage.get()( + storage_key.as_ptr(), + storage_key.len() as u32, + key.as_ptr(), + key.len() as u32, + &mut length + ); if length == u32::max_value() { None } else { @@ -153,7 +356,7 @@ pub fn child_storage(storage_key: &[u8], key: &[u8]) -> Option> { /// Set the storage of some particular key to Some value. pub fn set_storage(key: &[u8], value: &[u8]) { unsafe { - ext_set_storage( + ext_set_storage.get()( key.as_ptr(), key.len() as u32, value.as_ptr(), value.len() as u32 ); @@ -163,7 +366,7 @@ pub fn set_storage(key: &[u8], value: &[u8]) { /// Set the child storage of some particular key to Some value. pub fn set_child_storage(storage_key: &[u8], key: &[u8], value: &[u8]) { unsafe { - ext_set_child_storage( + ext_set_child_storage.get()( storage_key.as_ptr(), key.len() as u32, key.as_ptr(), key.len() as u32, value.as_ptr(), value.len() as u32 @@ -174,7 +377,7 @@ pub fn set_child_storage(storage_key: &[u8], key: &[u8], value: &[u8]) { /// Clear the storage of some particular key. pub fn clear_storage(key: &[u8]) { unsafe { - ext_clear_storage( + ext_clear_storage.get()( key.as_ptr(), key.len() as u32 ); } @@ -183,7 +386,7 @@ pub fn clear_storage(key: &[u8]) { /// Clear the storage of some particular key. pub fn clear_child_storage(storage_key: &[u8], key: &[u8]) { unsafe { - ext_clear_child_storage( + ext_clear_child_storage.get()( storage_key.as_ptr(), storage_key.len() as u32, key.as_ptr(), key.len() as u32 ); @@ -193,7 +396,7 @@ pub fn clear_child_storage(storage_key: &[u8], key: &[u8]) { /// Determine whether a particular key exists in storage. pub fn exists_storage(key: &[u8]) -> bool { unsafe { - ext_exists_storage( + ext_exists_storage.get()( key.as_ptr(), key.len() as u32 ) != 0 } @@ -202,7 +405,7 @@ pub fn exists_storage(key: &[u8]) -> bool { /// Determine whether a particular key exists in storage. pub fn exists_child_storage(storage_key: &[u8], key: &[u8]) -> bool { unsafe { - ext_exists_child_storage( + ext_exists_child_storage.get()( storage_key.as_ptr(), storage_key.len() as u32, key.as_ptr(), key.len() as u32 ) != 0 @@ -212,7 +415,7 @@ pub fn exists_child_storage(storage_key: &[u8], key: &[u8]) -> bool { /// Clear the storage entries key of which starts with the given prefix. pub fn clear_prefix(prefix: &[u8]) { unsafe { - ext_clear_prefix( + ext_clear_prefix.get()( prefix.as_ptr(), prefix.len() as u32 ); @@ -222,7 +425,7 @@ pub fn clear_prefix(prefix: &[u8]) { /// Clear an entire child storage. pub fn kill_child_storage(storage_key: &[u8]) { unsafe { - ext_kill_child_storage( + ext_kill_child_storage.get()( storage_key.as_ptr(), storage_key.len() as u32 ); @@ -233,10 +436,12 @@ pub fn kill_child_storage(storage_key: &[u8]) { /// the number of bytes that the key in storage was beyond the offset. pub fn read_storage(key: &[u8], value_out: &mut [u8], value_offset: usize) -> Option { unsafe { - match ext_get_storage_into( - key.as_ptr(), key.len() as u32, - value_out.as_mut_ptr(), value_out.len() as u32, - value_offset as u32 + match ext_get_storage_into.get()( + key.as_ptr(), + key.len() as u32, + value_out.as_mut_ptr(), + value_out.len() as u32, + value_offset as u32, ) { none if none == u32::max_value() => None, length => Some(length as usize), @@ -248,7 +453,7 @@ pub fn read_storage(key: &[u8], value_out: &mut [u8], value_offset: usize) -> Op /// the number of bytes that the key in storage was beyond the offset. pub fn read_child_storage(storage_key: &[u8], key: &[u8], value_out: &mut [u8], value_offset: usize) -> Option { unsafe { - match ext_get_child_storage_into( + match ext_get_child_storage_into.get()( storage_key.as_ptr(), storage_key.len() as u32, key.as_ptr(), key.len() as u32, value_out.as_mut_ptr(), value_out.len() as u32, @@ -264,7 +469,7 @@ pub fn read_child_storage(storage_key: &[u8], key: &[u8], value_out: &mut [u8], pub fn storage_root() -> [u8; 32] { let mut result: [u8; 32] = Default::default(); unsafe { - ext_storage_root(result.as_mut_ptr()); + ext_storage_root.get()(result.as_mut_ptr()); } result } @@ -273,7 +478,7 @@ pub fn storage_root() -> [u8; 32] { pub fn child_storage_root(storage_key: &[u8]) -> Option> { let mut length: u32 = 0; unsafe { - let ptr = ext_child_storage_root(storage_key.as_ptr(), storage_key.len() as u32, &mut length); + let ptr = ext_child_storage_root.get()(storage_key.as_ptr(), storage_key.len() as u32, &mut length); if length == u32::max_value() { None } else { @@ -289,7 +494,7 @@ pub fn child_storage_root(storage_key: &[u8]) -> Option> { pub fn storage_changes_root(parent_hash: [u8; 32], parent_num: u64) -> Option<[u8; 32]> { let mut result: [u8; 32] = Default::default(); let is_set = unsafe { - ext_storage_changes_root(parent_hash.as_ptr(), parent_hash.len() as u32, parent_num, result.as_mut_ptr()) + ext_storage_changes_root.get()(parent_hash.as_ptr(), parent_hash.len() as u32, parent_num, result.as_mut_ptr()) }; if is_set != 0 { @@ -326,7 +531,7 @@ pub fn ordered_trie_root< /// The current relay chain identifier. pub fn chain_id() -> u64 { unsafe { - ext_chain_id() + ext_chain_id.get()() } } @@ -334,7 +539,7 @@ pub fn chain_id() -> u64 { pub fn blake2_256(data: &[u8]) -> [u8; 32] { let mut result: [u8; 32] = Default::default(); unsafe { - ext_blake2_256(data.as_ptr(), data.len() as u32, result.as_mut_ptr()); + ext_blake2_256.get()(data.as_ptr(), data.len() as u32, result.as_mut_ptr()); } result } @@ -343,7 +548,7 @@ pub fn blake2_256(data: &[u8]) -> [u8; 32] { pub fn keccak_256(data: &[u8]) -> [u8; 32] { let mut result: [u8; 32] = Default::default(); unsafe { - ext_keccak_256(data.as_ptr(), data.len() as u32, result.as_mut_ptr()); + ext_keccak_256.get()(data.as_ptr(), data.len() as u32, result.as_mut_ptr()); } result } @@ -352,7 +557,7 @@ pub fn keccak_256(data: &[u8]) -> [u8; 32] { pub fn twox_256(data: &[u8]) -> [u8; 32] { let mut result: [u8; 32] = Default::default(); unsafe { - ext_twox_256(data.as_ptr(), data.len() as u32, result.as_mut_ptr()); + ext_twox_256.get()(data.as_ptr(), data.len() as u32, result.as_mut_ptr()); } result } @@ -361,7 +566,7 @@ pub fn twox_256(data: &[u8]) -> [u8; 32] { pub fn twox_128(data: &[u8]) -> [u8; 16] { let mut result: [u8; 16] = Default::default(); unsafe { - ext_twox_128(data.as_ptr(), data.len() as u32, result.as_mut_ptr()); + ext_twox_128.get()(data.as_ptr(), data.len() as u32, result.as_mut_ptr()); } result } @@ -369,24 +574,24 @@ pub fn twox_128(data: &[u8]) -> [u8; 16] { /// Verify a ed25519 signature. pub fn ed25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool { unsafe { - ext_ed25519_verify(msg.as_ptr(), msg.len() as u32, sig.as_ptr(), pubkey.as_ref().as_ptr()) == 0 + ext_ed25519_verify.get()(msg.as_ptr(), msg.len() as u32, sig.as_ptr(), pubkey.as_ref().as_ptr()) == 0 } } /// Verify a sr25519 signature. pub fn sr25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool { unsafe { - ext_sr25519_verify(msg.as_ptr(), msg.len() as u32, sig.as_ptr(), pubkey.as_ref().as_ptr()) == 0 + ext_sr25519_verify.get()(msg.as_ptr(), msg.len() as u32, sig.as_ptr(), pubkey.as_ref().as_ptr()) == 0 } } /// Verify and recover a SECP256k1 ECDSA signature. /// - `sig` is passed in RSV format. V should be either 0/1 or 27/28. -/// - returns `None` if the signatue is bad, the 64-byte pubkey (doesn't include the 0x04 prefix). +/// - returns `None` if the signature is bad, the 64-byte pubkey (doesn't include the 0x04 prefix). pub fn secp256k1_ecdsa_recover(sig: &[u8; 65], msg: &[u8; 32]) -> Result<[u8; 64], EcdsaVerifyError> { let mut pubkey = [0u8; 64]; match unsafe { - ext_secp256k1_ecdsa_recover(msg.as_ptr(), sig.as_ptr(), pubkey.as_mut_ptr()) + ext_secp256k1_ecdsa_recover.get()(msg.as_ptr(), sig.as_ptr(), pubkey.as_mut_ptr()) } { 0 => Ok(pubkey), 1 => Err(EcdsaVerifyError::BadRS), @@ -396,6 +601,18 @@ pub fn secp256k1_ecdsa_recover(sig: &[u8; 65], msg: &[u8; 32]) -> Result<[u8; 64 } } +/// Submit extrinsic from the runtime. +/// +/// Depending on the kind of extrinsic it will either be: +/// 1. scheduled to be included in the next produced block (inherent) +/// 2. added to the pool and propagated (transaction) +pub fn submit_extrinsic(data: &T) { + let encoded_data = codec::Encode::encode(data); + unsafe { + ext_submit_extrinsic.get()(encoded_data.as_ptr(), encoded_data.len() as u32) + } +} + /// Trait for things which can be printed. pub trait Printable { fn print(self); @@ -404,7 +621,7 @@ pub trait Printable { impl<'a> Printable for &'a [u8] { fn print(self) { unsafe { - ext_print_hex(self.as_ptr(), self.len() as u32); + ext_print_hex.get()(self.as_ptr(), self.len() as u32); } } } @@ -412,14 +629,14 @@ impl<'a> Printable for &'a [u8] { impl<'a> Printable for &'a str { fn print(self) { unsafe { - ext_print_utf8(self.as_ptr() as *const u8, self.len() as u32); + ext_print_utf8.get()(self.as_ptr() as *const u8, self.len() as u32); } } } impl Printable for u64 { fn print(self) { - unsafe { ext_print_num(self); } + unsafe { ext_print_num.get()(self); } } } diff --git a/core/sr-primitives/Cargo.toml b/core/sr-primitives/Cargo.toml index 2d981c58773f91c5ce58f8c203b03ca8e2026c18..565b9fb1e400aa1c533a2175e1bfe87a5fbd4ac7 100644 --- a/core/sr-primitives/Cargo.toml +++ b/core/sr-primitives/Cargo.toml @@ -9,12 +9,11 @@ num-traits = { version = "0.2", default-features = false } integer-sqrt = { version = "0.1.2" } serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", 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 } +log = { version = "0.4", optional = true } [dev-dependencies] serde_json = "1.0" diff --git a/core/sr-primitives/src/generic/block.rs b/core/sr-primitives/src/generic/block.rs index 951e5cbfbb48dd0a5020630df29aac429cd5ec79..5fb83a2a4f766251ca7908196148e89ade4a075e 100644 --- a/core/sr-primitives/src/generic/block.rs +++ b/core/sr-primitives/src/generic/block.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -23,8 +23,7 @@ use std::fmt; use serde_derive::Serialize; use rstd::prelude::*; -use parity_codec_derive::{Encode, Decode}; -use crate::codec::Codec; +use crate::codec::{Codec, Encode, Decode}; use crate::traits::{self, Member, Block as BlockT, Header as HeaderT, MaybeSerialize}; use crate::Justification; diff --git a/core/sr-primitives/src/generic/checked_extrinsic.rs b/core/sr-primitives/src/generic/checked_extrinsic.rs index 4cf61e37e4cb2ffe6cb59f52bef069b4ecf3109e..c0548c26e598ea51ce692fe4402e2fdb74cb86da 100644 --- a/core/sr-primitives/src/generic/checked_extrinsic.rs +++ b/core/sr-primitives/src/generic/checked_extrinsic.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/sr-primitives/src/generic/digest.rs b/core/sr-primitives/src/generic/digest.rs index 64bc0396fd30644f6e303799f102228f5b78bb54..710bcc77457ce3ac86262f7e3753f184874ad913 100644 --- a/core/sr-primitives/src/generic/digest.rs +++ b/core/sr-primitives/src/generic/digest.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -20,13 +20,10 @@ use serde_derive::Serialize; use rstd::prelude::*; -use parity_codec_derive::{Encode, Decode}; use crate::codec::{Decode, Encode, Codec, Input}; use crate::traits::{self, Member, DigestItem as DigestItemT, MaybeHash}; -use substrate_primitives::hash::H512 as Signature; - /// Generic header digest. #[derive(PartialEq, Eq, Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug, Serialize))] @@ -64,7 +61,7 @@ impl traits::Digest for Digest where /// provide opaque access to other items. #[derive(PartialEq, Eq, Clone)] #[cfg_attr(feature = "std", derive(Debug))] -pub enum DigestItem { +pub enum DigestItem { /// System digest item announcing that authorities set has been changed /// in the block. Contains the new set of authorities. AuthoritiesChange(Vec), @@ -73,13 +70,13 @@ pub enum DigestItem { /// trie creation. ChangesTrieRoot(Hash), /// Put a Seal on it - Seal(u64, Signature), + Seal(u64, SealSignature), /// Any 'non-system' digest item, opaque to the native code. Other(Vec), } #[cfg(feature = "std")] -impl ::serde::Serialize for DigestItem { +impl ::serde::Serialize for DigestItem { fn serialize(&self, seq: S) -> Result where S: ::serde::Serializer { self.using_encoded(|bytes| { ::substrate_primitives::bytes::serialize(bytes, seq) @@ -92,13 +89,13 @@ impl ::serde::Serialize for DigestItem { +pub enum DigestItemRef<'a, Hash: 'a, AuthorityId: 'a, SealSignature: 'a> { /// Reference to `DigestItem::AuthoritiesChange`. AuthoritiesChange(&'a [AuthorityId]), /// Reference to `DigestItem::ChangesTrieRoot`. ChangesTrieRoot(&'a Hash), /// A sealed signature for testing - Seal(&'a u64, &'a Signature), + Seal(&'a u64, &'a SealSignature), /// Any 'non-system' digest item, opaque to the native code. /// Reference to `DigestItem::Other`. Other(&'a Vec), @@ -117,7 +114,7 @@ enum DigestItemType { Seal, } -impl DigestItem { +impl DigestItem { /// Returns Some if `self` is a `DigestItem::Other`. pub fn as_other(&self) -> Option<&Vec> { match *self { @@ -127,7 +124,7 @@ impl DigestItem { } /// Returns a 'referencing view' for this digest item. - fn dref<'a>(&'a self) -> DigestItemRef<'a, Hash, AuthorityId> { + fn dref<'a>(&'a self) -> DigestItemRef<'a, Hash, AuthorityId, SealSignature> { match *self { DigestItem::AuthoritiesChange(ref v) => DigestItemRef::AuthoritiesChange(v), DigestItem::ChangesTrieRoot(ref v) => DigestItemRef::ChangesTrieRoot(v), @@ -140,7 +137,8 @@ impl DigestItem { impl< Hash: Codec + Member, AuthorityId: Codec + Member + MaybeHash, -> traits::DigestItem for DigestItem { + SealSignature: Codec + Member, +> traits::DigestItem for DigestItem { type Hash = Hash; type AuthorityId = AuthorityId; @@ -153,13 +151,13 @@ impl< } } -impl Encode for DigestItem { +impl Encode for DigestItem { fn encode(&self) -> Vec { self.dref().encode() } } -impl Decode for DigestItem { +impl Decode for DigestItem { fn decode(input: &mut I) -> Option { let item_type: DigestItemType = Decode::decode(input)?; match item_type { @@ -170,7 +168,7 @@ impl Decode for DigestItem Decode::decode(input)?, )), DigestItemType::Seal => { - let vals: (u64, Signature) = Decode::decode(input)?; + let vals: (u64, SealSignature) = Decode::decode(input)?; Some(DigestItem::Seal(vals.0, vals.1)) }, DigestItemType::Other => Some(DigestItem::Other( @@ -180,7 +178,7 @@ impl Decode for DigestItem } } -impl<'a, Hash: Codec + Member, AuthorityId: Codec + Member> DigestItemRef<'a, Hash, AuthorityId> { +impl<'a, Hash: Codec + Member, AuthorityId: Codec + Member, SealSignature: Codec + Member> DigestItemRef<'a, Hash, AuthorityId, SealSignature> { /// Cast this digest item into `AuthoritiesChange`. pub fn as_authorities_change(&self) -> Option<&'a [AuthorityId]> { match *self { @@ -198,7 +196,7 @@ impl<'a, Hash: Codec + Member, AuthorityId: Codec + Member> DigestItemRef<'a, Ha } } -impl<'a, Hash: Encode, AuthorityId: Encode> Encode for DigestItemRef<'a, Hash, AuthorityId> { +impl<'a, Hash: Encode, AuthorityId: Encode, SealSignature: Encode> Encode for DigestItemRef<'a, Hash, AuthorityId, SealSignature> { fn encode(&self) -> Vec { let mut v = Vec::new(); @@ -228,6 +226,7 @@ impl<'a, Hash: Encode, AuthorityId: Encode> Encode for DigestItemRef<'a, Hash, A #[cfg(test)] mod tests { use super::*; + use substrate_primitives::hash::H512 as Signature; #[test] fn should_serialize_digest() { diff --git a/core/sr-primitives/src/generic/era.rs b/core/sr-primitives/src/generic/era.rs index 9d2fe13793648cdba469a0dc1b3e115a6cf3aefb..037013b4feaa951512eaec7fceb185c3f7d77d75 100644 --- a/core/sr-primitives/src/generic/era.rs +++ b/core/sr-primitives/src/generic/era.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/sr-primitives/src/generic/header.rs b/core/sr-primitives/src/generic/header.rs index 91646e32a48692e27154619e8717e86a92ae4dd9..60ccd93b3ded8ccebeb7f8770d1ca649c4ff5354 100644 --- a/core/sr-primitives/src/generic/header.rs +++ b/core/sr-primitives/src/generic/header.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/sr-primitives/src/generic/mod.rs b/core/sr-primitives/src/generic/mod.rs index 3c21a8232ccf60fbee95060d3d3e3cee24bcdd30..47ce3cb25184f7b2c44d4cb1d4837247d981027f 100644 --- a/core/sr-primitives/src/generic/mod.rs +++ b/core/sr-primitives/src/generic/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/sr-primitives/src/generic/tests.rs b/core/sr-primitives/src/generic/tests.rs index 781f3f6329fc14db91483316a7353967aa806280..91fc8f3faf90486b67174463e2993a73caa10ac9 100644 --- a/core/sr-primitives/src/generic/tests.rs +++ b/core/sr-primitives/src/generic/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -17,12 +17,12 @@ //! Tests for the generic implementations of Extrinsic/Header/Block. use crate::codec::{Decode, Encode}; -use substrate_primitives::H256; +use substrate_primitives::{H256, H512}; use super::DigestItem; #[test] fn system_digest_item_encoding() { - let item = DigestItem::AuthoritiesChange::(vec![10, 20, 30]); + let item = DigestItem::AuthoritiesChange::(vec![10, 20, 30]); let encoded = item.encode(); assert_eq!(encoded, vec![ // type = DigestItemType::AuthoritiesChange @@ -35,13 +35,13 @@ fn system_digest_item_encoding() { 30, 0, 0, 0, ]); - let decoded: DigestItem = Decode::decode(&mut &encoded[..]).unwrap(); + let decoded: DigestItem = Decode::decode(&mut &encoded[..]).unwrap(); assert_eq!(item, decoded); } #[test] fn non_system_digest_item_encoding() { - let item = DigestItem::Other::(vec![10, 20, 30]); + let item = DigestItem::Other::(vec![10, 20, 30]); let encoded = item.encode(); assert_eq!(encoded, vec![ // type = DigestItemType::Other @@ -52,6 +52,6 @@ fn non_system_digest_item_encoding() { 10, 20, 30, ]); - let decoded: DigestItem = Decode::decode(&mut &encoded[..]).unwrap(); + let decoded: DigestItem = Decode::decode(&mut &encoded[..]).unwrap(); assert_eq!(item, decoded); } diff --git a/core/sr-primitives/src/generic/unchecked_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_extrinsic.rs index 25661031e6fd54579010e7683c1da84834c6c4e7..d6e0d60e2c218c255e5da9af987ce08e46b0d1e3 100644 --- a/core/sr-primitives/src/generic/unchecked_extrinsic.rs +++ b/core/sr-primitives/src/generic/unchecked_extrinsic.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -20,7 +20,6 @@ use std::fmt; use rstd::prelude::*; -use parity_codec_derive::{Encode, Decode}; use crate::codec::{Decode, Encode, Codec, Input, HasCompact}; use crate::traits::{self, Member, SimpleArithmetic, MaybeDisplay, Lookup, Extrinsic}; use super::CheckedExtrinsic; diff --git a/core/sr-primitives/src/generic/unchecked_mortal_compact_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_mortal_compact_extrinsic.rs index 3ffe7fae40841260671eca9cd7a5d1d78d5b17e5..243747092c49ca8100b6aa9a8490cb72c3cf775d 100644 --- a/core/sr-primitives/src/generic/unchecked_mortal_compact_extrinsic.rs +++ b/core/sr-primitives/src/generic/unchecked_mortal_compact_extrinsic.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -190,7 +190,7 @@ impl fmt::Debug for UncheckedMortalCompactExtri mod tests { use super::*; use runtime_io::blake2_256; - use parity_codec_derive::{Encode, Decode}; + use crate::codec::{Encode, Decode}; use serde_derive::{Serialize, Deserialize}; struct TestContext; diff --git a/core/sr-primitives/src/generic/unchecked_mortal_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_mortal_extrinsic.rs index 06c9003e3392e9fb7d57f807ba621ae25df50fbd..93eeb55884479281a77071953602553e576e012f 100644 --- a/core/sr-primitives/src/generic/unchecked_mortal_extrinsic.rs +++ b/core/sr-primitives/src/generic/unchecked_mortal_extrinsic.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -189,7 +189,7 @@ impl fmt::Debug for UncheckedMortalExtrinsic, Vec>; - -/// A set of key value pairs for children storage; -#[cfg(feature = "std")] -pub type ChildrenStorageOverlay = HashMap, StorageOverlay>; +pub use serde_derive::{Serialize, Deserialize}; /// Complex storage builder stuff. #[cfg(feature = "std")] -pub trait BuildStorage { +pub trait BuildStorage: Sized { /// Hash given slice. /// /// Default to xx128 hashing. @@ -107,7 +99,14 @@ pub trait BuildStorage { r } /// Build the storage out of this builder. - fn build_storage(self) -> Result<(StorageOverlay, ChildrenStorageOverlay), String>; + fn build_storage(self) -> Result<(StorageOverlay, ChildrenStorageOverlay), String> { + let mut storage = Default::default(); + let mut child_storage = Default::default(); + self.assimilate_storage(&mut storage, &mut child_storage)?; + 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>; } #[cfg(feature = "std")] @@ -115,6 +114,10 @@ impl BuildStorage for StorageOverlay { fn build_storage(self) -> Result<(StorageOverlay, ChildrenStorageOverlay), String> { Ok((self, Default::default())) } + fn assimilate_storage(self, storage: &mut StorageOverlay, _child_storage: &mut ChildrenStorageOverlay) -> Result<(), String> { + storage.extend(self); + Ok(()) + } } /// Permill is parts-per-million (i.e. after multiplying by this, divide by 1000000). @@ -248,55 +251,146 @@ impl From> for Perbill { } } -/// Ed25519 signature verify. -#[derive(Eq, PartialEq, Clone, Default, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] -pub struct Ed25519Signature(pub H512); +/// Perquintill is parts-per-quintillion. It stores a value between 0 and 1 in fixed point and +/// provides a means to multiply some other value by that. +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] +#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq)] +pub struct Perquintill(u64); + +const QUINTILLION: u64 = 1_000_000_000_000_000_000; + +impl Perquintill { + /// Nothing. + pub fn zero() -> Self { Self(0) } + + /// Everything. + pub fn one() -> Self { Self(QUINTILLION) } + + /// Construct new instance where `x` is in quintillionths. Value equivalent to `x / 1,000,000,000,000,000,000`. + pub fn from_quintillionths(x: u64) -> Self { Self(x.min(QUINTILLION)) } + + /// Construct new instance where `x` is in billionths. Value equivalent to `x / 1,000,000,000`. + pub fn from_billionths(x: u64) -> Self { Self(x.min(1_000_000_000) * 1_000_000_000 ) } -impl Verify for Ed25519Signature { - type Signer = H256; - fn verify>(&self, mut msg: L, signer: &Self::Signer) -> bool { - runtime_io::ed25519_verify((self.0).as_fixed_bytes(), msg.get(), &signer.as_bytes()) + /// Construct new instance where `x` is in millionths. Value equivalent to `x / 1,000,000`. + pub fn from_millionths(x: u64) -> Self { Self(x.min(1_000_000) * 1000_000_000_000) } + + /// Construct new instance where `x` is denominator and the nominator is 1. + pub fn from_xth(x: u64) -> Self { Self(QUINTILLION / x.min(QUINTILLION)) } + + #[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) * QUINTILLION as f64) as u64) } +} + +impl ::rstd::ops::Deref for Perquintill { + type Target = u64; + + fn deref(&self) -> &u64 { + &self.0 + } +} + +impl ::rstd::ops::Mul for Perquintill +where + N: traits::As +{ + type Output = N; + fn mul(self, b: N) -> Self::Output { + >::sa(b.as_().saturating_mul(self.0) / QUINTILLION) } } -impl From for Ed25519Signature { - fn from(h: H512) -> Ed25519Signature { - Ed25519Signature(h) +#[cfg(feature = "std")] +impl From for Perquintill { + fn from(x: f64) -> Perquintill { + Perquintill::from_fraction(x) } } -/// Sr25519 signature verify. -#[derive(Eq, PartialEq, Clone, Default, Encode, Decode)] +#[cfg(feature = "std")] +impl From for Perquintill { + fn from(x: f32) -> Perquintill { + Perquintill::from_fraction(x as f64) + } +} + +impl codec::CompactAs for Perquintill { + type As = u64; + fn encode_as(&self) -> &u64 { + &self.0 + } + fn decode_from(x: u64) -> Perquintill { + Perquintill(x) + } +} + +impl From> for Perquintill { + fn from(x: codec::Compact) -> Perquintill { + x.0 + } +} + +/// Signature verify that can work with any known signature types.. +#[derive(Eq, PartialEq, Clone, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Debug))] +pub enum MultiSignature { + /// An Ed25519 signature. + Ed25519(ed25519::Signature), + /// An Sr25519 signature. + Sr25519(sr25519::Signature), +} + +impl Default for MultiSignature { + fn default() -> Self { + MultiSignature::Ed25519(Default::default()) + } +} + +/// Public key for any known crypto algorithm. +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] -pub struct Sr25519Signature(pub H512); +pub enum MultiSigner { + /// An Ed25519 identity. + Ed25519(ed25519::Public), + /// An Sr25519 identity. + Sr25519(sr25519::Public), +} + +impl Default for MultiSigner { + fn default() -> Self { + MultiSigner::Ed25519(Default::default()) + } +} -impl Verify for Sr25519Signature { - type Signer = H256; - fn verify>(&self, mut msg: L, signer: &Self::Signer) -> bool { - runtime_io::sr25519_verify((self.0).as_fixed_bytes(), msg.get(), &signer.as_bytes()) +impl Verify for MultiSignature { + type Signer = MultiSigner; + fn verify>(&self, msg: L, signer: &Self::Signer) -> bool { + match (self, signer) { + (MultiSignature::Ed25519(ref sig), &MultiSigner::Ed25519(ref who)) => sig.verify(msg, who), + (MultiSignature::Sr25519(ref sig), &MultiSigner::Sr25519(ref who)) => sig.verify(msg, who), + _ => false, + } } } -impl From for Sr25519Signature { - fn from(h: H512) -> Sr25519Signature { - Sr25519Signature(h) +/// Signature verify that can work with any known signature types.. +#[derive(Eq, PartialEq, Clone, Default, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] +pub struct AnySignature(H512); + +impl Verify for AnySignature { + type Signer = sr25519::Public; + fn verify>(&self, mut msg: L, signer: &sr25519::Public) -> bool { + runtime_io::sr25519_verify(self.0.as_fixed_bytes(), msg.get(), &signer.0) || + runtime_io::ed25519_verify(self.0.as_fixed_bytes(), msg.get(), &signer.0) } } -/// Context for executing a call into the runtime. -#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug, Serialize))] -#[repr(u8)] -pub enum ExecutionContext { - /// Context for general importing (including own blocks). - Importing, - /// Context used when syncing the blockchain. - Syncing, - /// Context used for block construction. - BlockConstruction, - /// Context used for other calls. - Other, +impl From for AnySignature { + fn from(s: sr25519::Signature) -> AnySignature { + AnySignature(s.0.into()) + } } #[derive(Eq, PartialEq, Clone, Copy, Decode)] @@ -369,6 +463,13 @@ pub fn verify_encoded_lazy(sig: &V, item: &T, signe /// Helper macro for `impl_outer_config` #[macro_export] macro_rules! __impl_outer_config_types { + ( + $concrete:ident $config:ident $snake:ident < $ignore:ident, $instance:path > $( $rest:tt )* + ) => { + #[cfg(any(feature = "std", test))] + pub type $config = $snake::GenesisConfig<$concrete, $instance>; + $crate::__impl_outer_config_types! {$concrete $($rest)*} + }; ( $concrete:ident $config:ident $snake:ident < $ignore:ident > $( $rest:tt )* ) => { @@ -396,12 +497,12 @@ macro_rules! __impl_outer_config_types { macro_rules! impl_outer_config { ( pub struct $main:ident for $concrete:ident { - $( $config:ident => $snake:ident $( < $generic:ident > )*, )* + $( $config:ident => $snake:ident $( < $generic:ident $(, $instance:path)? > )*, )* } ) => { - $crate::__impl_outer_config_types! { $concrete $( $config $snake $( < $generic > )* )* } + $crate::__impl_outer_config_types! { $concrete $( $config $snake $( < $generic $(, $instance)? > )* )* } #[cfg(any(feature = "std", test))] - #[derive(Serialize, Deserialize)] + #[derive($crate::serde_derive::Serialize, $crate::serde_derive::Deserialize)] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] pub struct $main { @@ -411,19 +512,13 @@ macro_rules! impl_outer_config { } #[cfg(any(feature = "std", test))] impl $crate::BuildStorage for $main { - fn build_storage(self) -> ::std::result::Result<($crate::StorageOverlay, $crate::ChildrenStorageOverlay), String> { - let mut top = $crate::StorageOverlay::new(); - let mut children = $crate::ChildrenStorageOverlay::new(); + fn assimilate_storage(self, top: &mut $crate::StorageOverlay, children: &mut $crate::ChildrenStorageOverlay) -> ::std::result::Result<(), String> { $( if let Some(extra) = self.$snake { - let (other_top, other_children) = extra.build_storage()?; - top.extend(other_top); - for (other_child_key, other_child_map) in other_children { - children.entry(other_child_key).or_default().extend(other_child_map); - } + extra.assimilate_storage(top, children)?; } )* - Ok((top, children)) + Ok(()) } } } @@ -449,7 +544,7 @@ macro_rules! impl_outer_log { ( $(#[$attr:meta])* pub enum $name:ident ($internal:ident: DigestItem<$( $genarg:ty ),*>) for $trait:ident { - $( $module:ident( $( $sitem:ident ),* ) ),* + $( $module:ident $(<$instance:path>)? ( $( $sitem:ident ),* ) ),* } ) => { /// Wrapper for all possible log entries for the `$trait` runtime. Provides binary-compatible @@ -462,13 +557,13 @@ macro_rules! impl_outer_log { /// All possible log entries for the `$trait` runtime. `Encode`/`Decode` implementations /// are auto-generated => it is not binary-compatible with `generic::DigestItem`. - #[derive(Clone, PartialEq, Eq, Encode, Decode)] + #[derive(Clone, PartialEq, Eq, $crate::codec::Encode, $crate::codec::Decode)] #[cfg_attr(feature = "std", derive(Debug, $crate::serde_derive::Serialize))] $(#[$attr])* #[allow(non_camel_case_types)] pub enum InternalLog { $( - $module($module::Log<$trait>), + $module($module::Log<$trait $(, $instance)? >), )* } @@ -523,7 +618,7 @@ macro_rules! impl_outer_log { } impl $crate::codec::Decode for $name { - /// `generic::DigestItem` binray compatible decode. + /// `generic::DigestItem` binary compatible decode. fn decode(input: &mut I) -> Option { let gen: $crate::generic::DigestItem<$($genarg),*> = $crate::codec::Decode::decode(input)?; @@ -532,7 +627,7 @@ macro_rules! impl_outer_log { } impl $crate::codec::Encode for $name { - /// `generic::DigestItem` binray compatible encode. + /// `generic::DigestItem` binary compatible encode. fn encode(&self) -> Vec { match self.dref() { Some(dref) => dref.encode(), @@ -546,16 +641,16 @@ macro_rules! impl_outer_log { } $( - impl From<$module::Log<$trait>> for $name { + impl From<$module::Log<$trait $(, $instance)? >> for $name { /// Converts single module log item into `$name`. - fn from(x: $module::Log<$trait>) -> Self { + fn from(x: $module::Log<$trait $(, $instance)? >) -> Self { $name(x.into()) } } - impl From<$module::Log<$trait>> for InternalLog { + impl From<$module::Log<$trait $(, $instance)? >> for InternalLog { /// Converts single module log item into `$internal`. - fn from(x: $module::Log<$trait>) -> Self { + fn from(x: $module::Log<$trait $(, $instance)? >) -> Self { InternalLog::$module(x) } } @@ -563,12 +658,18 @@ macro_rules! impl_outer_log { }; } -/// Simple blob to hold an extrinsic without commiting to its format and ensure it is serialized +/// Simple blob to hold an extrinsic without committing to its format and ensure it is serialized /// correctly. #[derive(PartialEq, Eq, Clone, Default, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] pub struct OpaqueExtrinsic(pub Vec); +#[cfg(feature = "std")] +impl std::fmt::Debug for OpaqueExtrinsic { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(fmt, "{}", substrate_primitives::hexdisplay::HexDisplay::from(&self.0)) + } +} + #[cfg(feature = "std")] impl ::serde::Serialize for OpaqueExtrinsic { fn serialize(&self, seq: S) -> Result where S: ::serde::Serializer { @@ -584,9 +685,8 @@ impl traits::Extrinsic for OpaqueExtrinsic { #[cfg(test)] mod tests { - use substrate_primitives::hash::H256; - use crate::codec::{Encode as EncodeHidden, Decode as DecodeHidden}; - use parity_codec_derive::{Encode, Decode}; + use substrate_primitives::hash::{H256, H512}; + use crate::codec::{Encode, Decode}; use crate::traits::DigestItem; pub trait RuntimeT { @@ -601,7 +701,7 @@ mod tests { mod a { use super::RuntimeT; - use parity_codec_derive::{Encode, Decode}; + use crate::codec::{Encode, Decode}; use serde_derive::Serialize; pub type Log = RawLog<::AuthorityId>; @@ -611,7 +711,7 @@ mod tests { mod b { use super::RuntimeT; - use parity_codec_derive::{Encode, Decode}; + use crate::codec::{Encode, Decode}; use serde_derive::Serialize; pub type Log = RawLog<::AuthorityId>; @@ -620,7 +720,7 @@ mod tests { } impl_outer_log! { - pub enum Log(InternalLog: DigestItem) for Runtime { + pub enum Log(InternalLog: DigestItem) for Runtime { a(AuthoritiesChange), b() } } @@ -630,26 +730,26 @@ mod tests { // encode/decode regular item let b1: Log = b::RawLog::B1::(777).into(); let encoded_b1 = b1.encode(); - let decoded_b1: Log = DecodeHidden::decode(&mut &encoded_b1[..]).unwrap(); + let decoded_b1: Log = Decode::decode(&mut &encoded_b1[..]).unwrap(); assert_eq!(b1, decoded_b1); // encode/decode system item let auth_change: Log = a::RawLog::AuthoritiesChange::(vec![100, 200, 300]).into(); let encoded_auth_change = auth_change.encode(); - let decoded_auth_change: Log = DecodeHidden::decode(&mut &encoded_auth_change[..]).unwrap(); + let decoded_auth_change: Log = Decode::decode(&mut &encoded_auth_change[..]).unwrap(); assert_eq!(auth_change, decoded_auth_change); // interpret regular item using `generic::DigestItem` - let generic_b1: super::generic::DigestItem = DecodeHidden::decode(&mut &encoded_b1[..]).unwrap(); + let generic_b1: super::generic::DigestItem = Decode::decode(&mut &encoded_b1[..]).unwrap(); match generic_b1 { super::generic::DigestItem::Other(_) => (), _ => panic!("unexpected generic_b1: {:?}", generic_b1), } // interpret system item using `generic::DigestItem` - let generic_auth_change: super::generic::DigestItem = DecodeHidden::decode(&mut &encoded_auth_change[..]).unwrap(); + let generic_auth_change: super::generic::DigestItem = Decode::decode(&mut &encoded_auth_change[..]).unwrap(); match generic_auth_change { - super::generic::DigestItem::AuthoritiesChange::(authorities) => assert_eq!(authorities, vec![100, 200, 300]), + super::generic::DigestItem::AuthoritiesChange::(authorities) => assert_eq!(authorities, vec![100, 200, 300]), _ => panic!("unexpected generic_auth_change: {:?}", generic_auth_change), } diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index b854ca317a0fc1519b1904799d16041568ef7fd5..2711c0e623d62a171f249ab8adbe9bb998a77e07 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -24,31 +24,30 @@ use std::{fmt::Debug, ops::Deref, fmt}; use crate::codec::{Codec, Encode, Decode}; use crate::traits::{self, Checkable, Applyable, BlakeTwo256, Convert}; use crate::generic::DigestItem as GenDigestItem; -use parity_codec_derive::{Encode, Decode}; - -pub use substrate_primitives::{H256, Ed25519AuthorityId}; +pub use substrate_primitives::H256; use substrate_primitives::U256; +use substrate_primitives::ed25519::{Public as AuthorityId, Signature as AuthoritySignature}; /// Authority Id -#[derive(Default, PartialEq, Eq, Clone, Decode, Encode, Debug)] +#[derive(Default, PartialEq, Eq, Clone, Encode, Decode, Debug)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct UintAuthorityId(pub u64); -impl Into for UintAuthorityId { - fn into(self) -> Ed25519AuthorityId { +impl Into for UintAuthorityId { + fn into(self) -> AuthorityId { let bytes: [u8; 32] = U256::from(self.0).into(); - Ed25519AuthorityId(bytes) + AuthorityId(bytes) } } /// Converter between u64 and the AuthorityId wrapper type. pub struct ConvertUintAuthorityId; -impl Convert for ConvertUintAuthorityId { - fn convert(a: u64) -> UintAuthorityId { - UintAuthorityId(a) +impl Convert> for ConvertUintAuthorityId { + fn convert(a: u64) -> Option { + Some(UintAuthorityId(a)) } } /// Digest item -pub type DigestItem = GenDigestItem; +pub type DigestItem = GenDigestItem; /// Header Digest #[derive(Default, PartialEq, Eq, Clone, Serialize, Debug, Encode, Decode)] diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index 5e12d571ae2013ba4fe62e87c8ac427d61d305a1..ef3f133df6b85e01388ad4e8826fac591f0c48c6 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -23,13 +23,12 @@ use runtime_io; #[cfg(feature = "std")] use serde::{Serialize, de::DeserializeOwned}; #[cfg(feature = "std")] use serde_derive::{Serialize, Deserialize}; -use substrate_primitives; -use substrate_primitives::Blake2Hasher; +use substrate_primitives::{self, Hasher, Blake2Hasher}; use crate::codec::{Codec, Encode, HasCompact}; pub use integer_sqrt::IntegerSquareRoot; -pub use num_traits::{Zero, One, Bounded}; -pub use num_traits::ops::checked::{ - CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, CheckedShl, CheckedShr, +pub use num_traits::{ + Zero, One, Bounded, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, + CheckedShl, CheckedShr, Saturating }; use rstd::ops::{ Add, Sub, Mul, Div, Rem, AddAssign, SubAssign, MulAssign, DivAssign, @@ -56,6 +55,20 @@ pub trait Verify { fn verify>(&self, msg: L, signer: &Self::Signer) -> bool; } +impl Verify for substrate_primitives::ed25519::Signature { + type Signer = substrate_primitives::ed25519::Public; + fn verify>(&self, mut msg: L, signer: &Self::Signer) -> bool { + runtime_io::ed25519_verify(self.as_ref(), msg.get(), signer) + } +} + +impl Verify for substrate_primitives::sr25519::Signature { + type Signer = substrate_primitives::sr25519::Public; + fn verify>(&self, mut msg: L, signer: &Self::Signer) -> bool { + runtime_io::sr25519_verify(self.as_ref(), msg.get(), signer) + } +} + /// Some sort of check on the origin is performed by this object. pub trait EnsureOrigin { /// A return type. @@ -84,6 +97,8 @@ pub trait StaticLookup { type Target; /// Attempt a lookup. fn lookup(s: Self::Source) -> result::Result; + /// Convert from Target back to Source. + fn unlookup(t: Self::Target) -> Self::Source; } /// A lookup implementation returning the input value. @@ -93,6 +108,7 @@ impl StaticLookup for IdentityLookup< type Source = T; type Target = T; fn lookup(x: T) -> result::Result { Ok(x) } + fn unlookup(x: T) -> T { x } } impl Lookup for IdentityLookup { type Source = T; @@ -126,65 +142,22 @@ pub trait BlockNumberToHash { } } -/// Charge bytes fee trait -pub trait ChargeBytesFee { - /// Charge fees from `transactor` for an extrinsic (transaction) of encoded length - /// `encoded_len` bytes. Return Ok iff the payment was successful. - fn charge_base_bytes_fee(transactor: &AccountId, encoded_len: usize) -> Result<(), &'static str>; -} - -/// Charge fee trait -pub trait ChargeFee: ChargeBytesFee { - /// The type of fee amount. - type Amount; - - /// Charge `amount` of fees from `transactor`. Return Ok iff the payment was successful. - fn charge_fee(transactor: &AccountId, amount: Self::Amount) -> Result<(), &'static str>; - - /// Refund `amount` of previous charged fees from `transactor`. Return Ok iff the refund was successful. - fn refund_fee(transactor: &AccountId, amount: Self::Amount) -> Result<(), &'static str>; -} - -/// Transfer fungible asset trait -pub trait TransferAsset { - /// The type of asset amount. - type Amount; - - /// Transfer asset from `from` account to `to` account with `amount` of asset. - fn transfer(from: &AccountId, to: &AccountId, amount: Self::Amount) -> Result<(), &'static str>; - - /// Remove asset from `who` account by deducing `amount` in the account balances. - fn remove_from(who: &AccountId, amount: Self::Amount) -> Result<(), &'static str>; - - /// Add asset to `who` account by increasing `amount` in the account balances. - fn add_to(who: &AccountId, amount: Self::Amount) -> Result<(), &'static str>; -} - -impl ChargeBytesFee for () { - fn charge_base_bytes_fee(_: &T, _: usize) -> Result<(), &'static str> { Ok(()) } -} - -impl ChargeFee for () { - type Amount = (); - - fn charge_fee(_: &T, _: Self::Amount) -> Result<(), &'static str> { Ok(()) } - fn refund_fee(_: &T, _: Self::Amount) -> Result<(), &'static str> { Ok(()) } -} - -impl TransferAsset for () { - type Amount = (); - - fn transfer(_: &T, _: &T, _: Self::Amount) -> Result<(), &'static str> { Ok(()) } - fn remove_from(_: &T, _: Self::Amount) -> Result<(), &'static str> { Ok(()) } - fn add_to(_: &T, _: Self::Amount) -> Result<(), &'static str> { Ok(()) } -} - /// Extensible conversion trait. Generic over both source and destination types. pub trait Convert { /// Make conversion. fn convert(a: A) -> B; } +impl Convert for () { + fn convert(_: A) -> B { Default::default() } +} + +/// A structure that performs identity conversion. +pub struct Identity; +impl Convert for Identity { + fn convert(a: T) -> T { a } +} + /// Simple trait similar to `Into`, except that it can be used to convert numerics between each /// other. pub trait As { @@ -212,15 +185,6 @@ macro_rules! impl_numerics { impl_numerics!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); -/// A structure that performs identity conversion. -pub struct Identity; -impl Convert for Identity { - fn convert(a: T) -> T { a } -} -impl Convert for () { - fn convert(_: T) -> () { () } -} - /// A meta trait for arithmetic. pub trait SimpleArithmetic: Zero + One + IntegerSquareRoot + As + @@ -236,7 +200,8 @@ pub trait SimpleArithmetic: CheckedSub + CheckedMul + CheckedDiv + - PartialOrd + Ord + + Saturating + + PartialOrd + Ord + Bounded + HasCompact {} impl + Ord + + Saturating + + PartialOrd + Ord + Bounded + HasCompact > SimpleArithmetic for T {} @@ -304,6 +270,24 @@ pub trait OnInitialise { impl OnInitialise for () {} +/// Off-chain computation trait. +/// +/// Implementing this trait on a module allows you to perform a long-running tasks +/// that make validators generate extrinsics (either transactions or inherents) +/// with results of those long-running computations. +/// +/// NOTE: This function runs off-chain, so it can access the block state, +/// but cannot preform any alterations. +pub trait OffchainWorker { + /// This function is being called on every block. + /// + /// Implement this and use special `extern`s to generate transactions or inherents. + /// Any state alterations are lost and are not persisted. + fn generate_extrinsics(_n: BlockNumber) {} +} + +impl OffchainWorker for () {} + macro_rules! tuple_impl { ($one:ident,) => { impl> OnFinalise for ($one,) { @@ -316,6 +300,11 @@ macro_rules! tuple_impl { $one::on_initialise(n); } } + impl> OffchainWorker for ($one,) { + fn generate_extrinsics(n: Number) { + $one::generate_extrinsics(n); + } + } }; ($first:ident, $($rest:ident,)+) => { impl< @@ -338,6 +327,16 @@ macro_rules! tuple_impl { $($rest::on_initialise(n);)+ } } + impl< + Number: Copy, + $first: OffchainWorker, + $($rest: OffchainWorker),+ + > OffchainWorker for ($first, $($rest),+) { + fn generate_extrinsics(n: Number) { + $first::generate_extrinsics(n); + $($rest::generate_extrinsics(n);)+ + } + } tuple_impl!($($rest,)+); } } @@ -349,7 +348,10 @@ tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, pub trait Hash: 'static + MaybeSerializeDebug + Clone + Eq + PartialEq { // Stupid bug in the Rust compiler believes derived // traits must be fulfilled by all type parameters. /// The hash type produced. - type Output: Member + MaybeSerializeDebug + AsRef<[u8]> + AsMut<[u8]>; + type Output: Member + MaybeSerializeDebug + rstd::hash::Hash + AsRef<[u8]> + AsMut<[u8]> + Copy + Default; + + /// The associated hash_db Hasher type. + type Hasher: Hasher; /// Produce the hash of some byte-slice. fn hash(s: &[u8]) -> Self::Output; @@ -389,6 +391,7 @@ pub struct BlakeTwo256; impl Hash for BlakeTwo256 { type Output = substrate_primitives::H256; + type Hasher = Blake2Hasher; fn hash(s: &[u8]) -> Self::Output { runtime_io::blake2_256(s).into() } @@ -531,6 +534,7 @@ pub trait MaybeHash {} #[cfg(not(feature = "std"))] impl MaybeHash for T {} + /// A type that can be used in runtime structures. pub trait Member: Send + Sync + Sized + MaybeDebug + Eq + PartialEq + Clone + 'static {} impl Member for T {} diff --git a/core/sr-primitives/src/transaction_validity.rs b/core/sr-primitives/src/transaction_validity.rs index 472cc198fd6cca2977fffdc9e895afa4126b2e2f..7cf3aa1d6d6a1bb62f1f94a90ff523c48bdb4a28 100644 --- a/core/sr-primitives/src/transaction_validity.rs +++ b/core/sr-primitives/src/transaction_validity.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Transaction validity interface. use rstd::prelude::*; -use parity_codec_derive::{Encode, Decode}; +use crate::codec::{Encode, Decode}; /// Priority for a transaction. Additive. Higher is better. pub type TransactionPriority = u64; diff --git a/core/sr-sandbox/Cargo.toml b/core/sr-sandbox/Cargo.toml index b48744240e6cae4e98f60e647270669d8fb6fad2..599e66d6638b1b899619c3b9a175d2343544a5b9 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.0", default-features = false } +codec = { package = "parity-codec", version = "3.2", 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 8054e44ba94e437279452c6900e614a71d1d79da..e8bdd5727ea8795ea16efeae71426aecc014e73f 100755 --- a/core/sr-sandbox/src/lib.rs +++ b/core/sr-sandbox/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -140,7 +140,7 @@ impl EnvironmentDefinitionBuilder { } } - /// Register a host function in this environment defintion. + /// Register a host function in this environment definition. /// /// NOTE that there is no constraints on type of this function. An instance /// can import function passed here with any signature it wants. It can even import diff --git a/core/sr-sandbox/with_std.rs b/core/sr-sandbox/with_std.rs index 038ecc023c98a3951ec566c823e696c0d7f84301..ea7ce818350d082030c3660ef8408a73cfa1db2c 100755 --- a/core/sr-sandbox/with_std.rs +++ b/core/sr-sandbox/with_std.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/sr-sandbox/without_std.rs b/core/sr-sandbox/without_std.rs index d75168f1b06e3496af1f51ad2be2c714e359fc7e..070ca1ddf15cfd9f08e9275f57cea6567c8b3e11 100755 --- a/core/sr-sandbox/without_std.rs +++ b/core/sr-sandbox/without_std.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/sr-std/src/lib.rs b/core/sr-std/src/lib.rs index c00f26703825deecb68fcfcc58d31804096d4d81..45857b33eda784a3107bc162a3c12c1b610d0342 100644 --- a/core/sr-std/src/lib.rs +++ b/core/sr-std/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/sr-std/with_std.rs b/core/sr-std/with_std.rs index 3c0df0ce9305af0daf8f98f3ce87a3efa5adef18..9d8a7342f38221b95a21ef4b534756c1a5e8bcc1 100644 --- a/core/sr-std/with_std.rs +++ b/core/sr-std/with_std.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/sr-std/without_std.rs b/core/sr-std/without_std.rs index 05bfab91e97c2dd4cd55c0c53fafe7bdf8ce9f8e..b9287c00d5743d41cacaa7c93c1b1c89a9f91e58 100644 --- a/core/sr-std/without_std.rs +++ b/core/sr-std/without_std.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/sr-version/Cargo.toml b/core/sr-version/Cargo.toml index 6c4bbccf9f360d9187fc50e169011293b2cfdb37..cf3062faac01b7ffd0316e81324b1f39c926b1c3 100644 --- a/core/sr-version/Cargo.toml +++ b/core/sr-version/Cargo.toml @@ -6,10 +6,9 @@ edition = "2018" [dependencies] impl-serde = { version = "0.1", optional = true } -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", 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 } @@ -17,7 +16,7 @@ runtime_primitives = { package = "sr-primitives", path = "../sr-primitives", def default = ["std"] std = [ "impl-serde", - "serde/std", + "serde", "serde_derive", "parity-codec/std", "rstd/std", diff --git a/core/sr-version/src/lib.rs b/core/sr-version/src/lib.rs index 6d16f2e47c151ebb3959c376f7c6189df3d3d4d6..71a4c5149d393faac9b139aee3fa23e89f756b91 100644 --- a/core/sr-version/src/lib.rs +++ b/core/sr-version/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -27,6 +27,9 @@ use std::collections::HashSet; #[cfg(feature = "std")] use runtime_primitives::traits::RuntimeApiInfo; +use parity_codec::Encode; +#[cfg(feature = "std")] +use parity_codec::Decode; use runtime_primitives::RuntimeString; pub use runtime_primitives::create_runtime_str; @@ -59,8 +62,8 @@ macro_rules! create_apis_vec { /// This triplet have different semantics and mis-interpretation could cause problems. /// In particular: bug fixes should result in an increment of `spec_version` and possibly `authoring_version`, /// absolutely not `impl_version` since they change the semantics of the runtime. -#[derive(Clone, PartialEq, Eq, parity_codec_derive::Encode)] -#[cfg_attr(feature = "std", derive(Debug, Serialize, parity_codec_derive::Decode))] +#[derive(Clone, PartialEq, Eq, Encode)] +#[cfg_attr(feature = "std", derive(Debug, Serialize, Decode))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] pub struct RuntimeVersion { /// Identifies the different Substrate runtimes. There'll be at least polkadot and node. diff --git a/core/state-db/Cargo.toml b/core/state-db/Cargo.toml index 78e3821caedbc5e80b6564148d09d3349af529c1..28d5696928ef5bf99bc353e86111b0221a1ac2c8 100644 --- a/core/state-db/Cargo.toml +++ b/core/state-db/Cargo.toml @@ -8,8 +8,7 @@ edition = "2018" parking_lot = "0.7.1" log = "0.4" primitives = { package = "substrate-primitives", path = "../../core/primitives" } -parity-codec = "3.0" -parity-codec-derive = "3.0" +parity-codec = { version = "3.2", features = ["derive"] } [dev-dependencies] env_logger = "0.6" diff --git a/core/state-db/src/lib.rs b/core/state-db/src/lib.rs index a9df4e80cac5e9ac1bab2ba220a6f497b6ff90b7..8d9cf9c965f5a21d1a9b0064de4c5ce1dc846055 100644 --- a/core/state-db/src/lib.rs +++ b/core/state-db/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -58,12 +58,12 @@ pub trait MetaDb { } /// Backend database trait. Read-only. -pub trait HashDb { - type Hash: Hash; +pub trait NodeDb { + type Key: ?Sized; type Error: fmt::Debug; /// Get state trie node. - fn get(&self, key: &Self::Hash) -> Result, Self::Error>; + fn get(&self, key: &Self::Key) -> Result, Self::Error>; } /// Error type. @@ -285,11 +285,13 @@ impl StateDbSync { self.pinned.remove(hash); } - pub fn get>(&self, key: &Key, db: &D) -> Result, Error> { + pub fn get(&self, key: &Key, db: &D) -> Result, Error> + where Key: AsRef + { if let Some(value) = self.non_canonical.get(key) { return Ok(Some(value)); } - db.get(key).map_err(|e| Error::Db(e)) + db.get(key.as_ref()).map_err(|e| Error::Db(e)) } pub fn apply_pending(&mut self) { @@ -349,7 +351,9 @@ impl StateDb { } /// Get a value from non-canonical/pruning overlay or the backing DB. - pub fn get>(&self, key: &Key, db: &D) -> Result, Error> { + pub fn get(&self, key: &Key, db: &D) -> Result, Error> + where Key: AsRef + { self.db.read().get(key, db) } diff --git a/core/state-db/src/noncanonical.rs b/core/state-db/src/noncanonical.rs index 78a958b06608307d298f163286a1bf79136e1f37..da957335ba30f4e7d59e5fe7f5eda6613b9943d7 100644 --- a/core/state-db/src/noncanonical.rs +++ b/core/state-db/src/noncanonical.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -23,8 +23,7 @@ use std::fmt; use std::collections::{HashMap, VecDeque, hash_map::Entry}; use super::{Error, DBValue, ChangeSet, CommitSet, MetaDb, Hash, to_meta_key}; -use crate::codec::{Decode, Encode}; -use parity_codec_derive::{Decode, Encode}; +use crate::codec::{Encode, Decode}; use log::trace; const NON_CANONICAL_JOURNAL: &[u8] = b"noncanonical_journal"; diff --git a/core/state-db/src/pruning.rs b/core/state-db/src/pruning.rs index 83cd51b70b4d2f2ce01295243d7ca80ea9aa2dee..078745c7a264464b4ed58fb3ac3c90224602a9bd 100644 --- a/core/state-db/src/pruning.rs +++ b/core/state-db/src/pruning.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -23,10 +23,8 @@ //! The changes are journaled in the DB. use std::collections::{HashMap, HashSet, VecDeque}; -use std::mem; use crate::codec::{Encode, Decode}; use crate::{CommitSet, Error, MetaDb, to_meta_key, Hash}; -use parity_codec_derive::{Encode, Decode}; use log::{trace, warn}; const LAST_PRUNED: &[u8] = b"last_pruned"; @@ -34,10 +32,17 @@ const PRUNING_JOURNAL: &[u8] = b"pruning_journal"; /// See module documentation. pub struct RefWindow { + /// A queue of keys that should be deleted for each block in the pruning window. death_rows: VecDeque>, + /// An index that maps each key from `death_rows` to block number. death_index: HashMap, + /// Block number that corresponts to the front of `death_rows` pending_number: u64, - pending_records: Vec<(u64, JournalRecord)>, + /// Number of call of `note_canonical` after + /// last call `apply_pending` or `revert_pending` + pending_canonicalizations: usize, + /// Number of calls of `prune_one` after + /// last call `apply_pending` or `revert_pending` pending_prunings: usize, } @@ -72,7 +77,7 @@ impl RefWindow { death_rows: Default::default(), death_index: Default::default(), pending_number: pending_number, - pending_records: Default::default(), + pending_canonicalizations: 0, pending_prunings: 0, }; // read the journal @@ -115,7 +120,7 @@ impl RefWindow { } pub fn window_size(&self) -> u64 { - (self.death_rows.len() + self.pending_records.len() - self.pending_prunings) as u64 + (self.death_rows.len() - self.pending_prunings) as u64 } pub fn next_hash(&self) -> Option { @@ -131,8 +136,7 @@ impl RefWindow { } pub fn have_block(&self, hash: &BlockHash) -> bool { - self.death_rows.iter().skip(self.pending_prunings).any(|r| r.hash == *hash) || - self.pending_records.iter().any(|(_, record)| record.hash == *hash) + self.death_rows.iter().skip(self.pending_prunings).any(|r| r.hash == *hash) } /// Prune next block. Expects at least one block in the window. Adds changes to `commit`. @@ -144,13 +148,6 @@ impl RefWindow { commit.meta.inserted.push((to_meta_key(LAST_PRUNED, &()), index.encode())); commit.meta.deleted.push(pruned.journal_key.clone()); self.pending_prunings += 1; - } else if let Some((block, pruned)) = self.pending_records.get(self.pending_prunings - self.death_rows.len()) { - trace!(target: "state-db", "Pruning pending{:?} ({} deleted)", pruned.hash, pruned.deleted.len()); - commit.data.deleted.extend(pruned.deleted.iter().cloned()); - commit.meta.inserted.push((to_meta_key(LAST_PRUNED, &()), block.encode())); - let journal_key = to_journal_key(*block); - commit.meta.deleted.push(journal_key); - self.pending_prunings += 1; } else { warn!(target: "state-db", "Trying to prune when there's nothing to prune"); } @@ -166,21 +163,16 @@ impl RefWindow { inserted, deleted, }; - // Calculate pending block number taking pending canonicalizations into account, but not pending prunings - // as these are always applied last. - let block = self.pending_number + (self.death_rows.len() + self.pending_records.len()) as u64; + let block = self.pending_number + self.death_rows.len() as u64; let journal_key = to_journal_key(block); commit.meta.inserted.push((journal_key.clone(), journal_record.encode())); - self.pending_records.push((block, journal_record)); + self.import(&journal_record.hash, journal_key, journal_record.inserted.into_iter(), journal_record.deleted); + self.pending_canonicalizations += 1; } /// Apply all pending changes pub fn apply_pending(&mut self) { - for (block, journal_record) in mem::replace(&mut self.pending_records, Default::default()).into_iter() { - trace!(target: "state-db", "Applying pruning window record: {}: {:?}", block, journal_record.hash); - let journal_key = to_journal_key(block); - self.import(&journal_record.hash, journal_key, journal_record.inserted.into_iter(), journal_record.deleted); - } + self.pending_canonicalizations = 0; for _ in 0 .. self.pending_prunings { let pruned = self.death_rows.pop_front().expect("pending_prunings is always < death_rows.len()"); trace!(target: "state-db", "Applying pruning {:?} ({} deleted)", pruned.hash, pruned.deleted.len()); @@ -194,7 +186,14 @@ impl RefWindow { /// Revert all pending changes pub fn revert_pending(&mut self) { - self.pending_records.clear(); + // Revert pending deletions. + // Note that pending insertions might cause some existing deletions to be removed from `death_index` + // We don't bother to track and revert that for now. This means that a few nodes might end up no being + // deleted in case transaction fails and `revert_pending` is called. + self.death_rows.truncate(self.death_rows.len() - self.pending_canonicalizations); + let new_max_block = self.death_rows.len() as u64 + self.pending_number; + self.death_index.retain(|_, block| *block < new_max_block); + self.pending_canonicalizations = 0; self.pending_prunings = 0; } } @@ -232,7 +231,7 @@ mod tests { assert!(pruning.death_rows.is_empty()); assert!(pruning.death_index.is_empty()); assert!(pruning.pending_prunings == 0); - assert!(pruning.pending_records.is_empty()); + assert!(pruning.pending_canonicalizations == 0); } #[test] @@ -347,4 +346,34 @@ mod tests { pruning.apply_pending(); assert_eq!(pruning.pending_number, 3); } + + #[test] + fn reinserted_survivew_pending() { + let mut db = make_db(&[1, 2, 3]); + let mut pruning: RefWindow = RefWindow::new(&db).unwrap(); + let mut commit = make_commit(&[], &[2]); + pruning.note_canonical(&H256::random(), &mut commit); + db.commit(&commit); + let mut commit = make_commit(&[2], &[]); + pruning.note_canonical(&H256::random(), &mut commit); + db.commit(&commit); + let mut commit = make_commit(&[], &[2]); + pruning.note_canonical(&H256::random(), &mut commit); + db.commit(&commit); + assert!(db.data_eq(&make_db(&[1, 2, 3]))); + + let mut commit = CommitSet::default(); + pruning.prune_one(&mut commit); + db.commit(&commit); + assert!(db.data_eq(&make_db(&[1, 2, 3]))); + let mut commit = CommitSet::default(); + pruning.prune_one(&mut commit); + db.commit(&commit); + assert!(db.data_eq(&make_db(&[1, 2, 3]))); + pruning.prune_one(&mut commit); + db.commit(&commit); + assert!(db.data_eq(&make_db(&[1, 3]))); + pruning.apply_pending(); + assert_eq!(pruning.pending_number, 3); + } } diff --git a/core/state-db/src/test.rs b/core/state-db/src/test.rs index 871750d0c8b75d3f64b8e7f0c2d6b4d3079e6b2d..d90c36990612ed8ec059fafc4e5475510784f901 100644 --- a/core/state-db/src/test.rs +++ b/core/state-db/src/test.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -18,7 +18,7 @@ use std::collections::HashMap; use primitives::H256; -use crate::{DBValue, ChangeSet, CommitSet, MetaDb, HashDb}; +use crate::{DBValue, ChangeSet, CommitSet, MetaDb, NodeDb}; #[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct TestDb { @@ -34,9 +34,9 @@ impl MetaDb for TestDb { } } -impl HashDb for TestDb { +impl NodeDb for TestDb { type Error = (); - type Hash = H256; + type Key = H256; fn get(&self, key: &H256) -> Result, ()> { Ok(self.data.get(key).cloned()) diff --git a/core/state-machine/Cargo.toml b/core/state-machine/Cargo.toml index 197b601d1f1ea2a26f5ef9ef6d4f8623740bd5c9..d81079b5f9c39a00055ac4e671587588f59c5622 100644 --- a/core/state-machine/Cargo.toml +++ b/core/state-machine/Cargo.toml @@ -10,10 +10,10 @@ hex-literal = "0.1.0" log = "0.4" parking_lot = "0.7.1" heapsize = "0.4" -hash-db = "0.11" -trie-db = "0.11" -trie-root = "0.11" +hash-db = "0.12" +trie-db = "0.12" +trie-root = "0.12" trie = { package = "substrate-trie", path = "../trie" } primitives = { package = "substrate-primitives", path = "../primitives" } panic-handler = { package = "substrate-panic-handler", path = "../panic-handler" } -parity-codec = "3.0" +parity-codec = "3.2" diff --git a/core/state-machine/src/backend.rs b/core/state-machine/src/backend.rs index 29562f1d26dc35c7aea0a4a0ee6abcda2861b193..14e60b140a0e8a0ea8224f15c0371b70608c84f4 100644 --- a/core/state-machine/src/backend.rs +++ b/core/state-machine/src/backend.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -112,9 +112,9 @@ impl Consolidate for Vec<(Option>, Vec, Option>)> { } } -impl Consolidate for MemoryDB { +impl> Consolidate for trie::GenericMemoryDB { fn consolidate(&mut self, other: Self) { - MemoryDB::consolidate(self, other) + trie::GenericMemoryDB::consolidate(self, other) } } diff --git a/core/state-machine/src/basic.rs b/core/state-machine/src/basic.rs new file mode 100644 index 0000000000000000000000000000000000000000..7b2a95464e653e61cd8f010748b127ee92e6bd83 --- /dev/null +++ b/core/state-machine/src/basic.rs @@ -0,0 +1,189 @@ +// 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 . + +//! Basic implementation for Externalities. + +use std::collections::HashMap; +use std::iter::FromIterator; +use hash_db::Hasher; +use heapsize::HeapSizeOf; +use trie::trie_root; +use primitives::storage::well_known_keys::{CHANGES_TRIE_CONFIG, CODE, HEAP_PAGES}; +use parity_codec::Encode; +use super::{Externalities, OverlayedChanges}; +use log::warn; + +/// Simple HashMap-based Externalities impl. +pub struct BasicExternalities { + inner: HashMap, Vec>, + changes: OverlayedChanges, + code: Option>, +} + +impl BasicExternalities { + /// Create a new instance of `BasicExternalities` + pub fn new(inner: HashMap, Vec>) -> Self { + Self::new_with_code(&[], inner) + } + + /// 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()); + + BasicExternalities { + inner, + changes: overlay, + code: Some(code.to_vec()), + } + } + + /// Insert key/value + pub fn insert(&mut self, k: Vec, v: Vec) -> Option> { + self.inner.insert(k, v) + } +} + +impl ::std::fmt::Debug for BasicExternalities { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "{:?}", self.inner) + } +} + +impl PartialEq for BasicExternalities { + fn eq(&self, other: &BasicExternalities) -> bool { + self.inner.eq(&other.inner) + } +} + +impl FromIterator<(Vec, Vec)> for BasicExternalities { + fn from_iter, Vec)>>(iter: I) -> Self { + let mut t = Self::new(Default::default()); + t.inner.extend(iter); + t + } +} + +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 { + fn from(hashmap: HashMap, Vec>) -> Self { + BasicExternalities { + inner: hashmap, + changes: Default::default(), + code: None, + } + } +} + +impl Externalities for BasicExternalities where H::Out: Ord + HeapSizeOf { + fn storage(&self, key: &[u8]) -> Option> { + match key { + CODE => self.code.clone(), + _ => self.inner.get(key).cloned(), + } + } + + fn child_storage(&self, _storage_key: &[u8], _key: &[u8]) -> Option> { + None + } + + 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); } + } + } + } + } + + fn place_child_storage(&mut self, _storage_key: Vec, _key: Vec, _value: Option>) -> bool { + false + } + + fn kill_child_storage(&mut self, _storage_key: &[u8]) { } + + fn clear_prefix(&mut self, prefix: &[u8]) { + self.changes.clear_prefix(prefix); + self.inner.retain(|key, _| !key.starts_with(prefix)); + } + + fn chain_id(&self) -> u64 { 42 } + + fn storage_root(&mut self) -> H::Out { + trie_root::(self.inner.clone()) + } + + fn child_storage_root(&mut self, _storage_key: &[u8]) -> Option> { + None + } + + fn storage_changes_root(&mut self, _parent: H::Out, _parent_num: u64) -> Option { + None + } + + fn submit_extrinsic(&mut self, _extrinsic: Vec) -> Result<(), ()> { + warn!("Call to submit_extrinsic without offchain externalities set."); + Err(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use primitives::{Blake2Hasher, H256}; + use hex_literal::{hex, hex_impl}; + + #[test] + fn commit_should_work() { + let mut ext = BasicExternalities::default(); + let ext = &mut ext as &mut Externalities; + ext.set_storage(b"doe".to_vec(), b"reindeer".to_vec()); + ext.set_storage(b"dog".to_vec(), b"puppy".to_vec()); + ext.set_storage(b"dogglesworth".to_vec(), b"cat".to_vec()); + const ROOT: [u8; 32] = hex!("0b33ed94e74e0f8e92a55923bece1ed02d16cf424e124613ddebc53ac3eeeabe"); + assert_eq!(ext.storage_root(), H256::from(ROOT)); + } + + #[test] + fn set_and_retrieve_code() { + let mut ext = BasicExternalities::default(); + let ext = &mut ext as &mut Externalities; + + let code = vec![1, 2, 3]; + ext.set_storage(CODE.to_vec(), code.clone()); + + assert_eq!(&ext.storage(CODE).unwrap(), &code); + } +} diff --git a/core/state-machine/src/changes_trie/build.rs b/core/state-machine/src/changes_trie/build.rs index 548ffa42995d6e1d57bc27edb8733ae5f42415bf..9cb766874d8f847136093f334199c92046181d83 100644 --- a/core/state-machine/src/changes_trie/build.rs +++ b/core/state-machine/src/changes_trie/build.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/state-machine/src/changes_trie/build_iterator.rs b/core/state-machine/src/changes_trie/build_iterator.rs index 4097da3a549be2525b399369ed335c63a936c5fb..f9c6ba6e7b397021ca0c856499de012217815867 100644 --- a/core/state-machine/src/changes_trie/build_iterator.rs +++ b/core/state-machine/src/changes_trie/build_iterator.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/state-machine/src/changes_trie/changes_iterator.rs b/core/state-machine/src/changes_trie/changes_iterator.rs index 5805427870c86fa1372ec33bd815ea2c619e4018..ad70117984989bb9d022855b29f7cea87927c368 100644 --- a/core/state-machine/src/changes_trie/changes_iterator.rs +++ b/core/state-machine/src/changes_trie/changes_iterator.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -115,7 +115,7 @@ pub fn key_changes_proof_check, H: Hasher>( let mut proof_db = MemoryDB::::default(); for item in proof { - proof_db.insert(&item); + proof_db.insert(&[], &item); } let proof_db = InMemoryStorage::with_db(proof_db); diff --git a/core/state-machine/src/changes_trie/input.rs b/core/state-machine/src/changes_trie/input.rs index c106774021be8ff5769bddf35746938020f55192..3154aff715c2ba79070b6ecd6dd3c49a77c0729b 100644 --- a/core/state-machine/src/changes_trie/input.rs +++ b/core/state-machine/src/changes_trie/input.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/state-machine/src/changes_trie/mod.rs b/core/state-machine/src/changes_trie/mod.rs index 2bde6a259242bb2bb76285aa617d9fe0b03fb575..c29131cc0c5d8bd82724a02b0a2b072c59f2fd81 100644 --- a/core/state-machine/src/changes_trie/mod.rs +++ b/core/state-machine/src/changes_trie/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -77,7 +77,7 @@ pub trait RootsStorage: Send + Sync { /// Changes trie storage. Provides access to trie roots and trie nodes. pub trait Storage: RootsStorage { /// Get a trie node. - fn get(&self, key: &H::Out) -> Result, String>; + fn get(&self, key: &H::Out, prefix: &[u8]) -> Result, String>; } /// Changes trie configuration. diff --git a/core/state-machine/src/changes_trie/prune.rs b/core/state-machine/src/changes_trie/prune.rs index 74bf0c97bfdfe2b12bebd4f28a08c072e25cec69..de872a325589e9854b135ab1c3acce981edac994 100644 --- a/core/state-machine/src/changes_trie/prune.rs +++ b/core/state-machine/src/changes_trie/prune.rs @@ -1,4 +1,4 @@ -// Copyright 2017 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/state-machine/src/changes_trie/storage.rs b/core/state-machine/src/changes_trie/storage.rs index 2ac00a853577add04129021f18a8c185bfeefdfa..decc332c1a6187ea364eb4db2a2fb5e75a38a82c 100644 --- a/core/state-machine/src/changes_trie/storage.rs +++ b/core/state-machine/src/changes_trie/storage.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -92,7 +92,7 @@ impl InMemoryStorage where H::Out: HeapSizeOf { pub fn remove_from_storage(&self, keys: &HashSet) { let mut data = self.data.write(); for key in keys { - data.mdb.remove_and_purge(key); + data.mdb.remove_and_purge(key, &[]); } } @@ -116,8 +116,8 @@ impl RootsStorage for InMemoryStorage where H::Out: HeapSizeOf } impl Storage for InMemoryStorage where H::Out: HeapSizeOf { - fn get(&self, key: &H::Out) -> Result, String> { - MemoryDB::::get(&self.data.read().mdb, key) + fn get(&self, key: &H::Out, prefix: &[u8]) -> Result, String> { + MemoryDB::::get(&self.data.read().mdb, key, prefix) } } @@ -128,7 +128,9 @@ impl<'a, H: Hasher, S: 'a + Storage> TrieBackendAdapter<'a, H, S> { } impl<'a, H: Hasher, S: 'a + Storage> TrieBackendStorage for TrieBackendAdapter<'a, H, S> { - fn get(&self, key: &H::Out) -> Result, String> { - self.storage.get(key) + type Overlay = MemoryDB; + + fn get(&self, key: &H::Out, prefix: &[u8]) -> Result, String> { + self.storage.get(key, prefix) } } diff --git a/core/state-machine/src/ext.rs b/core/state-machine/src/ext.rs index e0f164b42b2aaea3b2091a4a2dcddf56c1910c67..33074c70590b1a42cc4d2eae668ae5c7e2b3cab5 100644 --- a/core/state-machine/src/ext.rs +++ b/core/state-machine/src/ext.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -20,13 +20,13 @@ use std::{error, fmt, cmp::Ord}; use log::warn; use crate::backend::{Backend, Consolidate}; use crate::changes_trie::{AnchorBlockId, Storage as ChangesTrieStorage, compute_changes_trie_root}; -use crate::{Externalities, OverlayedChanges}; +use crate::{Externalities, OverlayedChanges, OffchainExt}; use hash_db::Hasher; use primitives::storage::well_known_keys::is_child_storage_key; use trie::{MemoryDB, TrieDBMut, TrieMut, default_child_trie_root, is_child_trie_key_valid}; use heapsize::HeapSizeOf; -const EXT_NOT_ALLOWED_TO_FAIL: &'static str = "Externalities not allowed to fail within runtime"; +const EXT_NOT_ALLOWED_TO_FAIL: &str = "Externalities not allowed to fail within runtime"; /// Errors that can occur when interacting with the externalities. #[derive(Debug, Copy, Clone)] @@ -58,12 +58,11 @@ impl error::Error for Error { } /// Wraps a read-only backend, call executor, and current overlayed changes. -pub struct Ext<'a, H, B, T> +pub struct Ext<'a, H, B, T, O> where H: Hasher, B: 'a + Backend, - T: 'a + ChangesTrieStorage, { /// The overlayed changes to write to. overlay: &'a mut OverlayedChanges, @@ -81,23 +80,34 @@ where /// `storage_changes_root` is called matters + we need to remember additional /// data at this moment (block number). changes_trie_transaction: Option<(u64, MemoryDB, H::Out)>, + /// Additional externalities for offchain workers. + /// + /// If None, some methods from the trait might not supported. + offchain_externalities: Option<&'a mut O>, } -impl<'a, H, B, T> Ext<'a, H, B, T> +impl<'a, H, B, T, O> Ext<'a, H, B, T, O> where H: Hasher, B: 'a + Backend, T: 'a + ChangesTrieStorage, + O: 'a + OffchainExt, H::Out: Ord + HeapSizeOf, { /// Create a new `Ext` from overlayed changes and read-only backend - pub fn new(overlay: &'a mut OverlayedChanges, backend: &'a B, changes_trie_storage: Option<&'a T>) -> Self { + pub fn new( + overlay: &'a mut OverlayedChanges, + backend: &'a B, + changes_trie_storage: Option<&'a T>, + offchain_externalities: Option<&'a mut O>, + ) -> Self { Ext { overlay, backend, storage_transaction: None, changes_trie_storage, changes_trie_transaction: None, + offchain_externalities, } } @@ -152,12 +162,13 @@ where } #[cfg(test)] -impl<'a, H, B, T> Ext<'a, H, B, T> +impl<'a, H, B, T, O> Ext<'a, H, B, T, O> where H: Hasher, B: 'a + Backend, T: 'a + ChangesTrieStorage, + O: 'a + OffchainExt, { pub fn storage_pairs(&self) -> Vec<(Vec, Vec)> { use std::collections::HashMap; @@ -173,11 +184,12 @@ where } } -impl<'a, B: 'a, T: 'a, H> Externalities for Ext<'a, H, B, T> +impl<'a, B, T, H, O> Externalities for Ext<'a, H, B, T, O> where H: Hasher, B: 'a + Backend, T: 'a + ChangesTrieStorage, + O: 'a + OffchainExt, H::Out: Ord + HeapSizeOf, { fn storage(&self, key: &[u8]) -> Option> { @@ -329,6 +341,17 @@ where self.changes_trie_transaction = root_and_tx; root } + + fn submit_extrinsic(&mut self, extrinsic: Vec) -> Result<(), ()> { + let _guard = panic_handler::AbortGuard::new(true); + if let Some(ext) = self.offchain_externalities.as_mut() { + ext.submit_extrinsic(extrinsic); + Ok(()) + } else { + warn!("Call to submit_extrinsic without offchain externalities set."); + Err(()) + } + } } #[cfg(test)] @@ -345,7 +368,7 @@ mod tests { type TestBackend = InMemory; type TestChangesTrieStorage = InMemoryChangesTrieStorage; - type TestExt<'a> = Ext<'a, Blake2Hasher, TestBackend, TestChangesTrieStorage>; + type TestExt<'a> = Ext<'a, Blake2Hasher, TestBackend, TestChangesTrieStorage, crate::NeverOffchainExt>; fn prepare_overlay_with_changes() -> OverlayedChanges { OverlayedChanges { @@ -371,7 +394,7 @@ mod tests { fn storage_changes_root_is_none_when_storage_is_not_provided() { let mut overlay = prepare_overlay_with_changes(); let backend = TestBackend::default(); - let mut ext = TestExt::new(&mut overlay, &backend, None); + let mut ext = TestExt::new(&mut overlay, &backend, None, None); assert_eq!(ext.storage_changes_root(Default::default(), 100), None); } @@ -381,7 +404,7 @@ mod tests { overlay.changes_trie_config = None; let storage = TestChangesTrieStorage::new(); let backend = TestBackend::default(); - let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage)); + let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None); assert_eq!(ext.storage_changes_root(Default::default(), 100), None); } @@ -390,7 +413,7 @@ mod tests { let mut overlay = prepare_overlay_with_changes(); let storage = TestChangesTrieStorage::new(); let backend = TestBackend::default(); - let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage)); + let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None); assert_eq!(ext.storage_changes_root(Default::default(), 99), Some(hex!("5b829920b9c8d554a19ee2a1ba593c4f2ee6fc32822d083e04236d693e8358d5").into())); } @@ -401,7 +424,7 @@ mod tests { overlay.prospective.top.get_mut(&vec![1]).unwrap().value = None; let storage = TestChangesTrieStorage::new(); let backend = TestBackend::default(); - let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage)); + let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None); assert_eq!(ext.storage_changes_root(Default::default(), 99), Some(hex!("bcf494e41e29a15c9ae5caa053fe3cb8b446ee3e02a254efbdec7a19235b76e4").into())); } diff --git a/core/state-machine/src/lib.rs b/core/state-machine/src/lib.rs index 3b9e482e8211f0c697fd64e73f2622ae57f0b66f..0500aa72cfcc3782ac06670e1f77a32d30f97856 100644 --- a/core/state-machine/src/lib.rs +++ b/core/state-machine/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -23,12 +23,13 @@ use log::warn; use hash_db::Hasher; use heapsize::HeapSizeOf; use parity_codec::{Decode, Encode}; -use primitives::{storage::well_known_keys, NativeOrEncoded, NeverNativeValue}; +use primitives::{storage::well_known_keys, NativeOrEncoded, NeverNativeValue, OffchainExt}; pub mod backend; mod changes_trie; mod ext; mod testing; +mod basic; mod overlayed_changes; mod proving_backend; mod trie_backend; @@ -37,6 +38,7 @@ mod trie_backend_essence; use overlayed_changes::OverlayedChangeSet; pub use trie::{TrieMut, TrieDBMut, DBValue, MemoryDB}; pub use testing::TestExternalities; +pub use basic::BasicExternalities; pub use ext::Ext; pub use backend::Backend; pub use changes_trie::{ @@ -149,8 +151,27 @@ pub trait Externalities { /// Returns None if key provided is not a storage key. This can due to not being started with CHILD_STORAGE_KEY_PREFIX, or the trie implementation regards the key as invalid. fn child_storage_root(&mut self, storage_key: &[u8]) -> Option>; - /// Get the change trie root of the current storage overlay at a block wth given parent. + /// Get the change trie root of the current storage overlay at a block with given parent. fn storage_changes_root(&mut self, parent: H::Out, parent_num: u64) -> Option where H::Out: Ord; + + /// Submit extrinsic. + /// + /// Returns an error in case the API is not available. + fn submit_extrinsic(&mut self, extrinsic: Vec) -> Result<(), ()>; +} + +/// An implementation of offchain extensions that should never be triggered. +pub enum NeverOffchainExt {} + +impl NeverOffchainExt { + /// Create new offchain extensions. + pub fn new<'a>() -> Option<&'a mut Self> { + None + } +} + +impl OffchainExt for NeverOffchainExt { + fn submit_extrinsic(&mut self, _extrinsic: Vec) { unreachable!() } } /// Code execution engine. @@ -250,17 +271,19 @@ pub fn always_wasm() -> ExecutionManager> { } /// Creates new substrate state machine. -pub fn new<'a, H, B, T, Exec>( +pub fn new<'a, H, B, T, O, Exec>( backend: &'a B, changes_trie_storage: Option<&'a T>, + offchain_ext: Option<&'a mut O>, overlay: &'a mut OverlayedChanges, exec: &'a Exec, method: &'a str, call_data: &'a [u8], -) -> StateMachine<'a, H, B, T, Exec> { +) -> StateMachine<'a, H, B, T, O, Exec> { StateMachine { backend, changes_trie_storage, + offchain_ext, overlay, exec, method, @@ -270,9 +293,10 @@ pub fn new<'a, H, B, T, Exec>( } /// The substrate state machine. -pub struct StateMachine<'a, H, B, T, Exec> { +pub struct StateMachine<'a, H, B, T, O, Exec> { backend: &'a B, changes_trie_storage: Option<&'a T>, + offchain_ext: Option<&'a mut O>, overlay: &'a mut OverlayedChanges, exec: &'a Exec, method: &'a str, @@ -280,11 +304,12 @@ pub struct StateMachine<'a, H, B, T, Exec> { _hasher: PhantomData, } -impl<'a, H, B, T, Exec> StateMachine<'a, H, B, T, Exec> where +impl<'a, H, B, T, O, Exec> StateMachine<'a, H, B, T, O, Exec> where H: Hasher, Exec: CodeExecutor, B: Backend, T: ChangesTrieStorage, + O: OffchainExt, H::Out: Ord + HeapSizeOf, { /// Execute a call using the given state backend, overlayed changes, and call executor. @@ -322,7 +347,13 @@ impl<'a, H, B, T, Exec> StateMachine<'a, H, B, T, Exec> where R: Decode + Encode + PartialEq, NC: FnOnce() -> result::Result + UnwindSafe, { - let mut externalities = ext::Ext::new(self.overlay, self.backend, self.changes_trie_storage); + let offchain = self.offchain_ext.as_mut(); + let mut externalities = ext::Ext::new( + self.overlay, + self.backend, + self.changes_trie_storage, + offchain.map(|x| &mut **x), + ); let (result, was_native) = self.exec.call( &mut externalities, self.method, @@ -503,6 +534,7 @@ where let mut sm = StateMachine { backend: &proving_backend, changes_trie_storage: None as Option<&changes_trie::InMemoryStorage>, + offchain_ext: NeverOffchainExt::new(), overlay, exec, method, @@ -552,6 +584,7 @@ where let mut sm = StateMachine { backend: trie_backend, changes_trie_storage: None as Option<&changes_trie::InMemoryStorage>, + offchain_ext: NeverOffchainExt::new(), overlay, exec, method, @@ -625,7 +658,7 @@ where /// differs from previous OR config decode has failed. pub(crate) fn set_changes_trie_config(overlay: &mut OverlayedChanges, config: Option>, final_check: bool) -> Result<(), Box> { let config = match config { - Some(v) => Some(changes_trie::Configuration::decode(&mut &v[..]) + Some(v) => Some(Decode::decode(&mut &v[..]) .ok_or_else(|| Box::new("Failed to decode changes trie configuration".to_owned()) as Box)?), None => None, }; @@ -728,6 +761,7 @@ mod tests { assert_eq!(new( &trie_backend::tests::test_trie(), Some(&InMemoryChangesTrieStorage::new()), + NeverOffchainExt::new(), &mut Default::default(), &DummyCodeExecutor { change_changes_trie_config: false, @@ -748,6 +782,7 @@ mod tests { assert_eq!(new( &trie_backend::tests::test_trie(), Some(&InMemoryChangesTrieStorage::new()), + NeverOffchainExt::new(), &mut Default::default(), &DummyCodeExecutor { change_changes_trie_config: false, @@ -768,6 +803,7 @@ mod tests { assert!(new( &trie_backend::tests::test_trie(), Some(&InMemoryChangesTrieStorage::new()), + NeverOffchainExt::new(), &mut Default::default(), &DummyCodeExecutor { change_changes_trie_config: false, @@ -836,7 +872,7 @@ mod tests { { let changes_trie_storage = InMemoryChangesTrieStorage::new(); - let mut ext = Ext::new(&mut overlay, &backend, Some(&changes_trie_storage)); + let mut ext = Ext::new(&mut overlay, &backend, Some(&changes_trie_storage), NeverOffchainExt::new()); ext.clear_prefix(b"ab"); } overlay.commit_prospective(); @@ -860,7 +896,7 @@ mod tests { let backend = InMemory::::default().try_into_trie_backend().unwrap(); let changes_trie_storage = InMemoryChangesTrieStorage::new(); let mut overlay = OverlayedChanges::default(); - let mut ext = Ext::new(&mut overlay, &backend, Some(&changes_trie_storage)); + let mut ext = Ext::new(&mut overlay, &backend, Some(&changes_trie_storage), NeverOffchainExt::new()); assert!(ext.set_child_storage(b":child_storage:testchild".to_vec(), b"abc".to_vec(), b"def".to_vec())); assert_eq!(ext.child_storage(b":child_storage:testchild", b"abc"), Some(b"def".to_vec())); @@ -887,6 +923,7 @@ mod tests { assert!(new( &trie_backend::tests::test_trie(), Some(&InMemoryChangesTrieStorage::new()), + NeverOffchainExt::new(), &mut Default::default(), &DummyCodeExecutor { change_changes_trie_config: true, @@ -906,6 +943,7 @@ mod tests { assert!(new( &trie_backend::tests::test_trie(), Some(&InMemoryChangesTrieStorage::new()), + NeverOffchainExt::new(), &mut Default::default(), &DummyCodeExecutor { change_changes_trie_config: true, diff --git a/core/state-machine/src/overlayed_changes.rs b/core/state-machine/src/overlayed_changes.rs index 2f7522c48e7d75376deac6a946a89c305a4ac579..56e69323e878ccb98b180907b8f41618dc480b57 100644 --- a/core/state-machine/src/overlayed_changes.rs +++ b/core/state-machine/src/overlayed_changes.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -375,7 +375,12 @@ mod tests { }; let changes_trie_storage = InMemoryChangesTrieStorage::new(); - let mut ext = Ext::new(&mut overlay, &backend, Some(&changes_trie_storage)); + let mut ext = Ext::new( + &mut overlay, + &backend, + Some(&changes_trie_storage), + crate::NeverOffchainExt::new(), + ); const ROOT: [u8; 32] = hex!("0b41e488cccbd67d1f1089592c2c235f5c5399b053f7fe9152dd4b5f279914cd"); assert_eq!(ext.storage_root(), H256::from(ROOT)); } diff --git a/core/state-machine/src/proving_backend.rs b/core/state-machine/src/proving_backend.rs index 1aeb83fe3ad0c2b04e4885a1762bf8ab9e79ce27..4d85791faf681afbaaa94cef9090aad7ce98bd3f 100644 --- a/core/state-machine/src/proving_backend.rs +++ b/core/state-machine/src/proving_backend.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -21,7 +21,7 @@ use log::debug; use hash_db::Hasher; use heapsize::HeapSizeOf; use hash_db::HashDB; -use trie::{Recorder, MemoryDB, TrieError, default_child_trie_root, read_trie_value_with, read_child_trie_value_with, record_all_keys}; +use trie::{Recorder, MemoryDB, PrefixedMemoryDB, TrieError, default_child_trie_root, read_trie_value_with, read_child_trie_value_with, record_all_keys}; use crate::trie_backend::TrieBackend; use crate::trie_backend_essence::{Ephemeral, TrieBackendEssence, TrieBackendStorage}; use crate::{Error, ExecutionError, Backend}; @@ -40,7 +40,7 @@ impl<'a, S, H> ProvingBackendEssence<'a, S, H> H::Out: HeapSizeOf, { pub fn storage(&mut self, key: &[u8]) -> Result>, String> { - let mut read_overlay = MemoryDB::default(); + let mut read_overlay = S::Overlay::default(); let eph = Ephemeral::new( self.backend.backend_storage(), &mut read_overlay, @@ -54,7 +54,7 @@ impl<'a, S, H> ProvingBackendEssence<'a, S, H> pub fn child_storage(&mut self, storage_key: &[u8], key: &[u8]) -> Result>, String> { let root = self.storage(storage_key)?.unwrap_or(default_child_trie_root::(storage_key)); - let mut read_overlay = MemoryDB::default(); + let mut read_overlay = S::Overlay::default(); let eph = Ephemeral::new( self.backend.backend_storage(), &mut read_overlay, @@ -66,7 +66,7 @@ impl<'a, S, H> ProvingBackendEssence<'a, S, H> } pub fn record_all_keys(&mut self) { - let mut read_overlay = MemoryDB::default(); + let mut read_overlay = S::Overlay::default(); let eph = Ephemeral::new( self.backend.backend_storage(), &mut read_overlay, @@ -116,8 +116,8 @@ impl<'a, S, H> Backend for ProvingBackend<'a, S, H> H::Out: Ord + HeapSizeOf, { type Error = String; - type Transaction = MemoryDB; - type TrieBackendStorage = MemoryDB; + type Transaction = S::Overlay; + type TrieBackendStorage = PrefixedMemoryDB; fn storage(&self, key: &[u8]) -> Result>, Self::Error> { ProvingBackendEssence { @@ -151,7 +151,7 @@ impl<'a, S, H> Backend for ProvingBackend<'a, S, H> self.backend.keys(prefix) } - fn storage_root(&self, delta: I) -> (H::Out, MemoryDB) + fn storage_root(&self, delta: I) -> (H::Out, Self::Transaction) where I: IntoIterator, Option>)> { self.backend.storage_root(delta) @@ -181,7 +181,7 @@ where { let db = create_proof_check_backend_storage(proof); - if !db.contains(&root) { + if !db.contains(&root, &[]) { return Err(Box::new(ExecutionError::InvalidProof) as Box); } @@ -198,7 +198,7 @@ where { let mut db = MemoryDB::default(); for item in proof { - db.insert(&item); + db.insert(&[], &item); } db } @@ -210,7 +210,7 @@ mod tests { use super::*; use primitives::{Blake2Hasher}; - fn test_proving<'a>(trie_backend: &'a TrieBackend, Blake2Hasher>) -> ProvingBackend<'a, MemoryDB, Blake2Hasher> { + fn test_proving<'a>(trie_backend: &'a TrieBackend, Blake2Hasher>) -> ProvingBackend<'a, PrefixedMemoryDB, Blake2Hasher> { ProvingBackend::new(trie_backend) } diff --git a/core/state-machine/src/testing.rs b/core/state-machine/src/testing.rs index a0448dad7cc646c85c0949f8f8c086df8e2118a1..d03cc8e76dccce3bcd7e5c8bca5746865eb96130 100644 --- a/core/state-machine/src/testing.rs +++ b/core/state-machine/src/testing.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -107,6 +107,9 @@ impl From< HashMap, Vec> > for TestExternalities where } } +// TODO child test primitives are currently limited to `changes` (for non child the way +// things are defined seems utterly odd to (put changes in changes but never make them +// available for read through inner) impl Externalities for TestExternalities where H::Out: Ord + HeapSizeOf { fn storage(&self, key: &[u8]) -> Option> { match key { @@ -115,8 +118,8 @@ impl Externalities for TestExternalities where H::Out: Ord + He } } - fn child_storage(&self, _storage_key: &[u8], _key: &[u8]) -> Option> { - None + fn child_storage(&self, storage_key: &[u8], key: &[u8]) -> Option> { + self.changes.child_storage(storage_key, key)?.map(Vec::from) } fn place_storage(&mut self, key: Vec, maybe_value: Option>) { @@ -132,11 +135,15 @@ impl Externalities for TestExternalities where H::Out: Ord + He } } - fn place_child_storage(&mut self, _storage_key: Vec, _key: Vec, _value: Option>) -> bool { - false + fn place_child_storage(&mut self, storage_key: Vec, key: Vec, value: Option>) -> bool { + self.changes.set_child_storage(storage_key, key, value); + // TODO place_child_storage and set_child_storage should always be valid (create child on set)? + true } - fn kill_child_storage(&mut self, _storage_key: &[u8]) { } + fn kill_child_storage(&mut self, storage_key: &[u8]) { + self.changes.clear_child_storage(storage_key); + } fn clear_prefix(&mut self, prefix: &[u8]) { self.changes.clear_prefix(prefix); @@ -161,6 +168,10 @@ impl Externalities for TestExternalities where H::Out: Ord + He &AnchorBlockId { hash: parent, number: parent_num }, ).map(|(root, _)| root.clone()) } + + fn submit_extrinsic(&mut self, _extrinsic: Vec) -> Result<(), ()> { + unimplemented!() + } } #[cfg(test)] diff --git a/core/state-machine/src/trie_backend.rs b/core/state-machine/src/trie_backend.rs index 989b990d93815ea9bf63a8681c9555e833e76108..b152d7fea18578aedf032efb2ab482627d087f58 100644 --- a/core/state-machine/src/trie_backend.rs +++ b/core/state-machine/src/trie_backend.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -19,7 +19,7 @@ use log::{warn, debug}; use hash_db::Hasher; use heapsize::HeapSizeOf; -use trie::{TrieDB, TrieError, Trie, MemoryDB, delta_trie_root, default_child_trie_root, child_delta_trie_root}; +use trie::{TrieDB, TrieError, Trie, delta_trie_root, default_child_trie_root, child_delta_trie_root}; use crate::trie_backend_essence::{TrieBackendEssence, TrieBackendStorage, Ephemeral}; use crate::Backend; @@ -63,7 +63,7 @@ impl, H: Hasher> Backend for TrieBackend where H::Out: Ord + HeapSizeOf, { type Error = String; - type Transaction = MemoryDB; + type Transaction = S::Overlay; type TrieBackendStorage = S; fn storage(&self, key: &[u8]) -> Result>, Self::Error> { @@ -83,7 +83,7 @@ impl, H: Hasher> Backend for TrieBackend where } fn pairs(&self) -> Vec<(Vec, Vec)> { - let mut read_overlay = MemoryDB::default(); + let mut read_overlay = S::Overlay::default(); let eph = Ephemeral::new(self.essence.backend_storage(), &mut read_overlay); let collect_all = || -> Result<_, Box>> { @@ -107,7 +107,7 @@ impl, H: Hasher> Backend for TrieBackend where } fn keys(&self, prefix: &Vec) -> Vec> { - let mut read_overlay = MemoryDB::default(); + let mut read_overlay = S::Overlay::default(); let eph = Ephemeral::new(self.essence.backend_storage(), &mut read_overlay); let collect_all = || -> Result<_, Box>> { @@ -126,10 +126,10 @@ impl, H: Hasher> Backend for TrieBackend where collect_all().map_err(|e| debug!(target: "trie", "Error extracting trie keys: {}", e)).unwrap_or_default() } - fn storage_root(&self, delta: I) -> (H::Out, MemoryDB) + fn storage_root(&self, delta: I) -> (H::Out, S::Overlay) where I: IntoIterator, Option>)> { - let mut write_overlay = MemoryDB::default(); + let mut write_overlay = S::Overlay::default(); let mut root = *self.essence.root(); { @@ -154,7 +154,7 @@ impl, H: Hasher> Backend for TrieBackend where { let default_root = default_child_trie_root::(storage_key); - let mut write_overlay = MemoryDB::default(); + let mut write_overlay = S::Overlay::default(); let mut root = match self.storage(storage_key) { Ok(value) => value.unwrap_or(default_child_trie_root::(storage_key)), Err(e) => { @@ -189,12 +189,12 @@ impl, H: Hasher> Backend for TrieBackend where pub mod tests { use std::collections::HashSet; use primitives::{Blake2Hasher, H256}; - use trie::{TrieMut, TrieDBMut}; + use trie::{TrieMut, TrieDBMut, PrefixedMemoryDB}; use super::*; - fn test_db() -> (MemoryDB, H256) { + fn test_db() -> (PrefixedMemoryDB, H256) { let mut root = H256::default(); - let mut mdb = MemoryDB::::default(); + let mut mdb = PrefixedMemoryDB::::default(); { let mut trie = TrieDBMut::new(&mut mdb, &mut root); trie.insert(b"key", b"value").expect("insert failed"); @@ -208,7 +208,7 @@ pub mod tests { (mdb, root) } - pub(crate) fn test_trie() -> TrieBackend, Blake2Hasher> { + pub(crate) fn test_trie() -> TrieBackend, Blake2Hasher> { let (mdb, root) = test_db(); TrieBackend::new(mdb, root) } @@ -230,8 +230,8 @@ pub mod tests { #[test] fn pairs_are_empty_on_empty_storage() { - assert!(TrieBackend::, Blake2Hasher>::new( - MemoryDB::default(), + assert!(TrieBackend::, Blake2Hasher>::new( + PrefixedMemoryDB::default(), Default::default(), ).pairs().is_empty()); } diff --git a/core/state-machine/src/trie_backend_essence.rs b/core/state-machine/src/trie_backend_essence.rs index 5a2fc8d76d6467399103a4aee26a28b07dd7821d..8101126c39d78c7b386ae94a33a74195a8122d94 100644 --- a/core/state-machine/src/trie_backend_essence.rs +++ b/core/state-machine/src/trie_backend_essence.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -22,13 +22,14 @@ use std::sync::Arc; use log::{debug, warn}; use hash_db::{self, Hasher}; use heapsize::HeapSizeOf; -use trie::{TrieDB, Trie, MemoryDB, DBValue, TrieError, default_child_trie_root, read_trie_value, read_child_trie_value, for_keys_in_child_trie}; +use trie::{TrieDB, Trie, MemoryDB, PrefixedMemoryDB, DBValue, TrieError, default_child_trie_root, read_trie_value, read_child_trie_value, for_keys_in_child_trie}; use crate::changes_trie::Storage as ChangesTrieStorage; +use crate::backend::Consolidate; /// Patricia trie-based storage trait. pub trait Storage: Send + Sync { /// Get a trie node. - fn get(&self, key: &H::Out) -> Result, String>; + fn get(&self, key: &H::Out, prefix: &[u8]) -> Result, String>; } /// Patricia trie-based pairs storage essence. @@ -63,7 +64,7 @@ impl, H: Hasher> TrieBackendEssence where H::Out: /// Get the value of storage at given key. pub fn storage(&self, key: &[u8]) -> Result>, String> { - let mut read_overlay = MemoryDB::default(); + let mut read_overlay = S::Overlay::default(); let eph = Ephemeral { storage: &self.storage, overlay: &mut read_overlay, @@ -78,7 +79,7 @@ impl, H: Hasher> TrieBackendEssence where H::Out: pub fn child_storage(&self, storage_key: &[u8], key: &[u8]) -> Result>, String> { let root = self.storage(storage_key)?.unwrap_or(default_child_trie_root::(storage_key)); - let mut read_overlay = MemoryDB::default(); + let mut read_overlay = S::Overlay::default(); let eph = Ephemeral { storage: &self.storage, overlay: &mut read_overlay, @@ -99,7 +100,7 @@ impl, H: Hasher> TrieBackendEssence where H::Out: } }; - let mut read_overlay = MemoryDB::default(); + let mut read_overlay = S::Overlay::default(); let eph = Ephemeral { storage: &self.storage, overlay: &mut read_overlay, @@ -112,7 +113,7 @@ impl, H: Hasher> TrieBackendEssence where H::Out: /// Execute given closure for all keys starting with prefix. pub fn for_keys_with_prefix(&self, prefix: &[u8], mut f: F) { - let mut read_overlay = MemoryDB::default(); + let mut read_overlay = S::Overlay::default(); let eph = Ephemeral { storage: &self.storage, overlay: &mut read_overlay, @@ -145,7 +146,7 @@ impl, H: Hasher> TrieBackendEssence where H::Out: pub(crate) struct Ephemeral<'a, S: 'a + TrieBackendStorage, H: 'a + Hasher> { storage: &'a S, - overlay: &'a mut MemoryDB, + overlay: &'a mut S::Overlay, } impl<'a, @@ -171,7 +172,7 @@ impl<'a, } impl<'a, S: TrieBackendStorage, H: Hasher> Ephemeral<'a, S, H> { - pub fn new(storage: &'a S, overlay: &'a mut MemoryDB) -> Self { + pub fn new(storage: &'a S, overlay: &'a mut S::Overlay) -> Self { Ephemeral { storage, overlay, @@ -187,10 +188,10 @@ impl<'a, where H::Out: HeapSizeOf { fn get(&self, key: &H::Out) -> Option { - if let Some(val) = hash_db::PlainDB::get(self.overlay, key) { + if let Some(val) = hash_db::HashDB::get(self.overlay, key, &[]) { Some(val) } else { - match self.storage.get(&key) { + match self.storage.get(&key, &[]) { Ok(x) => x, Err(e) => { warn!(target: "trie", "Failed to read from DB: {}", e); @@ -201,15 +202,15 @@ impl<'a, } fn contains(&self, key: &H::Out) -> bool { - hash_db::PlainDB::get(self, key).is_some() + hash_db::HashDB::get(self, key, &[]).is_some() } fn emplace(&mut self, key: H::Out, value: DBValue) { - hash_db::PlainDB::emplace(self.overlay, key, value) + hash_db::HashDB::emplace(self.overlay, key, &[], value) } fn remove(&mut self, key: &H::Out) { - hash_db::PlainDB::remove(self.overlay, key) + hash_db::HashDB::remove(self.overlay, key, &[]) } } @@ -231,11 +232,11 @@ impl<'a, for Ephemeral<'a, S, H> where H::Out: HeapSizeOf { - fn get(&self, key: &H::Out) -> Option { - if let Some(val) = hash_db::HashDB::get(self.overlay, key) { + fn get(&self, key: &H::Out, prefix: &[u8]) -> Option { + if let Some(val) = hash_db::HashDB::get(self.overlay, key, prefix) { Some(val) } else { - match self.storage.get(&key) { + match self.storage.get(&key, prefix) { Ok(x) => x, Err(e) => { warn!(target: "trie", "Failed to read from DB: {}", e); @@ -245,20 +246,20 @@ impl<'a, } } - fn contains(&self, key: &H::Out) -> bool { - hash_db::HashDB::get(self, key).is_some() + fn contains(&self, key: &H::Out, prefix: &[u8]) -> bool { + hash_db::HashDB::get(self, key, prefix).is_some() } - fn insert(&mut self, value: &[u8]) -> H::Out { - hash_db::HashDB::insert(self.overlay, value) + fn insert(&mut self, prefix: &[u8], value: &[u8]) -> H::Out { + hash_db::HashDB::insert(self.overlay, prefix, value) } - fn emplace(&mut self, key: H::Out, value: DBValue) { - hash_db::HashDB::emplace(self.overlay, key, value) + fn emplace(&mut self, key: H::Out, prefix: &[u8], value: DBValue) { + hash_db::HashDB::emplace(self.overlay, key, prefix, value) } - fn remove(&mut self, key: &H::Out) { - hash_db::HashDB::remove(self.overlay, key) + fn remove(&mut self, key: &H::Out, prefix: &[u8]) { + hash_db::HashDB::remove(self.overlay, key, prefix) } } @@ -269,33 +270,49 @@ impl<'a, for Ephemeral<'a, S, H> where H::Out: HeapSizeOf { - fn get(&self, key: &H::Out) -> Option { hash_db::HashDB::get(self, key) } - fn contains(&self, key: &H::Out) -> bool { hash_db::HashDB::contains(self, key) } + fn get(&self, key: &H::Out, prefix: &[u8]) -> Option { hash_db::HashDB::get(self, key, prefix) } + fn contains(&self, key: &H::Out, prefix: &[u8]) -> bool { hash_db::HashDB::contains(self, key, prefix) } } /// Key-value pairs storage that is used by trie backend essence. pub trait TrieBackendStorage: Send + Sync { + /// Type of in-memory overlay. + type Overlay: hash_db::HashDB + Default + Consolidate; /// Get the value stored at key. - fn get(&self, key: &H::Out) -> Result, String>; + fn get(&self, key: &H::Out, prefix: &[u8]) -> Result, String>; } // This implementation is used by normal storage trie clients. impl TrieBackendStorage for Arc> { - fn get(&self, key: &H::Out) -> Result, String> { - Storage::::get(self.deref(), key) + type Overlay = PrefixedMemoryDB; + + fn get(&self, key: &H::Out, prefix: &[u8]) -> Result, String> { + Storage::::get(self.deref(), key, prefix) } } // This implementation is used by test storage trie clients. +impl TrieBackendStorage for PrefixedMemoryDB { + type Overlay = PrefixedMemoryDB; + + fn get(&self, key: &H::Out, prefix: &[u8]) -> Result, String> { + Ok(hash_db::HashDB::get(self, key, prefix)) + } +} + impl TrieBackendStorage for MemoryDB { - fn get(&self, key: &H::Out) -> Result, String> { - Ok(hash_db::PlainDB::get(self, key)) + type Overlay = MemoryDB; + + fn get(&self, key: &H::Out, prefix: &[u8]) -> Result, String> { + Ok(hash_db::HashDB::get(self, key, prefix)) } } // This implementation is used by changes trie clients. impl<'a, S, H: Hasher> TrieBackendStorage for &'a S where S: ChangesTrieStorage { - fn get(&self, key: &H::Out) -> Result, String> { - ChangesTrieStorage::::get(*self, key) + type Overlay = MemoryDB; + + fn get(&self, key: &H::Out, prefix: &[u8]) -> Result, String> { + ChangesTrieStorage::::get(*self, key, prefix) } } diff --git a/core/telemetry/Cargo.toml b/core/telemetry/Cargo.toml index 6567cdcf13ea580d860cadf8891442bcab9fb4cd..0553c4f16b7571948897a7808335497412f08a5f 100644 --- a/core/telemetry/Cargo.toml +++ b/core/telemetry/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "substrate-telemetry" -version = "0.3.0" +version = "0.3.1" authors = ["Parity Technologies "] description = "Telemetry utils" edition = "2018" @@ -9,6 +9,9 @@ edition = "2018" parking_lot = "0.7.1" lazy_static = "1.0" log = "0.4" +rand = "0.6" +serde = "1.0.81" +serde_derive = "1.0" slog = "^2" slog-json = "^2" slog-async = "^2" diff --git a/core/telemetry/src/lib.rs b/core/telemetry/src/lib.rs index 9afa7b03ed3dbb91094b864904ac0154453a21c9..21289459c624173c0f5b65ef90b43e12c8bda489 100644 --- a/core/telemetry/src/lib.rs +++ b/core/telemetry/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -26,15 +26,21 @@ use std::sync::Arc; use parking_lot::Mutex; use slog::{Drain, o}; use log::trace; +use rand::{thread_rng, Rng}; pub use slog_scope::with_logger; pub use slog; +use serde_derive::{Serialize, Deserialize}; +use slog::OwnedKVList; +use slog::Record; +use core::result; /// Configuration for telemetry. pub struct TelemetryConfig { - /// URL of the telemetry WebSocket server. - pub url: String, - /// What do do when we connect to the server. - pub on_connect: Box, + /// Collection of telemetry WebSocket servers with a corresponding verbosity level. + pub endpoints: TelemetryEndpoints, + /// What do do when we connect to the servers. + /// Note that this closure is executed each time we connect to a telemetry endpoint. + pub on_connect: Box, } /// Telemetry service guard. @@ -43,66 +49,165 @@ pub type Telemetry = slog_scope::GlobalLoggerGuard; /// Size of the channel for passing messages to telemetry thread. const CHANNEL_SIZE: usize = 262144; +/// Log levels. +pub const SUBSTRATE_DEBUG: &str = "9"; +pub const SUBSTRATE_INFO: &str = "0"; + +pub const CONSENSUS_TRACE: &str = "9"; +pub const CONSENSUS_DEBUG: &str = "5"; +pub const CONSENSUS_WARN: &str = "4"; +pub const CONSENSUS_INFO: &str = "3"; + +/// Multiply logging to all drains. This is similar to `slog::Duplicate`, which is +/// limited to two drains though and doesn't support dynamic nesting at runtime. +#[derive(Debug, Clone)] +pub struct Multiply (pub Vec>); + +impl Multiply { + pub fn new(v: Vec>) -> Self { + Multiply(v) + } +} + +impl Drain for Multiply { + type Ok = Vec; + type Err = Vec; + + fn log(&self, record: &Record, logger_values: &OwnedKVList) -> result::Result { + let mut oks = Vec::new(); + let mut errs = Vec::new(); + + self.0.iter().for_each(|l| { + let res: Result<::Ok, ::Err> = (*l).log(record, logger_values); + match res { + Ok(o) => oks.push(o), + Err(e) => errs.push(e), + } + }); + + if !errs.is_empty() { + result::Result::Err(errs) + } else { + result::Result::Ok(oks) + } + } +} + /// Initialise telemetry. pub fn init_telemetry(config: TelemetryConfig) -> slog_scope::GlobalLoggerGuard { - let writer = TelemetryWriter::new(); - let out_sync = writer.out.clone(); - let log = slog::Logger::root( - slog_async::Async::new( - slog_json::Json::default(writer).fuse() - ).chan_size(CHANNEL_SIZE) + let mut endpoint_drains: Vec>> = Vec::new(); + let mut out_syncs = Vec::new(); + + // Set up a filter/drain for each endpoint + config.endpoints.0.iter().for_each(|(url, verbosity)| { + let writer = TelemetryWriter::new(Arc::new(url.to_owned())); + let out_sync = writer.out.clone(); + out_syncs.push(out_sync); + + let until_verbosity = *verbosity; + let filter = slog::Filter( + slog_json::Json::default(writer).fuse(), + move |rec| { + let tag = rec.tag().parse::() + .expect("`telemetry!` macro requires tag."); + tag <= until_verbosity + }); + + let filter = Box::new(filter) as Box>; + endpoint_drains.push(filter); + }); + + // Set up logging to all endpoints + let drain = slog_async::Async::new(Multiply::new(endpoint_drains).fuse()); + let root = slog::Logger::root(drain.chan_size(CHANNEL_SIZE) .overflow_strategy(slog_async::OverflowStrategy::DropAndReport) .build().fuse(), o!() ); - let logger_guard = slog_scope::set_global_logger(log); - - thread::spawn(move || { - loop { - trace!(target: "telemetry", "Connecting to Telemetry... {:?}", config.url); - let _ = ws::connect(config.url.as_str(), |out| Connection::new(out, &*out_sync, &config)); - - thread::sleep(time::Duration::from_millis(5000)); - } + let logger_guard = slog_scope::set_global_logger(root); + + // Spawn a thread for each endpoint + let on_connect = Arc::new(config.on_connect); + config.endpoints.0.into_iter().for_each(|(url, verbosity)| { + let inner_verbosity = Arc::new(verbosity.to_owned()); + let inner_on_connect = Arc::clone(&on_connect); + + let out_sync = out_syncs.remove(0); + let out_sync = Arc::clone(&out_sync); + + thread::spawn(move || { + loop { + let on_connect = Arc::clone(&inner_on_connect); + let out_sync = Arc::clone(&out_sync); + let verbosity = Arc::clone(&inner_verbosity); + + trace!(target: "telemetry", + "Connecting to Telemetry at {} with verbosity {}", url, Arc::clone(&verbosity)); + + let _ = ws::connect(url.to_owned(), + |out| { + Connection::new(out, Arc::clone(&out_sync), Arc::clone(&on_connect), url.clone()) + }); + + // Sleep for a random time between 5-10 secs. If there are general connection + // issues not all threads should be synchronized in their re-connection time. + let random_sleep = thread_rng().gen_range(0, 5); + thread::sleep(time::Duration::from_secs(5) + time::Duration::from_secs(random_sleep)); + } + }); }); return logger_guard; } -/// Exactly equivalent to `slog_scope::info`, provided as a convenience. +/// Translates to `slog_scope::info`, but contains an additional verbosity +/// parameter which the log record is tagged with. Additionally the verbosity +/// parameter is added to the record as a key-value pair. #[macro_export] macro_rules! telemetry { - ( $($t:tt)* ) => { $crate::with_logger(|l| $crate::slog::slog_info!(l, $($t)* )) } + ( $a:expr; $b:expr; $( $t:tt )* ) => { + $crate::with_logger(|l| { + $crate::slog::slog_info!(l, #$a, $b; "verbosity" => stringify!($a), $($t)* ) + }) + } } -struct Connection<'a> { +struct Connection { out: ws::Sender, - out_sync: &'a Mutex>, - config: &'a TelemetryConfig, + out_sync: Arc>>, + on_connect: Arc>, + url: String, } -impl<'a> Connection<'a> { - fn new(out: ws::Sender, out_sync: &'a Mutex>, config: &'a TelemetryConfig) -> Self { +impl Connection { + fn new( + out: ws::Sender, + out_sync: Arc>>, + on_connect: Arc>, + url: String + ) -> Self { Connection { out, out_sync, - config, + on_connect, + url, } } } -impl<'a> ws::Handler for Connection<'a> { +impl ws::Handler for Connection { fn on_open(&mut self, _: ws::Handshake) -> ws::Result<()> { - trace!(target: "telemetry", "Connected!"); + trace!(target: "telemetry", "Connected to {}!", self.url); *self.out_sync.lock() = Some(self.out.clone()); - (self.config.on_connect)(); + (self.on_connect)(); Ok(()) } fn on_close(&mut self, code: ws::CloseCode, reason: &str) { *self.out_sync.lock() = None; - trace!(target: "telemetry", "Connection closing due to ({:?}) {}", code, reason); + trace!(target: "telemetry", "Connection to {} closing due to ({:?}) {}", + self.url, code, reason); } fn on_error(&mut self, _: ws::Error) { @@ -117,15 +222,17 @@ impl<'a> ws::Handler for Connection<'a> { struct TelemetryWriter { buffer: Vec, out: Arc>>, + url: Arc, } impl TelemetryWriter { - fn new() -> Self { + fn new(url: Arc) -> Self { let out = Arc::new(Mutex::new(None)); TelemetryWriter { buffer: Vec::new(), out, + url, } } } @@ -155,11 +262,11 @@ impl io::Write for TelemetryWriter { let error = if let Some(ref mut o) = *out { let r = o.send(s); - trace!(target: "telemetry", "Sent to telemetry: {} -> {:?}", s, r); + trace!(target: "telemetry", "Sent to telemetry {}: {} -> {:?}", self.url, s, r); r.is_err() } else { - trace!(target: "telemetry", "Telemetry socket closed, failed to send: {}", s); + trace!(target: "telemetry", "Telemetry socket closed to {}, failed to send: {}", self.url, s); false }; @@ -171,3 +278,12 @@ impl io::Write for TelemetryWriter { Ok(()) } } + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TelemetryEndpoints (Vec<(String, u8)>); + +impl TelemetryEndpoints { + pub fn new(endpoints: Vec<(String, u8)>) -> Self { + TelemetryEndpoints(endpoints) + } +} diff --git a/core/test-client/Cargo.toml b/core/test-client/Cargo.toml index 467a715de1033e04107de2e8bf1d11ef46419003..5049b2ff9fd62d5511b246a0a90bf25d6be8bd40 100644 --- a/core/test-client/Cargo.toml +++ b/core/test-client/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" client = { package = "substrate-client", path = "../client" } client-db = { package = "substrate-client-db", path = "../client/db", features = ["test-helpers"] } futures = { version = "0.1.17" } -parity-codec = "3.0" +parity-codec = "3.2" executor = { package = "substrate-executor", path = "../executor" } consensus = { package = "substrate-consensus-common", path = "../consensus/common" } keyring = { package = "substrate-keyring", path = "../../core/keyring" } diff --git a/core/test-client/src/block_builder_ext.rs b/core/test-client/src/block_builder_ext.rs index 68f4371d3e27a63b5b5e608e481c259caa37b97d..e427b5789291e705605b553332e0e7f21abffcd7 100644 --- a/core/test-client/src/block_builder_ext.rs +++ b/core/test-client/src/block_builder_ext.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Block Builder extensions for tests. use client; -use keyring; +use super::AccountKeyring; use runtime; use runtime_primitives::traits::ProvideRuntimeApi; use client::block_builder::api::BlockBuilder; @@ -38,9 +38,8 @@ impl<'a, A> BlockBuilderExt for client::block_builder::BlockBuilder<'a, runtime: } fn sign_tx(transfer: runtime::Transfer) -> runtime::Extrinsic { - let signature = keyring::Keyring::from_raw_public(transfer.from.to_fixed_bytes()) + let signature = AccountKeyring::from_public(&transfer.from) .unwrap() - .sign(&parity_codec::Encode::encode(&transfer)) - .into(); + .sign(&parity_codec::Encode::encode(&transfer)); runtime::Extrinsic::Transfer(transfer, signature) } diff --git a/core/test-client/src/client_ext.rs b/core/test-client/src/client_ext.rs index f766f427cd724494f7c34484977ce56af7bc4ddc..511b55ff622806cdd080e9bc9b39295e867dee93 100644 --- a/core/test-client/src/client_ext.rs +++ b/core/test-client/src/client_ext.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/test-client/src/lib.rs b/core/test-client/src/lib.rs index bd2d3a298a04422a58cb4728661874dd91661c78..4a99df65a5467c07d7ce4a29c0a0253d232b39df 100644 --- a/core/test-client/src/lib.rs +++ b/core/test-client/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -29,9 +29,9 @@ pub use client::ExecutionStrategies; pub use client::blockchain; pub use client::backend; pub use executor::NativeExecutor; -pub use keyring; pub use runtime; pub use consensus; +pub use keyring::{AuthorityKeyring, AccountKeyring}; use std::sync::Arc; use futures::future::FutureResult; @@ -39,7 +39,6 @@ use primitives::Blake2Hasher; use runtime_primitives::StorageOverlay; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Hash as HashT, NumberFor}; use runtime::genesismap::{GenesisConfig, additional_storage_with_genesis}; -use keyring::Keyring; use state_machine::ExecutionStrategy; use client::LocalCallExecutor; @@ -129,6 +128,7 @@ pub fn new_with_execution_strategy( syncing: execution_strategy, importing: execution_strategy, block_construction: execution_strategy, + offchain_worker: execution_strategy, other: execution_strategy, }; @@ -165,10 +165,16 @@ pub fn new_with_backend( fn genesis_config(support_changes_trie: bool) -> GenesisConfig { GenesisConfig::new(support_changes_trie, vec![ - Keyring::Alice.to_raw_public().into(), - Keyring::Bob.to_raw_public().into(), - Keyring::Charlie.to_raw_public().into(), - ], 1000) + AuthorityKeyring::Alice.into(), + AuthorityKeyring::Bob.into(), + AuthorityKeyring::Charlie.into(), + ], vec![ + AccountKeyring::Alice.into(), + AccountKeyring::Bob.into(), + AccountKeyring::Charlie.into(), + ], + 1000 + ) } fn genesis_storage(support_changes_trie: bool) -> StorageOverlay { diff --git a/core/test-client/src/trait_tests.rs b/core/test-client/src/trait_tests.rs index 8242f30d2e23f412477a8bdfb0753dea53469084..aa51f7d8bf9e33b24bad88060c5b8dca23a04018 100644 --- a/core/test-client/src/trait_tests.rs +++ b/core/test-client/src/trait_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -20,10 +20,9 @@ #![allow(missing_docs)] use std::sync::Arc; -use keyring::Keyring; use consensus::BlockOrigin; use primitives::Blake2Hasher; -use crate::TestClient; +use crate::{TestClient, AccountKeyring}; use runtime_primitives::traits::Block as BlockT; use crate::backend; use crate::blockchain::{Backend as BlockChainBackendT, HeaderBackend}; @@ -88,8 +87,8 @@ pub fn test_leaves_for_backend(backend: Arc) where let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap(); // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder.push_transfer(Transfer { - from: Keyring::Alice.to_raw_public().into(), - to: Keyring::Ferdie.to_raw_public().into(), + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), amount: 41, nonce: 0, }).unwrap(); @@ -117,8 +116,8 @@ pub fn test_leaves_for_backend(backend: Arc) where let mut builder = client.new_block_at(&BlockId::Hash(b2.hash())).unwrap(); // this push is required as otherwise C3 has the same hash as B3 and won't get imported builder.push_transfer(Transfer { - from: Keyring::Alice.to_raw_public().into(), - to: Keyring::Ferdie.to_raw_public().into(), + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), amount: 1, nonce: 1, }).unwrap(); @@ -132,8 +131,8 @@ pub fn test_leaves_for_backend(backend: Arc) where let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap(); // this push is required as otherwise D2 has the same hash as B2 and won't get imported builder.push_transfer(Transfer { - from: Keyring::Alice.to_raw_public().into(), - to: Keyring::Ferdie.to_raw_public().into(), + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), amount: 1, nonce: 0, }).unwrap(); @@ -180,8 +179,8 @@ pub fn test_children_for_backend(backend: Arc) where let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap(); // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder.push_transfer(Transfer { - from: Keyring::Alice.to_raw_public().into(), - to: Keyring::Ferdie.to_raw_public().into(), + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), amount: 41, nonce: 0, }).unwrap(); @@ -200,8 +199,8 @@ pub fn test_children_for_backend(backend: Arc) where let mut builder = client.new_block_at(&BlockId::Hash(b2.hash())).unwrap(); // this push is required as otherwise C3 has the same hash as B3 and won't get imported builder.push_transfer(Transfer { - from: Keyring::Alice.to_raw_public().into(), - to: Keyring::Ferdie.to_raw_public().into(), + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), amount: 1, nonce: 1, }).unwrap(); @@ -212,8 +211,8 @@ pub fn test_children_for_backend(backend: Arc) where let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap(); // this push is required as otherwise D2 has the same hash as B2 and won't get imported builder.push_transfer(Transfer { - from: Keyring::Alice.to_raw_public().into(), - to: Keyring::Ferdie.to_raw_public().into(), + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), amount: 1, nonce: 0, }).unwrap(); @@ -269,8 +268,8 @@ pub fn test_blockchain_query_by_number_gets_canonical(backend: Arc(backend: Arc(backend: Arc, - pub authorities: Vec, - pub balances: Vec<(Ed25519AuthorityId, u64)>, + pub authorities: Vec, + pub balances: Vec<(AccountId, u64)>, } impl GenesisConfig { - pub fn new_simple(authorities: Vec, balance: u64) -> Self { - Self::new(false, authorities, balance) - } - - pub fn new(support_changes_trie: bool, authorities: Vec, balance: u64) -> Self { + pub fn new(support_changes_trie: bool, authorities: Vec, endowed_accounts: Vec, balance: u64) -> Self { GenesisConfig { changes_trie_config: match support_changes_trie { true => Some(super::changes_trie_config()), false => None, }, authorities: authorities.clone(), - balances: authorities.into_iter().map(|a| (a, balance)).collect(), + balances: endowed_accounts.into_iter().map(|a| (a, balance)).collect(), } } pub fn genesis_map(&self) -> HashMap, Vec> { let wasm_runtime = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm").to_vec(); let mut map: HashMap, Vec> = self.balances.iter() - .map(|&(account, balance)| (account.to_keyed_vec(b"balance:"), vec![].and(&balance))) + .map(|&(ref account, balance)| (account.to_keyed_vec(b"balance:"), vec![].and(&balance))) .map(|(k, v)| (twox_128(&k[..])[..].to_vec(), v.to_vec())) .chain(vec![ (well_known_keys::CODE.into(), wasm_runtime), diff --git a/core/test-runtime/src/lib.rs b/core/test-runtime/src/lib.rs index cf1d6efed6d0f91140f6b6b24c7adc8b7a1aef0a..e41950486162f468fccc0019d035ab9882734cc0 100644 --- a/core/test-runtime/src/lib.rs +++ b/core/test-runtime/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -18,24 +18,23 @@ #![cfg_attr(not(feature = "std"), no_std)] -#[cfg(feature = "std")] pub mod genesismap; +#[cfg(feature = "std")] +pub mod genesismap; pub mod system; use rstd::{prelude::*, marker::PhantomData}; use parity_codec::{Encode, Decode, Input}; -use parity_codec_derive::{Encode, Decode}; use primitives::Blake2Hasher; -use memory_db::MemoryDB; use trie_db::{TrieMut, Trie}; -use substrate_trie::{TrieDB, TrieDBMut}; +use substrate_trie::{TrieDB, TrieDBMut, PrefixedMemoryDB}; use substrate_client::{ runtime_api as client_api, block_builder::api as block_builder_api, decl_runtime_apis, impl_runtime_apis, }; use runtime_primitives::{ - ApplyResult, Ed25519Signature, transaction_validity::TransactionValidity, + ApplyResult, transaction_validity::TransactionValidity, create_runtime_str, traits::{ BlindCheckable, BlakeTwo256, Block as BlockT, Extrinsic as ExtrinsicT, @@ -44,7 +43,7 @@ use runtime_primitives::{ }; use runtime_version::RuntimeVersion; pub use primitives::hash::H256; -use primitives::{Ed25519AuthorityId, OpaqueMetadata}; +use primitives::{ed25519, sr25519, OpaqueMetadata}; #[cfg(any(feature = "std", test))] use runtime_version::NativeVersion; use inherents::{CheckInherentsResult, InherentData}; @@ -83,12 +82,23 @@ pub struct Transfer { pub nonce: u64, } +impl Transfer { + /// Convert into a signed extrinsic. + #[cfg(feature = "std")] + pub fn into_signed_tx(self) -> Extrinsic { + let signature = keyring::AccountKeyring::from_public(&self.from) + .expect("Creates keyring from public key.").sign(&self.encode()).into(); + Extrinsic::Transfer(self, signature) + } +} + /// Extrinsic for test-runtime. #[derive(Clone, PartialEq, Eq, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug))] pub enum Extrinsic { - AuthoritiesChange(Vec), - Transfer(Transfer, Ed25519Signature), + AuthoritiesChange(Vec), + Transfer(Transfer, AccountSignature), + IncludeData(Vec), } #[cfg(feature = "std")] @@ -112,6 +122,7 @@ impl BlindCheckable for Extrinsic { Err(runtime_primitives::BAD_SIGNATURE) } }, + Extrinsic::IncludeData(data) => Ok(Extrinsic::IncludeData(data)), } } } @@ -131,8 +142,14 @@ impl Extrinsic { } } +// The identity type used by authorities. +pub type AuthorityId = ed25519::Public; +// The signature type used by authorities. +pub type AuthoritySignature = ed25519::Signature; /// An identifier for an account on this system. -pub type AccountId = H256; +pub type AccountId = sr25519::Public; +// The signature type used by accounts/transactions. +pub type AccountSignature = sr25519::Signature; /// A simple hash type for all our hashing. pub type Hash = H256; /// The block number type used in this runtime. @@ -140,7 +157,7 @@ pub type BlockNumber = u64; /// Index of a transaction. pub type Index = u64; /// The item of a block digest. -pub type DigestItem = runtime_primitives::generic::DigestItem; +pub type DigestItem = runtime_primitives::generic::DigestItem; /// The digest of a block. pub type Digest = runtime_primitives::generic::Digest; /// A test block. @@ -203,7 +220,7 @@ cfg_if! { pub trait TestAPI { /// Return the balance of the given account id. fn balance_of(id: AccountId) -> u64; - /// A benchmkark function that adds one to the given value and returns the result. + /// A benchmark function that adds one to the given value and returns the result. fn benchmark_add_one(val: &u64) -> u64; /// A benchmark function that adds one to each value in the given vector and returns the /// result. @@ -221,6 +238,8 @@ cfg_if! { fn fail_on_wasm() -> u64; /// trie no_std testing fn use_trie() -> u64; + fn benchmark_indirect_call() -> u64; + fn benchmark_direct_call() -> u64; } } } else { @@ -228,7 +247,7 @@ cfg_if! { pub trait TestAPI { /// Return the balance of the given account id. fn balance_of(id: AccountId) -> u64; - /// A benchmkark function that adds one to the given value and returns the result. + /// A benchmark function that adds one to the given value and returns the result. fn benchmark_add_one(val: &u64) -> u64; /// A benchmark function that adds one to each value in the given vector and returns the /// result. @@ -243,6 +262,8 @@ cfg_if! { fn fail_on_wasm() -> u64; /// trie no_std testing fn use_trie() -> u64; + fn benchmark_indirect_call() -> u64; + fn benchmark_direct_call() -> u64; } } } @@ -258,6 +279,16 @@ impl GetRuntimeBlockType for Runtime { type RuntimeBlock = Block; } +/// Adds one to the given input and returns the final result. +#[inline(never)] +fn benchmark_add_one(i: u64) -> u64 { + i + 1 +} + +/// The `benchmark_add_one` function as function pointer. +#[cfg(not(feature = "std"))] +static BENCHMARK_ADD_ONE: runtime_io::ExchangeableFunction u64> = runtime_io::ExchangeableFunction::new(benchmark_add_one); + cfg_if! { if #[cfg(feature = "std")] { impl_runtime_apis! { @@ -266,7 +297,7 @@ cfg_if! { version() } - fn authorities() -> Vec { + fn authorities() -> Vec { system::authorities() } @@ -351,10 +382,10 @@ cfg_if! { (b"0103000000000000000469".to_vec(), b"0401000000".to_vec()), ]; - let mut mdb = MemoryDB::default(); + let mut mdb = PrefixedMemoryDB::default(); let mut root = rstd::default::Default::default(); let _ = { - let v = &pairs; + let v = &pairs; let mut t = TrieDBMut::::new(&mut mdb, &mut root); for i in 0..v.len() { let key: &[u8]= &v[i].0; @@ -375,12 +406,25 @@ cfg_if! { iter_pairs.len() as u64 } - + fn benchmark_indirect_call() -> u64 { + let function = benchmark_add_one; + (0..1000).fold(0, |p, i| p + function(i)) + } + fn benchmark_direct_call() -> u64 { + (0..1000).fold(0, |p, i| p + benchmark_add_one(i)) + } } impl consensus_aura::AuraApi for Runtime { fn slot_duration() -> u64 { 1 } } + + impl offchain_primitives::OffchainWorkerApi for Runtime { + fn offchain_worker(block: u64) { + let ex = Extrinsic::IncludeData(block.encode()); + runtime_io::submit_extrinsic(&ex) + } + } } } else { impl_runtime_apis! { @@ -389,7 +433,7 @@ cfg_if! { version() } - fn authorities() -> Vec { + fn authorities() -> Vec { system::authorities() } @@ -478,10 +522,10 @@ cfg_if! { (b"0103000000000000000469".to_vec(), b"0401000000".to_vec()), ].to_vec(); - let mut mdb = MemoryDB::default(); + let mut mdb = PrefixedMemoryDB::default(); let mut root = rstd::default::Default::default(); let _ = { - let v = &pairs; + let v = &pairs; let mut t = TrieDBMut::::new(&mut mdb, &mut root); for i in 0..v.len() { let key: &[u8]= &v[i].0; @@ -501,6 +545,14 @@ cfg_if! { } iter_pairs.len() as u64 } + + fn benchmark_indirect_call() -> u64 { + (0..10000).fold(0, |p, i| p + BENCHMARK_ADD_ONE.get()(i)) + } + + fn benchmark_direct_call() -> u64 { + (0..10000).fold(0, |p, i| p + benchmark_add_one(i)) + } } @@ -508,6 +560,13 @@ cfg_if! { impl consensus_aura::AuraApi for Runtime { fn slot_duration() -> u64 { 1 } } + + impl offchain_primitives::OffchainWorkerApi for Runtime { + fn offchain_worker(block: u64) { + let ex = Extrinsic::IncludeData(block.encode()); + runtime_io::submit_extrinsic(&ex) + } + } } } } diff --git a/core/test-runtime/src/system.rs b/core/test-runtime/src/system.rs index 110666a6e06a0db7ec8f83fdd48237d4030b488a..ffc01182d47fdb8a21f007f0085f94dfb49648b3 100644 --- a/core/test-runtime/src/system.rs +++ b/core/test-runtime/src/system.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -21,13 +21,13 @@ use rstd::prelude::*; use runtime_io::{storage_root, enumerated_trie_root, storage_changes_root, twox_128}; use runtime_support::storage::{self, StorageValue, StorageMap}; use runtime_support::storage_items; -use runtime_primitives::traits::{Hash as HashT, BlakeTwo256, Digest as DigestT}; +use runtime_primitives::traits::{Hash as HashT, BlakeTwo256, Digest as DigestT, NumberFor, Block as BlockT}; use runtime_primitives::generic; use runtime_primitives::{ApplyError, ApplyOutcome, ApplyResult, transaction_validity::TransactionValidity}; use parity_codec::{KeyedVec, Encode}; use super::{AccountId, BlockNumber, Extrinsic, Transfer, H256 as Hash, Block, Header, Digest}; -use primitives::{Ed25519AuthorityId, Blake2Hasher}; -use primitives::storage::well_known_keys; +use primitives::{Blake2Hasher, storage::well_known_keys}; +use primitives::ed25519::Public as AuthorityId; const NONCE_OF: &[u8] = b"nonce:"; const BALANCE_OF: &[u8] = b"balance:"; @@ -37,7 +37,7 @@ storage_items! { // The current block number being processed. Set by `execute_block`. Number: b"sys:num" => required BlockNumber; ParentHash: b"sys:pha" => required Hash; - NewAuthorities: b"sys:new_auth" => Vec; + NewAuthorities: b"sys:new_auth" => Vec; } pub fn balance_of_key(who: AccountId) -> Vec { @@ -52,8 +52,8 @@ pub fn nonce_of(who: AccountId) -> u64 { storage::get_or(&who.to_keyed_vec(NONCE_OF), 0) } -/// Get authorities ar given block. -pub fn authorities() -> Vec { +/// Get authorities at given block. +pub fn authorities() -> Vec { let len: u32 = storage::unhashed::get(well_known_keys::AUTHORITY_COUNT) .expect("There are always authorities in test-runtime"); (0..len) @@ -70,24 +70,58 @@ pub fn initialise_block(header: &Header) { storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &0u32); } +fn execute_extrinsics_without_checks(extrinsics: Vec<::Extrinsic>) { + // execute transactions + extrinsics.into_iter().enumerate().for_each(|(i, e)| { + storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &(i as u32)); + execute_transaction_backend(&e).unwrap_or_else(|_| panic!("Invalid transaction")); + storage::unhashed::kill(well_known_keys::EXTRINSIC_INDEX); + }); +} + /// Actually execute all transitioning for `block`. -pub fn execute_block(block: Block) { - let ref header = block.header; +pub fn polish_block(block: &mut Block) { + let header = &mut block.header; // check transaction trie root represents the transactions. let txs = block.extrinsics.iter().map(Encode::encode).collect::>(); let txs = txs.iter().map(Vec::as_slice).collect::>(); let txs_root = enumerated_trie_root::(&txs).into(); info_expect_equal_hash(&txs_root, &header.extrinsics_root); - assert!(txs_root == header.extrinsics_root, "Transaction trie root must be valid."); + header.extrinsics_root = txs_root; // execute transactions block.extrinsics.iter().enumerate().for_each(|(i, e)| { storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &(i as u32)); - execute_transaction_backend(e).map_err(|_| ()).expect("Extrinsic error"); + execute_transaction_backend(e).unwrap_or_else(|_| panic!("Invalid transaction")); storage::unhashed::kill(well_known_keys::EXTRINSIC_INDEX); }); + header.state_root = storage_root().into(); + + // check digest + let mut digest = Digest::default(); + if let Some(storage_changes_root) = storage_changes_root(header.parent_hash.into(), header.number - 1) { + digest.push(generic::DigestItem::ChangesTrieRoot(storage_changes_root.into())); + } + if let Some(new_authorities) = ::take() { + digest.push(generic::DigestItem::AuthoritiesChange(new_authorities)); + } + header.digest = digest; +} + +pub fn execute_block(block: Block) { + let ref header = block.header; + + // check transaction trie root represents the transactions. + let txs = block.extrinsics.iter().map(Encode::encode).collect::>(); + let txs = txs.iter().map(Vec::as_slice).collect::>(); + let txs_root = enumerated_trie_root::(&txs).into(); + info_expect_equal_hash(&txs_root, &header.extrinsics_root); + assert!(txs_root == header.extrinsics_root, "Transaction trie root must be valid."); + + execute_extrinsics_without_checks(block.extrinsics); + // check storage root. let storage_root = storage_root().into(); info_expect_equal_hash(&storage_root, &header.state_root); @@ -104,6 +138,19 @@ pub fn execute_block(block: Block) { assert!(digest == header.digest, "Header digest items must match that calculated."); } +/// The block executor. +pub struct BlockExecutor; + +impl executive::ExecuteBlock for BlockExecutor { + fn execute_block(block: Block) { + execute_block(block); + } + + fn execute_extrinsics_without_checks(_: NumberFor, extrinsics: Vec<::Extrinsic>) { + execute_extrinsics_without_checks(extrinsics); + } +} + /// Execute a transaction outside of the block execution function. /// This doesn't attempt to validate anything regarding the block. pub fn validate_transaction(utx: Extrinsic) -> TransactionValidity { @@ -122,7 +169,7 @@ pub fn validate_transaction(utx: Extrinsic) -> TransactionValidity { } let hash = |from: &AccountId, nonce: u64| { - twox_128(&nonce.to_keyed_vec(from.as_bytes())).to_vec() + twox_128(&nonce.to_keyed_vec(&from.encode())).to_vec() }; let requires = if tx.nonce != expected_nonce && tx.nonce > 0 { let mut deps = Vec::new(); @@ -144,7 +191,6 @@ pub fn validate_transaction(utx: Extrinsic) -> TransactionValidity { } } - /// Execute a transaction outside of the block execution function. /// This doesn't attempt to validate anything regarding the block. pub fn execute_transaction(utx: Extrinsic) -> ApplyResult { @@ -196,6 +242,7 @@ fn execute_transaction_backend(utx: &Extrinsic) -> ApplyResult { match utx { Extrinsic::Transfer(ref transfer, _) => execute_transfer_backend(transfer), Extrinsic::AuthoritiesChange(ref new_auth) => execute_new_authorities_backend(new_auth), + Extrinsic::IncludeData(_) => Ok(ApplyOutcome::Success), } } @@ -225,8 +272,8 @@ fn execute_transfer_backend(tx: &Transfer) -> ApplyResult { Ok(ApplyOutcome::Success) } -fn execute_new_authorities_backend(new_authorities: &[Ed25519AuthorityId]) -> ApplyResult { - let new_authorities: Vec = new_authorities.iter().cloned().collect(); +fn execute_new_authorities_backend(new_authorities: &[AuthorityId]) -> ApplyResult { + let new_authorities: Vec = new_authorities.iter().cloned().collect(); ::put(new_authorities); Ok(ApplyOutcome::Success) } @@ -258,12 +305,11 @@ mod tests { use runtime_io::{with_externalities, twox_128, TestExternalities}; use parity_codec::{Joiner, KeyedVec}; - use keyring::Keyring; - use crate::{Header, Digest, Extrinsic, Transfer}; + use substrate_test_client::{AuthorityKeyring, AccountKeyring}; + use crate::{Header, Transfer}; use primitives::{Blake2Hasher, map}; use primitives::storage::well_known_keys; use substrate_executor::WasmExecutor; - use hex_literal::{hex, hex_impl}; const WASM_CODE: &'static [u8] = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm"); @@ -272,36 +318,29 @@ mod tests { TestExternalities::new(map![ twox_128(b"latest").to_vec() => vec![69u8; 32], twox_128(well_known_keys::AUTHORITY_COUNT).to_vec() => vec![].and(&3u32), - twox_128(&0u32.to_keyed_vec(well_known_keys::AUTHORITY_PREFIX)).to_vec() => Keyring::Alice.to_raw_public().to_vec(), - twox_128(&1u32.to_keyed_vec(well_known_keys::AUTHORITY_PREFIX)).to_vec() => Keyring::Bob.to_raw_public().to_vec(), - twox_128(&2u32.to_keyed_vec(well_known_keys::AUTHORITY_PREFIX)).to_vec() => Keyring::Charlie.to_raw_public().to_vec(), - twox_128(&Keyring::Alice.to_raw_public().to_keyed_vec(b"balance:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0] + twox_128(&0u32.to_keyed_vec(well_known_keys::AUTHORITY_PREFIX)).to_vec() => AuthorityKeyring::Alice.to_raw_public().to_vec(), + twox_128(&1u32.to_keyed_vec(well_known_keys::AUTHORITY_PREFIX)).to_vec() => AuthorityKeyring::Bob.to_raw_public().to_vec(), + twox_128(&2u32.to_keyed_vec(well_known_keys::AUTHORITY_PREFIX)).to_vec() => AuthorityKeyring::Charlie.to_raw_public().to_vec(), + twox_128(&AccountKeyring::Alice.to_raw_public().to_keyed_vec(b"balance:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0] ]) } - fn construct_signed_tx(tx: Transfer) -> Extrinsic { - let signature = Keyring::from_raw_public(tx.from.to_fixed_bytes()).unwrap().sign(&tx.encode()).into(); - Extrinsic::Transfer(tx, signature) - } - fn block_import_works(block_executor: F) where F: Fn(Block, &mut TestExternalities) { - let mut t = new_test_ext(); - let h = Header { parent_hash: [69u8; 32].into(), number: 1, - state_root: hex!("e51369d0b37e4aa1383f1e7a34c2eec75f18ee6b4b199a440f4f2456906e0eb7").into(), - extrinsics_root: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").into(), - digest: Digest { logs: vec![], }, + state_root: Default::default(), + extrinsics_root: Default::default(), + digest: Default::default(), }; - - let b = Block { + let mut b = Block { header: h, extrinsics: vec![], }; - block_executor(b, &mut t); + with_externalities(&mut new_test_ext(), || polish_block(&mut b)); + block_executor(b, &mut new_test_ext()); } #[test] @@ -321,69 +360,74 @@ mod tests { } fn block_import_with_transaction_works(block_executor: F) where F: Fn(Block, &mut TestExternalities) { - let mut t = new_test_ext(); - - with_externalities(&mut t, || { - assert_eq!(balance_of(Keyring::Alice.to_raw_public().into()), 111); - assert_eq!(balance_of(Keyring::Bob.to_raw_public().into()), 0); - }); - - let b = Block { + let mut b1 = Block { header: Header { parent_hash: [69u8; 32].into(), number: 1, - state_root: hex!("f61a14ce70846cd6a1714bbe1b63b2ca1172df1c8c01adfd798bb08bd30dc486").into(), - extrinsics_root: hex!("198205cb7729fec8ccdc2e58571a4858586a4f305898078e0e8bee1dddea7e4b").into(), - digest: Digest { logs: vec![], }, + state_root: Default::default(), + extrinsics_root: Default::default(), + digest: Default::default(), }, extrinsics: vec![ - construct_signed_tx(Transfer { - from: Keyring::Alice.to_raw_public().into(), - to: Keyring::Bob.to_raw_public().into(), + Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Bob.into(), amount: 69, nonce: 0, - }) + }.into_signed_tx() ], }; - with_externalities(&mut t, || { - execute_block(b.clone()); - - assert_eq!(balance_of(Keyring::Alice.to_raw_public().into()), 42); - assert_eq!(balance_of(Keyring::Bob.to_raw_public().into()), 69); - }); + let mut dummy_ext = new_test_ext(); + with_externalities(&mut dummy_ext, || polish_block(&mut b1)); - let b = Block { + let mut b2 = Block { header: Header { - parent_hash: b.header.hash(), + parent_hash: b1.header.hash(), number: 2, - state_root: hex!("a47383d9a5d6c8c7531386abccdf512c76729a1a19c59b6c2e4f95dde419923a").into(), - extrinsics_root: hex!("041fa8971dda28745967179a9f39e3ca1a595c510682105df1cff74ae6f05e0d").into(), - digest: Digest { logs: vec![], }, + state_root: Default::default(), + extrinsics_root: Default::default(), + digest: Default::default(), }, extrinsics: vec![ - construct_signed_tx(Transfer { - from: Keyring::Bob.to_raw_public().into(), - to: Keyring::Alice.to_raw_public().into(), + Transfer { + from: AccountKeyring::Bob.into(), + to: AccountKeyring::Alice.into(), amount: 27, nonce: 0, - }), - construct_signed_tx(Transfer { - from: Keyring::Alice.to_raw_public().into(), - to: Keyring::Charlie.to_raw_public().into(), + }.into_signed_tx(), + Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Charlie.into(), amount: 69, nonce: 1, - }), + }.into_signed_tx(), ], }; - block_executor(b, &mut t); + with_externalities(&mut dummy_ext, || polish_block(&mut b2)); + drop(dummy_ext); + + let mut t = new_test_ext(); with_externalities(&mut t, || { + assert_eq!(balance_of(AccountKeyring::Alice.into()), 111); + assert_eq!(balance_of(AccountKeyring::Bob.into()), 0); + }); + + block_executor(b1, &mut t); - assert_eq!(balance_of(Keyring::Alice.to_raw_public().into()), 0); - assert_eq!(balance_of(Keyring::Bob.to_raw_public().into()), 42); - assert_eq!(balance_of(Keyring::Charlie.to_raw_public().into()), 69); + with_externalities(&mut t, || { + assert_eq!(balance_of(AccountKeyring::Alice.into()), 42); + assert_eq!(balance_of(AccountKeyring::Bob.into()), 69); + }); + + block_executor(b2, &mut t); + + with_externalities(&mut t, || { + assert_eq!(balance_of(AccountKeyring::Alice.into()), 0); + assert_eq!(balance_of(AccountKeyring::Bob.into()), 42); + assert_eq!(balance_of(AccountKeyring::Charlie.into()), 69); }); } diff --git a/core/test-runtime/wasm/Cargo.lock b/core/test-runtime/wasm/Cargo.lock index 0b4d9fde10bbfa39f059bff5128f090bcf62182d..de782afb9879022583407ab60b8f7ca3473f361d 100644 --- a/core/test-runtime/wasm/Cargo.lock +++ b/core/test-runtime/wasm/Cargo.lock @@ -1,5 +1,57 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[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.6.10" +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.25 (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.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-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "arrayref" version = "0.3.5" @@ -7,49 +59,102 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "arrayvec" -version = "0.4.8" +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.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "autocfg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "backtrace" -version = "0.3.9" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.2 (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.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "backtrace-sys" -version = "0.1.24" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "base-x" +version = "0.2.4" +source = "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 = "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 = "git+https://github.com/paritytech/bitmask#a84e147be602631617badd18b6b9af83391db4a9" + +[[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.8 (registry+https://github.com/rust-lang/crates.io-index)", + "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)", ] @@ -69,7 +174,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-padding 0.1.3 (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.2.7 (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)", ] @@ -81,6 +194,11 @@ 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 = "byte-tools" version = "0.2.0" @@ -93,26 +211,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "byteorder" -version = "1.2.7" +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.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "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 = "cc" -version = "1.0.29" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -122,7 +245,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -130,7 +253,7 @@ name = "clear_on_drop" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -148,46 +271,105 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "crossbeam" -version = "0.2.12" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.7 (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.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "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.6.2" +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.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.2 (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)", ] [[package]] name = "crossbeam-epoch" -version = "0.6.1" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (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.7 (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.6.2" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.7 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -209,18 +391,50 @@ dependencies = [ "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.0.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "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 0.6.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.0.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 = "digest" version = "0.6.2" @@ -237,18 +451,37 @@ dependencies = [ "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "discard" +version = "1.0.4" +source = "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.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek 1.1.3 (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.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)", ] +[[package]] +name = "either" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "elastic-array" version = "0.10.2" @@ -259,7 +492,7 @@ dependencies = [ [[package]] name = "environmental" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -267,13 +500,28 @@ name = "error-chain" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.14 (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.14 (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.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "fake-simd" @@ -285,10 +533,10 @@ name = "fixed-hash" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "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.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (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)", ] @@ -311,6 +559,11 @@ name = "foreign-types-shared" version = "0.1.1" 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" @@ -330,6 +583,15 @@ name = "futures" version = "0.1.25" 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.25 (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 = "generic-array" version = "0.8.3" @@ -349,16 +611,24 @@ dependencies = [ [[package]] name = "hash-db" -version = "0.11.0" +version = "0.12.2" [[package]] name = "hash256-std-hasher" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.12.2" dependencies = [ "crunchy 0.2.1 (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" @@ -372,9 +642,22 @@ dependencies = [ "winapi 0.3.6 (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.2.1 (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.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -399,6 +682,15 @@ dependencies = [ "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" @@ -421,7 +713,7 @@ 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.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -429,7 +721,7 @@ name = "impl-codec" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -438,7 +730,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.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -451,7 +743,7 @@ name = "iovec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -485,12 +777,7 @@ dependencies = [ [[package]] name = "lazy_static" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lazy_static" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -500,9 +787,328 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.48" +version = "0.2.50" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "libp2p" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (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.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-core-derive 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-dns 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-floodsub 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-identify 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-kad 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-mdns 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-mplex 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-noise 0.3.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-ping 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-plaintext 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-ratelimit 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-secio 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-tcp 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-uds 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-yamux 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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)", + "stdweb 0.4.15 (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.6 (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-core" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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.25 (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)", + "multistream-select 0.3.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.4.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.1 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "secp256k1 0.12.0 (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.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-timer 0.2.10 (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)", + "zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libp2p-core-derive" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libp2p-dns" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "protobuf 2.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)", + "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.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.4.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)", + "tokio-timer 0.2.10 (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)", +] + +[[package]] +name = "libp2p-kad" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-identify 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-ping 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.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)", + "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)", + "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)", +] + +[[package]] +name = "libp2p-mdns" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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-timer 0.2.10 (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)", +] + +[[package]] +name = "libp2p-mplex" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.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-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.3.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "curve25519-dalek 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (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.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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)", + "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.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-ping" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parking_lot 0.7.1 (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)", + "tokio-timer 0.2.10 (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-plaintext" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libp2p-ratelimit" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "aio-limited 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 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)", +] + +[[package]] +name = "libp2p-secio" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "hmac 0.7.0 (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.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.4.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.1 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "stdweb 0.4.15 (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)", +] + +[[package]] +name = "libp2p-tcp" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libp2p-yamux" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "libsecp256k1" version = "0.2.2" @@ -511,7 +1117,7 @@ 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.3 (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)", ] @@ -530,7 +1136,7 @@ name = "log" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -538,6 +1144,11 @@ 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" @@ -545,9 +1156,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memory-db" -version = "0.11.0" +version = "0.12.2" dependencies = [ - "hash-db 0.11.0", + "hash-db 0.12.2", "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)", ] @@ -559,14 +1170,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "merlin" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "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 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.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]] @@ -579,11 +1189,11 @@ dependencies = [ "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)", "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (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.1 (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)", ] @@ -595,7 +1205,7 @@ dependencies = [ "lazycell 1.2.1 (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.16 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -604,7 +1214,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.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -619,13 +1229,27 @@ dependencies = [ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "multistream-select" +version = "0.3.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -634,6 +1258,11 @@ 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 = "num-integer" version = "0.1.39" @@ -649,16 +1278,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "once_cell" -version = "0.1.6" +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" @@ -667,28 +1299,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl" -version = "0.10.16" +version = "0.10.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (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.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.40 (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.50 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "openssl-sys" -version = "0.9.40" +version = "0.9.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.6 (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" @@ -704,21 +1345,50 @@ source = "git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7 [[package]] name = "parity-codec" -version = "3.0.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "parity-codec-derive" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-crate 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parity-multiaddr" +version = "0.2.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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)", + "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "serde 1.0.89 (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-multihash" +version = "0.1.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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)", + "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.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]] @@ -726,7 +1396,16 @@ name = "parity-wasm" version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "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]] @@ -747,15 +1426,26 @@ dependencies = [ "parking_lot_core 0.4.0 (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.50 (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.6 (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.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (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.7 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -764,10 +1454,10 @@ name = "parking_lot_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (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.7 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -786,9 +1476,19 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-hack 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (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]] @@ -833,9 +1533,9 @@ name = "proc-macro-hack" version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -845,135 +1545,234 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "0.4.24" +version = "0.4.27" 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.4.0" +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.10" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.4.3" +version = "0.3.23" 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)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (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.50 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.5.5" +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-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.2.2 (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.50 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.6.1" +version = "0.6.5" 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-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (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_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.3 (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.6 (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.2 (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.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (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_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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.50 (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.6 (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.50 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rand_core" -version = "0.2.2" +name = "rand_pcg" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.2 (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_core" -version = "0.3.0" +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 = "rand_hc" -version = "0.1.0" +name = "rayon" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.1 (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 = "rand_isaac" -version = "0.1.1" +name = "rayon-core" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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.50 (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 = "rand_pcg" -version = "0.1.1" +name = "rdrand" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (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_xorshift" -version = "0.1.0" +name = "redox_syscall" +version = "0.1.51" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "regex" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.6.10 (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.5 (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 = "redox_syscall" -version = "0.1.43" +name = "regex-syntax" +version = "0.6.5" 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.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.30 (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.50 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-demangle" -version = "0.1.9" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -989,23 +1788,59 @@ dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rw-stream-sink" +version = "0.1.1" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (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.7" 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.0.0" +source = "git+https://github.com/w3f/schnorrkel#3179838da9dd4896c12bb910e7c42477a3250641" +dependencies = [ + "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek 1.1.3 (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.0.3 (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.1 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "schnorrkel" +version = "0.1.0" 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.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek 1.1.3 (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.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "merlin 1.0.3 (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.1 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1015,6 +1850,16 @@ name = "scopeguard" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "secp256k1" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "semver" version = "0.9.0" @@ -1030,27 +1875,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.81" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.81" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.33" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1095,7 +1940,7 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1119,27 +1964,41 @@ 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)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (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.0.1" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "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.7" +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 = [ - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1153,19 +2012,19 @@ version = "0.1.0" dependencies = [ "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-crate 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "sr-io" version = "0.1.0" dependencies = [ - "environmental 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.11.0", + "environmental 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (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 0.1.0", "substrate-primitives 0.1.0", @@ -1181,10 +2040,9 @@ 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.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-std 0.1.0", "substrate-primitives 0.1.0", @@ -1202,22 +2060,33 @@ name = "sr-version" version = "0.1.0" dependencies = [ "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-primitives 0.1.0", + "sr-std 0.1.0", +] + +[[package]] +name = "srml-executive" +version = "0.1.0" +dependencies = [ + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", + "srml-support 0.1.0", + "srml-system 0.1.0", ] [[package]] name = "srml-metadata" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 0.1.0", "substrate-primitives 0.1.0", ] @@ -1226,13 +2095,13 @@ dependencies = [ name = "srml-support" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitmask 0.5.0 (git+https://github.com/paritytech/bitmask)", + "hex-literal 0.1.3 (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.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "paste 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", @@ -1245,11 +2114,11 @@ dependencies = [ name = "srml-support-procedural" version = "0.1.0" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "sr-api-macros 0.1.0", "srml-support-procedural-tools 0.1.0", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1257,19 +2126,35 @@ name = "srml-support-procedural-tools" version = "0.1.0" dependencies = [ "proc-macro-crate 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "srml-support-procedural-tools-derive 0.1.0", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "srml-support-procedural-tools-derive" version = "0.1.0" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "srml-system" +version = "0.1.0" +dependencies = [ + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.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.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 0.1.0", + "sr-primitives 0.1.0", + "sr-std 0.1.0", + "srml-support 0.1.0", + "substrate-primitives 0.1.0", ] [[package]] @@ -1282,6 +2167,90 @@ 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 = "stdweb" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "stdweb-derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "stdweb-internal-macros 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "stdweb-internal-runtime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base-x 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.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.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "substrate-bip39" +version = "0.2.0" +source = "git+https://github.com/paritytech/substrate-bip39#a28806512c977992af8d6740d45352f5a1c832a0" +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.0.0 (git+https://github.com/w3f/schnorrkel)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "substrate-client" version = "0.1.0" @@ -1289,13 +2258,12 @@ dependencies = [ "error-chain 0.12.0 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.11.0", + "hash-db 0.12.2", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-api-macros 0.1.0", "sr-primitives 0.1.0", @@ -1307,7 +2275,7 @@ dependencies = [ "substrate-keyring 0.1.0", "substrate-primitives 0.1.0", "substrate-state-machine 0.1.0", - "substrate-telemetry 0.3.0", + "substrate-telemetry 0.3.1", "substrate-trie 0.4.0", ] @@ -1322,32 +2290,33 @@ dependencies = [ name = "substrate-consensus-common" version = "0.1.0" dependencies = [ - "crossbeam-channel 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-version 0.1.0", "substrate-inherents 0.1.0", "substrate-primitives 0.1.0", - "tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "substrate-executor" version = "0.1.0" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-version 0.1.0", "substrate-panic-handler 0.1.0", @@ -1363,8 +2332,7 @@ dependencies = [ name = "substrate-inherents" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", @@ -1374,16 +2342,26 @@ dependencies = [ name = "substrate-keyring" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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 0.1.0", ] +[[package]] +name = "substrate-offchain-primitives" +version = "0.1.0" +dependencies = [ + "sr-primitives 0.1.0", + "substrate-client 0.1.0", +] + [[package]] name = "substrate-panic-handler" version = "0.1.0" dependencies = [ - "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1393,22 +2371,25 @@ version = "0.1.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.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.11.0", - "hash256-std-hasher 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", + "hash256-std-hasher 0.12.2", + "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "primitive-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.14.5 (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.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.14.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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "schnorrkel 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 0.1.0", + "substrate-bip39 0.2.0 (git+https://github.com/paritytech/substrate-bip39)", + "tiny-bip39 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "twox-hash 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmi 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1418,38 +2399,41 @@ dependencies = [ name = "substrate-serializer" version = "0.1.0" dependencies = [ - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (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 = "0.1.0" dependencies = [ - "hash-db 0.11.0", + "hash-db 0.12.2", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 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)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-panic-handler 0.1.0", "substrate-primitives 0.1.0", "substrate-trie 0.4.0", - "trie-db 0.11.0", - "trie-root 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-db 0.12.2", + "trie-root 0.12.2", ] [[package]] name = "substrate-telemetry" -version = "0.3.0" +version = "0.3.1" dependencies = [ - "lazy_static 1.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)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (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.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "slog-async 2.3.0 (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.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slog-scope 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ws 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1457,26 +2441,27 @@ dependencies = [ name = "substrate-test-runtime" version = "0.1.0" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 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)", - "memory-db 0.11.0", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "memory-db 0.12.2", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", "sr-version 0.1.0", + "srml-executive 0.1.0", "srml-support 0.1.0", "substrate-client 0.1.0", "substrate-consensus-aura-primitives 0.1.0", "substrate-inherents 0.1.0", "substrate-keyring 0.1.0", + "substrate-offchain-primitives 0.1.0", "substrate-primitives 0.1.0", "substrate-trie 0.4.0", - "trie-db 0.11.0", + "trie-db 0.12.2", ] [[package]] @@ -1490,14 +2475,19 @@ dependencies = [ name = "substrate-trie" version = "0.4.0" dependencies = [ - "hash-db 0.11.0", - "memory-db 0.11.0", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", + "memory-db 0.12.2", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 0.1.0", - "trie-db 0.11.0", - "trie-root 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-db 0.12.2", + "trie-root 0.12.2", ] +[[package]] +name = "subtle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "subtle" version = "2.0.0" @@ -1505,11 +2495,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "0.15.22" +version = "0.15.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (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.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1523,19 +2524,33 @@ name = "thread_local" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.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)", ] [[package]] name = "time" -version = "0.1.40" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tiny-bip39" +version = "0.6.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)", + "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" @@ -1544,26 +2559,38 @@ 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.25 (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.16 (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.13" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (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.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-fs 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-current-thread 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (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.3 (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.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.10 (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.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1571,101 +2598,125 @@ name = "tokio-codec" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (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.4" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (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.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-executor" -version = "0.1.5" +version = "0.1.6" 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.25 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-fs" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.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-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-io" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (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.25 (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.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.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)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (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.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-sync 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-sync" +version = "0.1.3" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-tcp" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (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.25 (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.16 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 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-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-threadpool" -version = "0.1.9" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-deque 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "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.25 (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.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-timer" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1673,30 +2724,30 @@ name = "tokio-udp" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (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.25 (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.16 (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.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 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-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-uds" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (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.25 (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.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (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.16 (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.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 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-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1704,26 +2755,35 @@ name = "toml" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "trie-db" -version = "0.11.0" +version = "0.12.2" dependencies = [ "elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.11.0", + "hash-db 0.12.2", "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.1 (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.11.0" +version = "0.12.2" +dependencies = [ + "hash-db 0.12.2", +] + +[[package]] +name = "twofish" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hash-db 0.11.0", + "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]] @@ -1731,7 +2791,7 @@ name = "twox-hash" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1739,12 +2799,17 @@ 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.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "crunchy 0.2.1 (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)", @@ -1760,7 +2825,15 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.7" +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.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1769,11 +2842,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "unreachable" -version = "1.0.0" +name = "unsigned-varint" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "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]] @@ -1791,6 +2865,11 @@ dependencies = [ "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 = "vcpkg" version = "0.2.6" @@ -1806,7 +2885,7 @@ name = "wasmi" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "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)", ] @@ -1845,16 +2924,16 @@ name = "ws" version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.11 (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)", "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)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.10.19 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1867,59 +2946,123 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "x25519-dalek" +version = "0.5.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.3 (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.1.9" +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.25 (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" + [metadata] +"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.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5" +"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.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f405cc4c21cd8b784f6c8fc2adf9bc00f59558f0049b5ec21517f875963040cc" -"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" -"checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0" +"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 autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" +"checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4" +"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" +"checksum base-x 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d55aa264e822dbafa12db4d54767aff17c6ba55ea2d8559b3e17392c7d000e5d" "checksum base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" +"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 (git+https://github.com/paritytech/bitmask)" = "" +"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.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" +"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" "checksum block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d75255892aeb580d3c566f213a2b6fdc1c66667839f45719ee1d30ebf2aea591" +"checksum bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0de79cfb98e7aa9988188784d8664b4b5dad6eaaa0863b91d9a4ed871d4f7a42" "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 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" -"checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" -"checksum cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "4390a3b5f4f6bce9c1d0c00128379df433e53777fdd30e92f16a529332baec4e" -"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" +"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 cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)" = "d01c69d08ff207f231f07196e30f84c70f1c815b04f980f8b7b01ff01f05eb92" +"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" "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 crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bd66663db5a988098a89599d4857919b3acf7f61402e61365acfd3919857b9be" -"checksum crossbeam-channel 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8d4f5844607ce8da3fff431e7dba56cda8bfcc570aa50bee36adba8a32b8cad7" -"checksum crossbeam-deque 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fe1b6f945f824c7a25afe44f62e25d714c0cc523f8e99d8db5cd1026e1269d3" -"checksum crossbeam-epoch 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2449aaa4ec7ef96e5fb24db16024b935df718e9ae1cec0a1e68feeca2efca7b8" -"checksum crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e07fc155212827475223f0bcfae57e945e694fc90950ddf3f6695bbfd5555c72" +"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.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c240f247c278fa08a6d4820a6a222bfc6e0d999e51ba67be94f44c905b2161f2" "checksum crypto-mac 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "779015233ac67d65098614aec748ac1c756ab6677fa2e14cf8b37c08dfed1198" -"checksum curve25519-dalek 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dae47cc3529cdab597dbc8b606e565707209b506e55848f3c15679214a56c956" +"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.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e1f8a6fc0376eb52dc18af94915cc04dfdf8353746c0e8c550ae683a0815e5c1" +"checksum data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f47ca1860a761136924ddd2422ba77b2ea54fe8cc75b9040804a0d9d32ad97" "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 discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" +"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.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c67353c641dc847124ea1902d69bd753dee9bb3beff9aa3662ecf86c971d1fac" "checksum elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "073be79b6538296faf81c631872676600616073817dd9a440c477ad09b408983" -"checksum environmental 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db746025e3ea695bfa0ae744dbacd5fcfc8db51b9760cf8bd0ab69708bb93c49" +"checksum environmental 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c7464757b80de8930c91c9afe77ddce501826bf9d134a87db2c67d9dc177e2c" "checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" "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.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a557e80084b05c32b455963ff565a9de6f2866da023d6671705c6aff6f65e01c" "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 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.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" +"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "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 hash256-std-hasher 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5c13dbac3cc50684760f54af18545c9e80fb75e93a3e586d71ebdc13138f6a4" +"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 hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4da5f0e01bd8a71a224a4eedecaacfcabda388dbb7a80faf04d3514287572d95" +"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.3 (registry+https://github.com/rust-lang/crates.io-index)" = "27455ce8b4a6666c87220e4b59c9a83995476bdadc10197905e61dbe906e36fa" "checksum hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1d340b6514f232f6db1bd16db65302a5278a04fef9ce867cb932e7e5fa21130a" "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 httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" @@ -1931,41 +3074,66 @@ dependencies = [ "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 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" +"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.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" +"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1" +"checksum libp2p 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-core-derive 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-dns 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-floodsub 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-identify 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-kad 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-mdns 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-mplex 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-noise 0.3.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-ping 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-plaintext 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-ratelimit 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-secio 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-tcp 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-uds 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-yamux 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" "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 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_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" -"checksum merlin 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a9e97b439f6d38cbe2a4a4aa93f6770c5305f62761b78b1851406c09c87ee2a" +"checksum merlin 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "83c2dda19c01176e8e7148f7bdb88bbdf215a8db0641f89fc40e4b81736aeda5" "checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432" "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" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +"checksum multistream-select 0.3.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" "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 num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" -"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -"checksum once_cell 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d7ce3535d54560c937c1652ba4a0da66bfc63e0f8e07bed127483afb6e5ee925" +"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" +"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 openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ec7bd7ca4cce6dbdc77e7c1230682740d307d1218a87fb0349a571272be749f9" -"checksum openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)" = "1bb974e77de925ef426b6bc82fce15fd45bdcbeb5728bffcfc7cdeeb7ce1c2d6" +"checksum openssl 0.10.19 (registry+https://github.com/rust-lang/crates.io-index)" = "84321fb9004c3bce5611188a644d6171f895fa2889d155927d528782edb21c5d" +"checksum openssl-sys 0.9.42 (registry+https://github.com/rust-lang/crates.io-index)" = "cb534d752bf98cf363b473950659ac2546517f9c6be9723771614ab3f03bbc9e" +"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.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "88f69984317b736dceac3baa86600fc089856f69b44b07231f39b5648b02bcd4" -"checksum parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a58ba33211595f92cc2163ac583961d3dc767e656934146636b05256cc9acd7f" +"checksum parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "21c9c3a1623c71ed83964ff28cac6126e178920f7646d32c337eacb9152b2907" +"checksum parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "864e9f66b58c0b38f0d6b511b6576afa2b678ae801b64220553bced57ac12df9" +"checksum parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" "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_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 paste 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f50392d1265092fbee9273414cc40eb6d47d307bd66222c477bb8450c8504f9d" "checksum paste-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a3cd512fe3a55e8933b2dcad913e365639db86d512e4004c3084b86864d9467a" +"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 pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" "checksum primitive-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edb92f1ebfc177432c03287b15d48c202e6e2c95993a7af3ba039abb43b1492e" @@ -1973,73 +3141,107 @@ dependencies = [ "checksum proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c725b36c99df7af7bf9324e9c999b9e37d92c8f8caf106d82e1d7953218d2d8" "checksum proc-macro-hack 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3e90aa19cd73dedc2d0e1e8407473f073d735fef0ab521438de6da8ee449ab66" "checksum proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b753ad9ed99dd8efeaa7d2fb8453c8f6bc3e54b97966d35f1bc77ca6865254a" -"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09" -"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c" -"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" -"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" -"checksum rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae9d223d52ae411a33cf7e54ec6034ec165df296ccd23533d671a28252b6f66a" -"checksum rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "771b009e3a508cb67e8823dda454aaa5368c7bc1c16829fb77d3e980440dd34a" -"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372" -"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db" +"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" +"checksum protobuf 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24d5d73d2b88fddb8b8141f2730d950d88772c940ac4f8f3e93230b9a99d92df" +"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.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" +"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_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05" -"checksum rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effa3fcaa47e18db002bdde6060944b6d2f9cfd8db471c30e873448ad9187be3" -"checksum redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "679da7508e9a6390aeaf7fbd02a800fdc64b73fe2204dd2c8ae66d22d9d5ad5d" -"checksum ring 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)" = "148fc853f6d85f53f5f315d46701eaacc565cdfb3cb1959730c96e81e7e49999" -"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" +"checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832" +"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.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" +"checksum regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53ee8cfdddb2e0291adfb9f13d31d3bbe0a03c9a402c01b1e24188d86c35b24f" +"checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861" +"checksum ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)" = "426bc186e3e95cac1e4a4be125a4aca7e84c2d616ffc02244eef36e2a60a093c" +"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" "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 rw-stream-sink 0.1.1 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" -"checksum schnorrkel 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe554f318830b48e5da8ab1ccb1ffd02b79228364dac7766b7cd1ec461ca5116" +"checksum safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7bf422d23a88c16d5090d455f182bc99c60af4df6a345c63428acf5129e347" +"checksum schnorrkel 0.0.0 (git+https://github.com/w3f/schnorrkel)" = "" +"checksum schnorrkel 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a700659388785588c75b197cecda0f23c7112a9281ef703e8ffc651061ce014c" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" +"checksum secp256k1 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4070f3906e65249228094cf97b04a90799fba04468190bbbcfa812309cf86e32" "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.81 (registry+https://github.com/rust-lang/crates.io-index)" = "c91eb5b0190ae87b4e2e39cbba6e3bed3ac6186935fe265f0426156c4c49961b" -"checksum serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)" = "477b13b646f5b5b56fc95bedfc3b550d12141ce84f466f6c44b9a17589923885" -"checksum serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "c37ccd6be3ed1fdf419ee848f7c758eb31b054d7cd3ae3600e3bae0adf569811" +"checksum serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "92514fb95f900c9b5126e32d020f5c6d40564c27a5ea6d1d7d9f157a96623560" +"checksum serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6eabf4b5914e88e24eea240bb7c9f9a2cbc1bbbe8d961d381975ec3c6b806c" +"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" "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.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34a5e54083ce2b934bf059fdf38e7330a154177e029ab6c4e18638f2f624053a" -"checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" +"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-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e544d16c6b230d84c866662fe55e31aacfca6ae71e6fc49ae9a311cb379bfc2f" "checksum slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddc0d2aff1f8f325ef660d9a0eb6e6dcd20b30b3f581a5897f58bf42d061c37a" -"checksum slog-scope 4.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "053344c94c0e2b22da6305efddb698d7c485809427cf40555dc936085f67a9df" -"checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db" +"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 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 stdweb 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a3edad410e603184d656e2abded5fd4d3d6e93d5763d21130dbaf99795db74eb" +"checksum stdweb-derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e21ebd9179de08f2300a65454268a17ea3de204627458588c84319c4def3930" +"checksum stdweb-internal-macros 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1635afd059cbfac7d5b1274f0c44cec110c1e013c48e8bbc22e07e52696cf887" +"checksum stdweb-internal-runtime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a2a2f4a2eb556337b2d1a302630bbddf989ae383c70393e89b48152b9896cbda" +"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.0 (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.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "702662512f3ddeb74a64ce2fbbf3707ee1b6bb663d28bb054e0779bbc720d926" -"checksum syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)" = "ae8b29eb5210bc5cf63ed6149cbf9adfc82ac0be023d8735c176ee74a2db4da7" +"checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2" +"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" +"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum tiny-bip39 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a1415431cb2398d84da64173f8473c792808314427d4a6f2f3ea85ae67239fe3" "checksum tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e9175261fbdb60781fcd388a4d6cc7e14764a2b629a7ad94abb439aed223a44f" -"checksum tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "a7817d4c98cc5be21360b3b37d6036fe9b7aefa5b7a201b7b16ff33423822f7d" +"checksum tk-listen 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5462b0f968c0457efe38fcd2df7e487096b992419e4f5337b06775a614bbda4b" +"checksum tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fcaabb3cec70485d0df6e9454fe514393ad1c4070dee8915f11041e95630b230" "checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" -"checksum tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "331c8acc267855ec06eb0c94618dcbbfea45bed2d20b77252940095273fb58f6" -"checksum tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c117b6cf86bb730aab4834f10df96e4dd586eff2c3c27d3781348da49e255bde" -"checksum tokio-fs 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "60ae25f6b17d25116d2cba342083abe5255d3c2c79cb21ea11aa049c53bf7c75" -"checksum tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "7392fe0a70d5ce0c882c4778116c519bd5dbaa8a7c3ae3d04578b3afafdcda21" -"checksum tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "502b625acb4ee13cbb3b90b8ca80e0addd263ddacf6931666ef751e610b07fb5" -"checksum tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7ad235e9dadd126b2d47f6736f65aa1fdcd6420e66ca63f44177bc78df89f912" -"checksum tokio-threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "56c5556262383032878afad66943926a1d1f0967f17e94bd7764ceceb3b70e7f" -"checksum tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4f37f0111d76cc5da132fe9bc0590b9b9cfd079bc7e75ac3846278430a299ff8" +"checksum tokio-current-thread 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c756b04680eea21902a46fca4e9f410a2332c04995af590e07ff262e2193a9a3" +"checksum tokio-dns-unofficial 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82c65483db54eb91b4ef3a9389a3364558590faf30ce473141707c0e16fda975" +"checksum tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30c6dbf2d1ad1de300b393910e8a3aa272b724a400b6531da03eed99e329fbf0" +"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-sync 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1bf2b9dac2a0509b5cfd1df5aa25eafacb616a42a491a13604d6bbeab4486363" +"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" +"checksum tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "742e511f6ce2298aeb86fc9ea0d8df81c2388c6ebae3dc8a7316e8c9df0df801" +"checksum tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2910970404ba6fa78c5539126a9ae2045d62e3713041e447f695f41405a120c6" "checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92" -"checksum tokio-uds 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "99ce87382f6c1a24b513a72c048b2c8efe66cb5161c9061d00bee510f08dc168" +"checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" -"checksum trie-root 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3c6fef2705af3258ec46a7e22286090394a44216201a1cf7d04b78db825e543" +"checksum twofish 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d261e83e727c8e2dbb75dacac67c36e35db36a958ee504f2164fc052434e1" "checksum twox-hash 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "555cd4909480122bbbf21e34faac4cb08a171f324775670447ed116726c474af" "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.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e7780bb27fd8a22295e0d9d53ae3be253f715a0dccb1808527f478f1c2603708" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" +"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" +"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +"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 vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum wasmi 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21ef487a11df1ed468cf613c78798c26282da5c30e9d49f824872d4c77b47d1d" @@ -2050,3 +3252,6 @@ dependencies = [ "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum ws 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "329d3e6dd450a9c5c73024e1047f0be7e24121a68484eb0b5368977bee3cf8c3" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +"checksum x25519-dalek 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4aca1ba6bec2719576bd20dfe5b24d9359552e616d10bff257e50cd85f745d17" +"checksum yamux 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "302defd1bed8a9a6d43b82f0e5a50510dfdfbbd02c270c93ff9d6f3f5e2dea89" +"checksum zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8ddfeb6eee2fb3b262ef6e0898a52b7563bb8e0d5955a313b3cf2f808246ea14" diff --git a/core/test-runtime/wasm/Cargo.toml b/core/test-runtime/wasm/Cargo.toml index 6ca1dabd4fbfebe1d18da5afe67d8aebfca30e11..8657ad80aed8da532edad8c5bc830b99f275c4b9 100644 --- a/core/test-runtime/wasm/Cargo.toml +++ b/core/test-runtime/wasm/Cargo.toml @@ -27,5 +27,7 @@ members = [] [patch.crates-io] trie-db = { path = "../../../../parity-trie/trie-db" } +trie-root = { path = "../../../../parity-trie/trie-root" } hash-db = { path = "../../../../parity-trie/hash-db" } memory-db = { path = "../../../../parity-trie/memory-db" } +hash256-std-hasher = { path = "../../../../parity-trie/hash256-std-hasher" } diff --git a/core/test-runtime/wasm/src/lib.rs b/core/test-runtime/wasm/src/lib.rs index fd89232f1550cdced022bbdd0b4c642df658ab3b..6620f276d0397fbd44840aef3f1500b2877798cb 100644 --- a/core/test-runtime/wasm/src/lib.rs +++ b/core/test-runtime/wasm/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm b/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm index 8887f960f174e58c9a08db2db08bb520b94a6470..6ca2f7991718242b469e3d0308d122b04fc77bdc 100644 Binary files a/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm and b/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm differ diff --git a/core/transaction-pool/Cargo.toml b/core/transaction-pool/Cargo.toml index 1dd765bb0efa2353b3e5fe00d987e5f93889f288..1286b7bde4b093de55512f1fba4528ef44b8cf3c 100644 --- a/core/transaction-pool/Cargo.toml +++ b/core/transaction-pool/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" error-chain = "0.12" futures = "0.1" log = "0.4" -parity-codec = "3.0" +parity-codec = "3.2" parking_lot = "0.7.1" 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 5872a385991b10f88ef2e02a46764eb48fff55f7..58aeec885d849e52e8fc6d34803c3a4984d8d271 100644 --- a/core/transaction-pool/graph/Cargo.toml +++ b/core/transaction-pool/graph/Cargo.toml @@ -11,9 +11,11 @@ log = "0.4" parking_lot = "0.7.1" serde = "1.0" serde_derive = "1.0" +substrate-primitives = { path = "../../primitives" } sr-primitives = { path = "../../sr-primitives" } [dev-dependencies] assert_matches = "1.1" -parity-codec = "3.0" +env_logger = "0.6" +parity-codec = "3.2" test_runtime = { package = "substrate-test-runtime", path = "../../test-runtime" } diff --git a/core/transaction-pool/graph/src/base_pool.rs b/core/transaction-pool/graph/src/base_pool.rs index e2d21de2140377163ea508592abbe93a134d22c0..ad434e57d45a21cdc2cec8a10984f1c782eb8a27 100644 --- a/core/transaction-pool/graph/src/base_pool.rs +++ b/core/transaction-pool/graph/src/base_pool.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -19,13 +19,16 @@ //! For a more full-featured pool, have a look at the `pool` module. use std::{ + collections::HashSet, + fmt, hash, sync::Arc, }; -use serde::Serialize; use error_chain::bail; use log::{trace, debug, warn}; +use serde::Serialize; +use substrate_primitives::hexdisplay::HexDisplay; use sr_primitives::traits::Member; use sr_primitives::transaction_validity::{ TransactionTag as Tag, @@ -82,7 +85,7 @@ pub struct PruneStatus { /// Immutable transaction #[cfg_attr(test, derive(Clone))] -#[derive(Debug, PartialEq, Eq)] +#[derive(PartialEq, Eq)] pub struct Transaction { /// Raw extrinsic representing that transaction. pub data: Extrinsic, @@ -100,6 +103,41 @@ pub struct Transaction { pub provides: Vec, } +impl fmt::Debug for Transaction where + Hash: fmt::Debug, + Extrinsic: fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn print_tags(fmt: &mut fmt::Formatter, tags: &[Tag]) -> fmt::Result { + let mut it = tags.iter(); + if let Some(t) = it.next() { + write!(fmt, "{}", HexDisplay::from(t))?; + } + for t in it { + write!(fmt, ",{}", HexDisplay::from(t))?; + } + Ok(()) + } + + write!(fmt, "Transaction {{ ")?; + write!(fmt, "hash: {:?}, ", &self.hash)?; + write!(fmt, "priority: {:?}, ", &self.priority)?; + write!(fmt, "valid_till: {:?}, ", &self.valid_till)?; + write!(fmt, "bytes: {:?}, ", &self.bytes)?; + write!(fmt, "requires: [")?; + print_tags(fmt, &self.requires)?; + write!(fmt, "], provides: [")?; + print_tags(fmt, &self.provides)?; + write!(fmt, "], ")?; + write!(fmt, "data: {:?}", &self.data)?; + write!(fmt, "}}")?; + Ok(()) + } +} + +/// Store last pruned tags for given number of invocations. +const RECENTLY_PRUNED_TAGS: usize = 2; + /// Transaction pool. /// /// Builds a dependency graph for all transactions in the pool and returns @@ -114,6 +152,12 @@ pub struct Transaction { pub struct BasePool { future: FutureTransactions, ready: ReadyTransactions, + /// Store recently pruned tags (for last two invocations). + /// + /// This is used to make sure we don't accidentally put + /// transactions to future in case they were just stuck in verification. + recently_pruned: [HashSet; RECENTLY_PRUNED_TAGS], + recently_pruned_index: usize, } impl Default for BasePool { @@ -121,6 +165,8 @@ impl Default for BasePool { BasePool { future: Default::default(), ready: Default::default(), + recently_pruned: Default::default(), + recently_pruned_index: 0, } } } @@ -141,7 +187,11 @@ impl BasePool BasePool) -> PruneStatus { let mut to_import = vec![]; let mut pruned = vec![]; + let recently_pruned = &mut self.recently_pruned[self.recently_pruned_index]; + self.recently_pruned_index = (self.recently_pruned_index + 1) % RECENTLY_PRUNED_TAGS; + recently_pruned.clear(); for tag in tags { // make sure to promote any future transactions that could be unlocked to_import.append(&mut self.future.satisfy_tags(::std::iter::once(&tag))); // and actually prune transactions in ready queue - pruned.append(&mut self.ready.prune_tags(tag)); + pruned.append(&mut self.ready.prune_tags(tag.clone())); + // store the tags for next submission + recently_pruned.insert(tag); } let mut promoted = vec![]; @@ -360,6 +415,7 @@ impl BasePool { /// Transaction details. pub transaction: Arc>, @@ -38,6 +39,23 @@ pub struct WaitingTransaction { pub imported_at: time::Instant, } +impl fmt::Debug for WaitingTransaction { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "WaitingTransaction {{ ")?; + write!(fmt, "imported_at: {:?}, ", self.imported_at)?; + write!(fmt, "transaction: {:?}, ", self.transaction)?; + write!(fmt, "missing_tags: {{")?; + let mut it = self.missing_tags.iter().map(|tag| HexDisplay::from(tag)); + if let Some(tag) = it.next() { + write!(fmt, "{}", tag)?; + } + for tag in it { + write!(fmt, ", {}", tag)?; + } + write!(fmt, " }}}}") + } +} + impl Clone for WaitingTransaction { fn clone(&self) -> Self { WaitingTransaction { @@ -53,10 +71,19 @@ impl WaitingTransaction { /// /// Computes the set of missing tags based on the requirements and tags that /// are provided by all transactions in the ready queue. - pub fn new(transaction: Transaction, provided: &HashMap) -> Self { + pub fn new( + transaction: Transaction, + provided: &HashMap, + recently_pruned: &[HashSet], + ) -> Self { let missing_tags = transaction.requires .iter() - .filter(|tag| !provided.contains_key(&**tag)) + .filter(|tag| { + // is true if the tag is already satisfied either via transaction in the pool + // or one that was recently included. + let is_provided = provided.contains_key(&**tag) || recently_pruned.iter().any(|x| x.contains(&**tag)); + !is_provided + }) .cloned() .collect(); diff --git a/core/transaction-pool/graph/src/lib.rs b/core/transaction-pool/graph/src/lib.rs index d30032830c7ad85be4b55c80cded3180baab2dca..ea890a5cd0f2182d3d85c95250bf37c6914957eb 100644 --- a/core/transaction-pool/graph/src/lib.rs +++ b/core/transaction-pool/graph/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/transaction-pool/graph/src/listener.rs b/core/transaction-pool/graph/src/listener.rs index e2dfaef915f5f66c070ec57cb846e9d41c02f38d..ac59b4c57e102c01b5344a6ef8aba3a0c5161162 100644 --- a/core/transaction-pool/graph/src/listener.rs +++ b/core/transaction-pool/graph/src/listener.rs @@ -1,5 +1,5 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/transaction-pool/graph/src/pool.rs b/core/transaction-pool/graph/src/pool.rs index f705385f94aebc48c220f005c728f30f6e02d38d..9c3478d3d7831003a9e79e3c1334fc6d8b94f3da 100644 --- a/core/transaction-pool/graph/src/pool.rs +++ b/core/transaction-pool/graph/src/pool.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -176,6 +176,8 @@ impl Pool { let ready_limit = &self.options.ready; let future_limit = &self.options.future; + debug!(target: "txpool", "Pool Status: {:?}", status); + if ready_limit.is_exceeded(status.ready, status.ready_bytes) || future_limit.is_exceeded(status.future, status.future_bytes) { // clean up the pool @@ -453,12 +455,14 @@ mod tests { use super::*; use futures::Stream; use parity_codec::Encode; - use test_runtime::{Block, Extrinsic, Transfer, H256}; + use test_runtime::{Block, Extrinsic, Transfer, H256, AccountId}; use assert_matches::assert_matches; use crate::watcher; #[derive(Debug, Default)] - struct TestApi; + struct TestApi { + delay: Mutex>>, + } impl ChainApi for TestApi { type Block = Block; @@ -467,9 +471,20 @@ mod tests { /// Verify extrinsic at given block. fn validate_transaction(&self, at: &BlockId, uxt: ExtrinsicFor) -> Result { + let block_number = self.block_id_to_number(at)?.unwrap(); let nonce = uxt.transfer().nonce; + // This is used to control the test flow. + if nonce > 0 { + let opt = self.delay.lock().take(); + if let Some(delay) = opt { + if delay.recv().is_err() { + println!("Error waiting for delay!"); + } + } + } + if nonce < block_number { Ok(TransactionValidity::Invalid(0)) } else { @@ -493,7 +508,7 @@ mod tests { /// Returns a block hash given the block id. fn block_id_to_hash(&self, at: &BlockId) -> Result>, Self::Error> { Ok(match at { - BlockId::Number(num) => Some(H256::from_low_u64_be(*num)), + BlockId::Number(num) => Some(H256::from_low_u64_be(*num)).into(), BlockId::Hash(_) => None, }) } @@ -502,7 +517,7 @@ mod tests { fn hash_and_length(&self, uxt: &ExtrinsicFor) -> (Self::Hash, usize) { let len = uxt.encode().len(); ( - (uxt.transfer().from.to_low_u64_be() << 5) + uxt.transfer().nonce, + (H256::from(uxt.transfer().from.clone()).to_low_u64_be() << 5) + uxt.transfer().nonce, len ) } @@ -524,8 +539,8 @@ mod tests { // when let hash = pool.submit_one(&BlockId::Number(0), uxt(Transfer { - from: H256::from_low_u64_be(1), - to: H256::from_low_u64_be(2), + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), amount: 5, nonce: 0, })).unwrap(); @@ -539,8 +554,8 @@ mod tests { // given let pool = pool(); let uxt = uxt(Transfer { - from: H256::from_low_u64_be(1), - to: H256::from_low_u64_be(2), + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), amount: 5, nonce: 0, }); @@ -564,21 +579,21 @@ mod tests { // when let _hash = pool.submit_one(&BlockId::Number(0), uxt(Transfer { - from: H256::from_low_u64_be(1), - to: H256::from_low_u64_be(2), + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), amount: 5, nonce: 0, })).unwrap(); let _hash = pool.submit_one(&BlockId::Number(0), uxt(Transfer { - from: H256::from_low_u64_be(1), - to: H256::from_low_u64_be(2), + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), amount: 5, nonce: 1, })).unwrap(); // future doesn't count let _hash = pool.submit_one(&BlockId::Number(0), uxt(Transfer { - from: H256::from_low_u64_be(1), - to: H256::from_low_u64_be(2), + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), amount: 5, nonce: 3, })).unwrap(); @@ -600,20 +615,20 @@ mod tests { // given let pool = pool(); let hash1 = pool.submit_one(&BlockId::Number(0), uxt(Transfer { - from: H256::from_low_u64_be(1), - to: H256::from_low_u64_be(2), + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), amount: 5, nonce: 0, })).unwrap(); let hash2 = pool.submit_one(&BlockId::Number(0), uxt(Transfer { - from: H256::from_low_u64_be(1), - to: H256::from_low_u64_be(2), + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), amount: 5, nonce: 1, })).unwrap(); let hash3 = pool.submit_one(&BlockId::Number(0), uxt(Transfer { - from: H256::from_low_u64_be(1), - to: H256::from_low_u64_be(2), + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), amount: 5, nonce: 3, })).unwrap(); @@ -636,8 +651,8 @@ mod tests { // given let pool = pool(); let hash1 = pool.submit_one(&BlockId::Number(0), uxt(Transfer { - from: H256::from_low_u64_be(1), - to: H256::from_low_u64_be(2), + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), amount: 5, nonce: 0, })).unwrap(); @@ -662,8 +677,8 @@ mod tests { }, TestApi::default()); let hash1 = pool.submit_one(&BlockId::Number(0), uxt(Transfer { - from: H256::from_low_u64_be(1), - to: H256::from_low_u64_be(2), + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), amount: 5, nonce: 1, })).unwrap(); @@ -671,8 +686,8 @@ mod tests { // when let hash2 = pool.submit_one(&BlockId::Number(0), uxt(Transfer { - from: H256::from_low_u64_be(2), - to: H256::from_low_u64_be(2), + from: AccountId::from_h256(H256::from_low_u64_be(2)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), amount: 5, nonce: 10, })).unwrap(); @@ -697,8 +712,8 @@ mod tests { // when pool.submit_one(&BlockId::Number(0), uxt(Transfer { - from: H256::from_low_u64_be(1), - to: H256::from_low_u64_be(2), + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), amount: 5, nonce: 1, })).unwrap_err(); @@ -717,8 +732,8 @@ mod tests { // given let pool = pool(); let watcher = pool.submit_and_watch(&BlockId::Number(0), uxt(Transfer { - from: H256::from_low_u64_be(1), - to: H256::from_low_u64_be(2), + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), amount: 5, nonce: 0, })).unwrap(); @@ -733,7 +748,7 @@ mod tests { // then let mut stream = watcher.into_stream().wait(); assert_eq!(stream.next(), Some(Ok(watcher::Status::Ready))); - assert_eq!(stream.next(), Some(Ok(watcher::Status::Finalised(H256::from_low_u64_be(2))))); + assert_eq!(stream.next(), Some(Ok(watcher::Status::Finalised(H256::from_low_u64_be(2).into())))); assert_eq!(stream.next(), None); } @@ -742,8 +757,8 @@ mod tests { // given let pool = pool(); let watcher = pool.submit_and_watch(&BlockId::Number(0), uxt(Transfer { - from: H256::from_low_u64_be(1), - to: H256::from_low_u64_be(2), + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), amount: 5, nonce: 0, })).unwrap(); @@ -758,7 +773,7 @@ mod tests { // then let mut stream = watcher.into_stream().wait(); assert_eq!(stream.next(), Some(Ok(watcher::Status::Ready))); - assert_eq!(stream.next(), Some(Ok(watcher::Status::Finalised(H256::from_low_u64_be(2))))); + assert_eq!(stream.next(), Some(Ok(watcher::Status::Finalised(H256::from_low_u64_be(2).into())))); assert_eq!(stream.next(), None); } @@ -767,8 +782,8 @@ mod tests { // given let pool = pool(); let watcher = pool.submit_and_watch(&BlockId::Number(0), uxt(Transfer { - from: H256::from_low_u64_be(1), - to: H256::from_low_u64_be(2), + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), amount: 5, nonce: 1, })).unwrap(); @@ -777,8 +792,8 @@ mod tests { // when pool.submit_one(&BlockId::Number(0), uxt(Transfer { - from: H256::from_low_u64_be(1), - to: H256::from_low_u64_be(2), + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), amount: 5, nonce: 0, })).unwrap(); @@ -795,8 +810,8 @@ mod tests { // given let pool = pool(); let uxt = uxt(Transfer { - from: H256::from_low_u64_be(1), - to: H256::from_low_u64_be(2), + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), amount: 5, nonce: 0, }); @@ -819,8 +834,8 @@ mod tests { // given let pool = pool(); let uxt = uxt(Transfer { - from: H256::from_low_u64_be(1), - to: H256::from_low_u64_be(2), + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), amount: 5, nonce: 0, }); @@ -853,8 +868,8 @@ mod tests { }, TestApi::default()); let xt = uxt(Transfer { - from: H256::from_low_u64_be(1), - to: H256::from_low_u64_be(2), + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), amount: 5, nonce: 0, }); @@ -863,8 +878,8 @@ mod tests { // when let xt = uxt(Transfer { - from: H256::from_low_u64_be(2), - to: H256::from_low_u64_be(1), + from: AccountId::from_h256(H256::from_low_u64_be(2)), + to: AccountId::from_h256(H256::from_low_u64_be(1)), amount: 4, nonce: 1, }); @@ -876,5 +891,59 @@ mod tests { assert_eq!(stream.next(), Some(Ok(watcher::Status::Ready))); assert_eq!(stream.next(), Some(Ok(watcher::Status::Dropped))); } + + #[test] + fn should_handle_pruning_in_the_middle_of_import() { + let _ = env_logger::try_init(); + // given + let (ready, is_ready) = std::sync::mpsc::sync_channel(0); + let (tx, rx) = std::sync::mpsc::sync_channel(1); + let mut api = TestApi::default(); + api.delay = Mutex::new(rx.into()); + let pool = Arc::new(Pool::new(Default::default(), api)); + + // when + let xt = uxt(Transfer { + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: 1, + }); + + // This transaction should go to future, since we use `nonce: 1` + let pool2 = pool.clone(); + std::thread::spawn(move || { + pool2.submit_one(&BlockId::Number(0), xt).unwrap(); + ready.send(()).unwrap(); + }); + + // But now before the previous one is imported we import + // the one that it depends on. + let xt = uxt(Transfer { + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 4, + nonce: 0, + }); + // The tag the above transaction provides (TestApi is using just nonce as u8) + let provides = vec![0_u8]; + pool.submit_one(&BlockId::Number(0), xt).unwrap(); + assert_eq!(pool.status().ready, 1); + + // Now block import happens before the second transaction is able to finish verification. + pool.prune_tags(&BlockId::Number(1), vec![provides], vec![]).unwrap(); + assert_eq!(pool.status().ready, 0); + + + // so when we release the verification of the previous one it will have + // something in `requires`, but should go to ready directly, since the previous transaction was imported + // correctly. + tx.send(()).unwrap(); + + // then + is_ready.recv().unwrap(); // wait for finish + assert_eq!(pool.status().ready, 1); + assert_eq!(pool.status().future, 0); + } } } diff --git a/core/transaction-pool/graph/src/ready.rs b/core/transaction-pool/graph/src/ready.rs index faca722d12c37ef590cda283ad0c17a652dd3df4..befb1b60ccc2deb18e18eee7a4a08b977f87045d 100644 --- a/core/transaction-pool/graph/src/ready.rs +++ b/core/transaction-pool/graph/src/ready.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -517,18 +517,18 @@ mod tests { tx3.provides = vec![vec![4]]; // when - let x = WaitingTransaction::new(tx2, &ready.provided_tags()); + let x = WaitingTransaction::new(tx2, &ready.provided_tags(), &[]); ready.import(x).unwrap(); - let x = WaitingTransaction::new(tx3, &ready.provided_tags()); + let x = WaitingTransaction::new(tx3, &ready.provided_tags(), &[]); ready.import(x).unwrap(); assert_eq!(ready.get().count(), 2); // too low priority - let x = WaitingTransaction::new(tx1.clone(), &ready.provided_tags()); + let x = WaitingTransaction::new(tx1.clone(), &ready.provided_tags(), &[]); ready.import(x).unwrap_err(); tx1.priority = 10; - let x = WaitingTransaction::new(tx1.clone(), &ready.provided_tags()); + let x = WaitingTransaction::new(tx1.clone(), &ready.provided_tags(), &[]); ready.import(x).unwrap(); // then @@ -562,15 +562,15 @@ mod tests { }; // when - let x = WaitingTransaction::new(tx1, &ready.provided_tags()); + let x = WaitingTransaction::new(tx1, &ready.provided_tags(), &[]); ready.import(x).unwrap(); - let x = WaitingTransaction::new(tx2, &ready.provided_tags()); + let x = WaitingTransaction::new(tx2, &ready.provided_tags(), &[]); ready.import(x).unwrap(); - let x = WaitingTransaction::new(tx3, &ready.provided_tags()); + let x = WaitingTransaction::new(tx3, &ready.provided_tags(), &[]); ready.import(x).unwrap(); - let x = WaitingTransaction::new(tx4, &ready.provided_tags()); + let x = WaitingTransaction::new(tx4, &ready.provided_tags(), &[]); ready.import(x).unwrap(); - let x = WaitingTransaction::new(tx5, &ready.provided_tags()); + let x = WaitingTransaction::new(tx5, &ready.provided_tags(), &[]); ready.import(x).unwrap(); // then diff --git a/core/transaction-pool/graph/src/rotator.rs b/core/transaction-pool/graph/src/rotator.rs index eed7e628932bc1620556ab338da2f39fa0a6e297..2ca51ef74e880007285ec8b0f279019fb2b5fa3f 100644 --- a/core/transaction-pool/graph/src/rotator.rs +++ b/core/transaction-pool/graph/src/rotator.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/transaction-pool/graph/src/watcher.rs b/core/transaction-pool/graph/src/watcher.rs index bb73a4b0e914f9e89fa184780255141fa63b154f..419a98ca79230085f4dd2f5125224478c1661dba 100644 --- a/core/transaction-pool/graph/src/watcher.rs +++ b/core/transaction-pool/graph/src/watcher.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/transaction-pool/src/api.rs b/core/transaction-pool/src/api.rs index dd8cb95c7ddd641bf34da1eb80f13175b6f9abfe..84475376fe6377ff6c71afd2499bb941bd453865 100644 --- a/core/transaction-pool/src/api.rs +++ b/core/transaction-pool/src/api.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/transaction-pool/src/error.rs b/core/transaction-pool/src/error.rs index 9f191b8545e2f6125401c5e210c504573755bd0b..e1223c537de3731446840f1176489f2ebfec0d2e 100644 --- a/core/transaction-pool/src/error.rs +++ b/core/transaction-pool/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/transaction-pool/src/lib.rs b/core/transaction-pool/src/lib.rs index ee9d8d8cbb17d985b98b9da34f6f995f1e2da9e1..1899c601b2fdbbc8b73aac524c5bd030026615e5 100644 --- a/core/transaction-pool/src/lib.rs +++ b/core/transaction-pool/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/core/transaction-pool/src/tests.rs b/core/transaction-pool/src/tests.rs index 770f00fa6491614dae339452972175dd2c42ee28..cab44f49cc79c4b812c513a2cc197b0a5e00d01d 100644 --- a/core/transaction-pool/src/tests.rs +++ b/core/transaction-pool/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -17,10 +17,9 @@ use super::*; -use keyring::Keyring::{self, *}; use parity_codec::Encode; use txpool::{self, Pool}; -use test_client::runtime::{AccountId, Block, Hash, Index, Extrinsic, Transfer}; +use test_client::{runtime::{AccountId, Block, Hash, Index, Extrinsic, Transfer}, AccountKeyring::{self, *}}; use sr_primitives::{ generic::{self, BlockId}, traits::{Hash as HashT, BlakeTwo256}, @@ -86,9 +85,9 @@ fn number_of(at: &BlockId) -> u64 { } } -fn uxt(who: Keyring, nonce: Index) -> Extrinsic { +fn uxt(who: AccountKeyring, nonce: Index) -> Extrinsic { let transfer = Transfer { - from: who.to_raw_public().into(), + from: who.into(), to: AccountId::default(), nonce, amount: 1, diff --git a/core/trie/Cargo.toml b/core/trie/Cargo.toml index daa2af7a9701fbc7d4b34b3fe521fd0146261a81..0140eaacf5ede5fd82768a03823bbfc668c316aa 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.0", default-features = false } +codec = { package = "parity-codec", version = "3.2", default-features = false } rstd = { package = "sr-std", path = "../sr-std", default-features = false } -hash-db = { version = "0.11", default-features = false } -trie-db = { version = "0.11", default-features = false } -trie-root = { version = "0.11", default-features = false } -memory-db = { version = "0.11", default-features = false } +hash-db = { version = "0.12", default-features = false } +trie-db = { version = "0.12", default-features = false } +trie-root = { version = "0.12", default-features = false } +memory-db = { version = "0.12", default-features = false } [dev-dependencies] substrate-primitives = { path = "../primitives" } -trie-bench = { version = "0.11" } -trie-standardmap = { version = "0.11" } -keccak-hasher = { version = "0.11" } +trie-bench = { version = "0.12" } +trie-standardmap = { version = "0.12" } +keccak-hasher = { version = "0.12" } criterion = "0.2" hex-literal = "0.1.0" diff --git a/core/trie/benches/bench.rs b/core/trie/benches/bench.rs index f4100bff15fc6f855a3bc4a16c60f8450b681d52..179dc6aaf8413c0c85e88f3c95ecda7d3e089d5b 100644 --- a/core/trie/benches/bench.rs +++ b/core/trie/benches/bench.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// Copyright 2015-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Parity is free software: you can redistribute it and/or modify diff --git a/core/trie/src/lib.rs b/core/trie/src/lib.rs index 89cb136914575dc87d6e89f6792d4a845a5f0693..f40ae814914f25e25f17a46628632486563b97c5 100644 --- a/core/trie/src/lib.rs +++ b/core/trie/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// Copyright 2015-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Parity is free software: you can redistribute it and/or modify @@ -35,6 +35,8 @@ pub use trie_stream::TrieStream; pub use node_codec::NodeCodec; /// Various re-exports from the `trie-db` crate. pub use trie_db::{Trie, TrieMut, DBValue, Recorder, Query}; +/// Various re-exports from the `memory-db` crate. +pub use memory_db::{KeyFunction, prefixed_key}; /// As in `trie_db`, but less generic, error type for the crate. pub type TrieError = trie_db::TrieError; @@ -45,8 +47,12 @@ impl> AsHashDB for T {} pub type HashDB<'a, H> = hash_db::HashDB + 'a; /// As in `hash_db`, but less generic, trait exposed. pub type PlainDB<'a, K> = hash_db::PlainDB + 'a; +/// As in `memory_db::MemoryDB` that uses prefixed storage key scheme. +pub type PrefixedMemoryDB = memory_db::MemoryDB, trie_db::DBValue>; +/// As in `memory_db::MemoryDB` that uses prefixed storage key scheme. +pub type MemoryDB = memory_db::MemoryDB, trie_db::DBValue>; /// As in `memory_db`, but less generic, trait exposed. -pub type MemoryDB = memory_db::MemoryDB; +pub type GenericMemoryDB = memory_db::MemoryDB; /// Persistent trie database read-access interface for the a given hasher. pub type TrieDB<'a, H> = trie_db::TrieDB<'a, H, NodeCodec>; @@ -316,7 +322,6 @@ mod tests { use super::*; use codec::{Encode, Compact}; use substrate_primitives::Blake2Hasher; - use memory_db::MemoryDB; use hash_db::{HashDB, Hasher}; use trie_db::{DBValue, TrieMut, Trie}; use trie_standardmap::{Alphabet, ValueMode, StandardMap}; diff --git a/core/trie/src/node_codec.rs b/core/trie/src/node_codec.rs index 4a82b7a5e12e67bf8b1ad70a11131f833ca24123..775ee9a4026c8901e497cbe0f7685bd65781c7fe 100644 --- a/core/trie/src/node_codec.rs +++ b/core/trie/src/node_codec.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// Copyright 2015-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Parity is free software: you can redistribute it and/or modify diff --git a/core/trie/src/node_header.rs b/core/trie/src/node_header.rs index 99b1241cab4524c41c634a9e0d7d08d67a3a451e..4f7617c0684bb881d970c177d940559d0760d9a9 100644 --- a/core/trie/src/node_header.rs +++ b/core/trie/src/node_header.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// Copyright 2015-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Parity is free software: you can redistribute it and/or modify @@ -72,7 +72,6 @@ impl Decode for NodeHeader { BRANCH_NODE_NO_VALUE => NodeHeader::Branch(false), // 254 BRANCH_NODE_WITH_VALUE => NodeHeader::Branch(true), // 255 - _ => unreachable!(), }) } } diff --git a/core/trie/src/trie_stream.rs b/core/trie/src/trie_stream.rs index c1c9c520f4d85051a1e272e9d12de39019296a4b..81a1a301ebc32f7bc4652da9a41a033923abea50 100644 --- a/core/trie/src/trie_stream.rs +++ b/core/trie/src/trie_stream.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// Copyright 2015-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Parity is free software: you can redistribute it and/or modify diff --git a/core/util/fork-tree/Cargo.toml b/core/util/fork-tree/Cargo.toml index 8be64bedab735ab47c6925be1d973df563b4f86c..4098fb80fad283d1eeab59f4b87ea8a8d704f63b 100644 --- a/core/util/fork-tree/Cargo.toml +++ b/core/util/fork-tree/Cargo.toml @@ -5,5 +5,4 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -parity-codec = "3.0" -parity-codec-derive = "3.0" +parity-codec = { version = "3.2", features = ["derive"] } diff --git a/core/util/fork-tree/src/lib.rs b/core/util/fork-tree/src/lib.rs index 2fac80db799553b86e1109f9015843559ebee80e..f194ac8915159b104be7e469bf5e27dcf9dbbdea 100644 --- a/core/util/fork-tree/src/lib.rs +++ b/core/util/fork-tree/src/lib.rs @@ -20,7 +20,7 @@ #![warn(missing_docs)] use std::fmt; -use parity_codec_derive::{Decode, Encode}; +use parity_codec::{Decode, Encode}; /// Error occured when interating with the tree. #[derive(Clone, Debug, PartialEq)] @@ -79,7 +79,7 @@ pub enum FinalizationResult { /// in order. Each node is uniquely identified by its hash but can be ordered by /// its number. In order to build the tree an external function must be provided /// when interacting with the tree to establish a node's ancestry. -#[derive(Clone, Debug, Decode, Encode)] +#[derive(Clone, Debug, Decode, Encode, PartialEq)] pub struct ForkTree { roots: Vec>, best_finalized_number: Option, @@ -228,17 +228,19 @@ impl ForkTree where /// Checks if any node in the tree is finalized by either finalizing the /// node itself or a child node that's not in the tree, guaranteeing that /// the node being finalized isn't a descendent of any of the node's - /// children. The given `predicate` is checked on the prospective finalized - /// root and must pass for finalization to occur. The given function - /// `is_descendent_of` should return `true` if the second hash (target) is a - /// descendent of the first hash (base). + /// children. Returns `Some(true)` if the node being finalized is a root, + /// `Some(false)` if the node being finalized is not a root, and `None` if + /// no node in the tree is finalized. The given `predicate` is checked on + /// the prospective finalized root and must pass for finalization to occur. + /// The given function `is_descendent_of` should return `true` if the second + /// hash (target) is a descendent of the first hash (base). pub fn finalizes_any_with_descendent_if( &self, hash: &H, number: N, is_descendent_of: &F, predicate: P, - ) -> Result> + ) -> Result, Error> where E: std::error::Error, F: Fn(&H, &H) -> Result, P: Fn(&V) -> bool, @@ -253,20 +255,20 @@ impl ForkTree where // tree, if we find a valid node that passes the predicate then we must // ensure that we're not finalizing past any of its child nodes. for node in self.node_iter() { - if node.hash == *hash || is_descendent_of(&node.hash, hash)? { - if predicate(&node.data) { + if predicate(&node.data) { + if node.hash == *hash || is_descendent_of(&node.hash, hash)? { for node in node.children.iter() { if node.number <= number && is_descendent_of(&node.hash, &hash)? { return Err(Error::UnfinalizedAncestor); } } - return Ok(true); + return Ok(Some(self.roots.iter().any(|root| root.hash == node.hash))); } } } - Ok(false) + Ok(None) } /// Finalize a root in the tree by either finalizing the node itself or a @@ -298,8 +300,8 @@ impl ForkTree where // we're not finalizing past any children node. let mut position = None; for (i, root) in self.roots.iter().enumerate() { - if root.hash == *hash || is_descendent_of(&root.hash, hash)? { - if predicate(&root.data) { + if predicate(&root.data) { + if root.hash == *hash || is_descendent_of(&root.hash, hash)? { for node in root.children.iter() { if node.number <= number && is_descendent_of(&node.hash, &hash)? { return Err(Error::UnfinalizedAncestor); @@ -349,58 +351,65 @@ impl ForkTree where } } -#[derive(Clone, Debug, Decode, Encode)] -#[cfg_attr(test, derive(PartialEq))] -struct Node { - hash: H, - number: N, - data: V, - children: Vec>, -} +// Workaround for: https://github.com/rust-lang/rust/issues/34537 +mod node_implementation { + use super::*; -impl Node { - fn import( - &mut self, - mut hash: H, - mut number: N, - mut data: V, - is_descendent_of: &F, - ) -> Result, Error> - where E: fmt::Debug, - F: Fn(&H, &H) -> Result, - { - if self.hash == hash { - return Err(Error::Duplicate); - }; + #[derive(Clone, Debug, Decode, Encode, PartialEq)] + pub struct Node { + pub hash: H, + pub number: N, + pub data: V, + pub children: Vec>, + } - if number <= self.number { return Ok(Some((hash, number, data))); } + impl Node { + pub fn import( + &mut self, + mut hash: H, + mut number: N, + mut data: V, + is_descendent_of: &F, + ) -> Result, Error> + where E: fmt::Debug, + F: Fn(&H, &H) -> Result, + { + if self.hash == hash { + return Err(Error::Duplicate); + }; - for node in self.children.iter_mut() { - match node.import(hash, number, data, is_descendent_of)? { - Some((h, n, d)) => { - hash = h; - number = n; - data = d; - }, - None => return Ok(None), - } - } + if number <= self.number { return Ok(Some((hash, number, data))); } - if is_descendent_of(&self.hash, &hash)? { - self.children.push(Node { - data, - hash: hash, - number: number, - children: Vec::new(), - }); + for node in self.children.iter_mut() { + match node.import(hash, number, data, is_descendent_of)? { + Some((h, n, d)) => { + hash = h; + number = n; + data = d; + }, + None => return Ok(None), + } + } - Ok(None) - } else { - Ok(Some((hash, number, data))) + if is_descendent_of(&self.hash, &hash)? { + self.children.push(Node { + data, + hash: hash, + number: number, + children: Vec::new(), + }); + + Ok(None) + } else { + Ok(Some((hash, number, data))) + } } } } +// Workaround for: https://github.com/rust-lang/rust/issues/34537 +use node_implementation::Node; + struct ForkTreeIterator<'a, H, N, V> { stack: Vec<&'a Node>, } @@ -685,7 +694,19 @@ mod test { &is_descendent_of, |c| c.effective <= 2, ), - Ok(false), + Ok(None), + ); + + // finalizing "D" will finalize a block from the tree, but it can't be applied yet + // since it is not a root change + assert_eq!( + tree.finalizes_any_with_descendent_if( + &"D", + 10, + &is_descendent_of, + |c| c.effective == 10, + ), + Ok(Some(false)), ); // finalizing "B" doesn't finalize "A0" since the predicate doesn't pass, @@ -713,7 +734,7 @@ mod test { &is_descendent_of, |c| c.effective <= 5, ), - Ok(true), + Ok(Some(true)), ); assert_eq!( @@ -750,7 +771,7 @@ mod test { &is_descendent_of, |c| c.effective <= 100, ), - Ok(true), + Ok(Some(true)), ); assert_eq!( @@ -781,4 +802,76 @@ mod test { ], ); } + + #[test] + fn minimizes_calls_to_is_descendent_of() { + use std::sync::atomic::{AtomicUsize, Ordering}; + + let n_is_descendent_of_calls = AtomicUsize::new(0); + + let is_descendent_of = |_: &&str, _: &&str| -> Result { + n_is_descendent_of_calls.fetch_add(1, Ordering::SeqCst); + Ok(true) + }; + + { + // Deep tree where we want to call `finalizes_any_with_descendent_if`. The + // search for the node should first check the predicate (which is cheaper) and + // only then call `is_descendent_of` + let mut tree = ForkTree::new(); + let letters = vec!["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K"]; + + for (i, letter) in letters.iter().enumerate() { + tree.import::<_, TestError>(*letter, i, i, &|_, _| Ok(true)).unwrap(); + } + + // "L" is a descendent of "K", but the predicate will only pass for "K", + // therefore only one call to `is_descendent_of` should be made + assert_eq!( + tree.finalizes_any_with_descendent_if( + &"L", + 11, + &is_descendent_of, + |i| *i == 10, + ), + Ok(Some(false)), + ); + + assert_eq!( + n_is_descendent_of_calls.load(Ordering::SeqCst), + 1, + ); + } + + n_is_descendent_of_calls.store(0, Ordering::SeqCst); + + { + // Multiple roots in the tree where we want to call `finalize_with_descendent_if`. + // The search for the root node should first check the predicate (which is cheaper) + // and only then call `is_descendent_of` + let mut tree = ForkTree::new(); + let letters = vec!["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K"]; + + for (i, letter) in letters.iter().enumerate() { + tree.import::<_, TestError>(*letter, i, i, &|_, _| Ok(false)).unwrap(); + } + + // "L" is a descendent of "K", but the predicate will only pass for "K", + // therefore only one call to `is_descendent_of` should be made + assert_eq!( + tree.finalize_with_descendent_if( + &"L", + 11, + &is_descendent_of, + |i| *i == 10, + ), + Ok(FinalizationResult::Changed(Some(10))), + ); + + assert_eq!( + n_is_descendent_of_calls.load(Ordering::SeqCst), + 1, + ); + } + } } diff --git a/license_header.txt b/license_header.txt index c357cc10ed409fad4f845affd912fe93a0b983f6..15b778660733f3b2b5415f3044df5e7a0d9e04d7 100644 --- a/license_header.txt +++ b/license_header.txt @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/node-template/Cargo.toml b/node-template/Cargo.toml index bb5396a884a00e7a9290894dff79e38bf4111955..cd8f5157c4821638a32c0dd2a8198f1f1f5cbc92 100644 --- a/node-template/Cargo.toml +++ b/node-template/Cargo.toml @@ -18,9 +18,8 @@ tokio = "0.1" exit-future = "0.1" parking_lot = "0.7.1" hex-literal = "0.1" -slog = "^2" -parity-codec = "3.0" -trie-root = "0.11.0" +parity-codec = "3.2" +trie-root = "0.12" sr-io = { path = "../core/sr-io" } substrate-cli = { path = "../core/cli" } primitives = { package = "substrate-primitives", path = "../core/primitives" } @@ -33,7 +32,6 @@ consensus = { package = "substrate-consensus-aura", path = "../core/consensus/au substrate-client = { path = "../core/client" } basic-authorship = { package = "substrate-basic-authorship", path = "../core/basic-authorship" } node-template-runtime = { path = "runtime" } -node-executor = { path = "../node/executor" } [build-dependencies] vergen = "3" diff --git a/node-template/build.rs b/node-template/build.rs index d30f13c0c9d793b545974a2dfd9851ab693272b1..afc39d3b63c5eab92b362d436f3f2b4786088ed0 100644 --- a/node-template/build.rs +++ b/node-template/build.rs @@ -1,6 +1,6 @@ use vergen::{ConstantsFlags, generate_cargo_keys}; -const ERROR_MSG: &'static str = "Failed to generate metadata files"; +const ERROR_MSG: &str = "Failed to generate metadata files"; fn main() { generate_cargo_keys(ConstantsFlags::all()).expect(ERROR_MSG); diff --git a/node-template/runtime/Cargo.toml b/node-template/runtime/Cargo.toml index 99cb977b44e66e2973cf4f1054f8ea5b36fa0d7c..2ba64a3a9cdb96c6186c6d6a8f42a1676c94cf48 100644 --- a/node-template/runtime/Cargo.toml +++ b/node-template/runtime/Cargo.toml @@ -5,18 +5,16 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false } -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", 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 } support = { package = "srml-support", path = "../../srml/support", default_features = false } primitives = { package = "substrate-primitives", path = "../../core/primitives", default_features = false } balances = { package = "srml-balances", path = "../../srml/balances", default_features = false } -fees = { package = "srml-fees", path = "../../srml/fees", default_features = false } consensus = { package = "srml-consensus", path = "../../srml/consensus", default_features = false } aura = { package = "srml-aura", path = "../../srml/aura", default_features = false } executive = { package = "srml-executive", path = "../../srml/executive", default_features = false } @@ -27,19 +25,18 @@ sudo = { package = "srml-sudo", path = "../../srml/sudo", default_features = fal runtime-primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default_features = false } client = { package = "substrate-client", path = "../../core/client", default_features = false } 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 } [features] default = ["std"] std = [ "parity-codec/std", - "parity-codec-derive/std", "primitives/std", "client/std", "rstd/std", "runtime-io/std", "support/std", "balances/std", - "fees/std", "executive/std", "aura/std", "indices/std", @@ -49,7 +46,8 @@ std = [ "sudo/std", "version/std", "serde_derive", - "serde/std", + "serde", "safe-mix/std", "consensus-aura/std", + "offchain-primitives/std", ] diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index 7c6804670727469ecb1b814ba476bbdc8cf92625..a82f8ce5859589036438f5b240b3137de71ae846 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -7,14 +7,14 @@ #[cfg(feature = "std")] use serde_derive::{Serialize, Deserialize}; -use parity_codec_derive::{Encode, Decode}; +use parity_codec::{Encode, Decode}; use rstd::prelude::*; #[cfg(feature = "std")] use primitives::bytes; -use primitives::{Ed25519AuthorityId, OpaqueMetadata}; +use primitives::{ed25519, sr25519, OpaqueMetadata}; use runtime_primitives::{ - ApplyResult, transaction_validity::TransactionValidity, Ed25519Signature, generic, - traits::{self, BlakeTwo256, Block as BlockT, StaticLookup}, create_runtime_str + ApplyResult, transaction_validity::TransactionValidity, generic, create_runtime_str, + traits::{self, NumberFor, BlakeTwo256, Block as BlockT, StaticLookup, Verify} }; use client::{ block_builder::api::{CheckInherentsResult, InherentData, self as block_builder_api}, @@ -34,8 +34,17 @@ pub use runtime_primitives::{Permill, Perbill}; pub use timestamp::BlockPeriod; pub use support::{StorageValue, construct_runtime}; -/// Alias to Ed25519 pubkey that identifies an account on the chain. -pub type AccountId = primitives::H256; +/// The type that is used for identifying authorities. +pub type AuthorityId = ::Signer; + +/// The type used by authorities to prove their ID. +pub type AuthoritySignature = ed25519::Signature; + +/// Alias to pubkey that identifies an account on the chain. +pub type AccountId = ::Signer; + +/// The type used by authorities to prove their ID. +pub type AccountSignature = sr25519::Signature; /// A hash of some data used by the chain. pub type Hash = primitives::H256; @@ -58,21 +67,27 @@ pub mod opaque { /// Opaque, encoded, unchecked extrinsic. #[derive(PartialEq, Eq, Clone, Default, Encode, Decode)] - #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] + #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct UncheckedExtrinsic(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec); + #[cfg(feature = "std")] + impl std::fmt::Debug for UncheckedExtrinsic { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(fmt, "{}", primitives::hexdisplay::HexDisplay::from(&self.0)) + } + } impl traits::Extrinsic for UncheckedExtrinsic { fn is_signed(&self) -> Option { None } } /// Opaque block header type. - pub type Header = generic::Header>; + pub type Header = generic::Header>; /// Opaque block type. pub type Block = generic::Block; /// Opaque block identifier type. pub type BlockId = generic::BlockId; /// Opaque session key type. - pub type SessionKey = Ed25519AuthorityId; + pub type SessionKey = AuthorityId; } /// This runtime version. @@ -125,7 +140,7 @@ impl aura::Trait for Runtime { impl consensus::Trait for Runtime { /// The identifier we use to refer to authorities. - type SessionKey = Ed25519AuthorityId; + type SessionKey = AuthorityId; // The aura module handles offline-reports internally // rather than using an explicit report system. type InherentOfflineReport = (); @@ -158,15 +173,12 @@ impl balances::Trait for Runtime { type OnFreeBalanceZero = (); /// What to do if a new account is created. type OnNewAccount = Indices; - /// Restrict whether an account can transfer funds. We don't place any further restrictions. - type EnsureAccountLiquid = (); /// The uniquitous event type. type Event = Event; -} -impl fees::Trait for Runtime { - type TransferAsset = Balances; - type Event = Event; + type TransactionPayment = (); + type DustRemoval = (); + type TransferPayment = (); } impl sudo::Trait for Runtime { @@ -176,12 +188,12 @@ impl sudo::Trait for Runtime { } /// Used for the module template in `./template.rs` -impl template::Trait for Runtime { +impl template::Trait for Runtime { type Event = Event; } construct_runtime!( - pub enum Runtime with Log(InternalLog: DigestItem) where + pub enum Runtime with Log(InternalLog: DigestItem) where Block = Block, NodeBlock = opaque::Block, UncheckedExtrinsic = UncheckedExtrinsic @@ -193,7 +205,6 @@ construct_runtime!( Indices: indices, Balances: balances, Sudo: sudo, - Fees: fees::{Module, Storage, Config, Event}, // Used for the module template in `./template.rs` TemplateModule: template::{Module, Call, Storage, Event}, } @@ -210,11 +221,11 @@ pub type Block = generic::Block; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; /// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = generic::UncheckedMortalCompactExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedMortalCompactExtrinsic; /// Extrinsic type that has already been checked. pub type CheckedExtrinsic = generic::CheckedExtrinsic; /// Executive: handles dispatch to the various modules. -pub type Executive = executive::Executive; +pub type Executive = executive::Executive; // Implement our runtime API endpoints. This is just a bunch of proxying. impl_runtime_apis! { @@ -223,7 +234,7 @@ impl_runtime_apis! { VERSION } - fn authorities() -> Vec { + fn authorities() -> Vec { Consensus::authorities() } @@ -275,4 +286,10 @@ impl_runtime_apis! { Aura::slot_duration() } } + + impl offchain_primitives::OffchainWorkerApi for Runtime { + fn offchain_worker(n: NumberFor) { + Executive::offchain_worker(n) + } + } } diff --git a/node-template/runtime/src/template.rs b/node-template/runtime/src/template.rs index 300b48af114c7b47f028c419dc23743b5086ad2b..fd122433daea3460d170b1d5c1cc068d024be7e1 100644 --- a/node-template/runtime/src/template.rs +++ b/node-template/runtime/src/template.rs @@ -6,7 +6,7 @@ /// For more guidance on Substrate modules, see the example module -/// https://github.com/paritytech/substrate/blob/gav-template/srml/example/src/lib.rs +/// https://github.com/paritytech/substrate/blob/master/srml/example/src/lib.rs use support::{decl_module, decl_storage, decl_event, StorageValue, dispatch::Result}; use system::ensure_signed; @@ -55,7 +55,6 @@ decl_module! { } decl_event!( - /// An event in this module. pub enum Event where AccountId = ::AccountId { // Just a dummy event. // Event `Something` is declared with a parameter of the type `u32` and `AccountId` @@ -95,7 +94,7 @@ mod tests { type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; diff --git a/node-template/runtime/wasm/Cargo.lock b/node-template/runtime/wasm/Cargo.lock index d06bef8fed8063ed78d8d1cf52187966260b4345..bef63babbcc7821b8ae6df83b976042755b326e5 100644 --- a/node-template/runtime/wasm/Cargo.lock +++ b/node-template/runtime/wasm/Cargo.lock @@ -1,5 +1,57 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[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.6.10" +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.25 (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.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-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "arrayref" version = "0.3.5" @@ -13,6 +65,23 @@ 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.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "autocfg" version = "0.1.2" @@ -20,13 +89,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.2 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -36,20 +105,50 @@ name = "backtrace-sys" version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "base-x" +version = "0.2.4" +source = "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 = "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 = "git+https://github.com/paritytech/bitmask#a84e147be602631617badd18b6b9af83391db4a9" + +[[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" @@ -79,6 +178,14 @@ dependencies = [ "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.3" @@ -87,6 +194,11 @@ 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 = "byte-tools" version = "0.2.0" @@ -97,6 +209,11 @@ 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" @@ -104,7 +221,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bytes" -version = "0.4.11" +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)", @@ -113,12 +230,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.28" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -136,7 +253,7 @@ name = "clear_on_drop" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -157,25 +274,32 @@ name = "crossbeam" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (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.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.9.0 (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.6" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "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]] @@ -183,29 +307,69 @@ name = "crossbeam-deque" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-epoch 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 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)", +] + +[[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.7.0" +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.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (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.7 (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.6.3" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (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.7 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -227,18 +391,50 @@ dependencies = [ "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.0.3" +version = "1.1.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)", "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 0.6.4 (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.0.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 = "digest" version = "0.6.2" @@ -255,21 +451,40 @@ dependencies = [ "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "discard" +version = "1.0.4" +source = "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.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek 1.1.3 (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.4 (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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "elastic-array" -version = "0.10.0" +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)", @@ -277,7 +492,7 @@ dependencies = [ [[package]] name = "environmental" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -285,13 +500,28 @@ name = "error-chain" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.14 (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.14 (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.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "fake-simd" @@ -305,8 +535,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)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (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)", ] @@ -329,6 +559,11 @@ name = "foreign-types-shared" version = "0.1.1" 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" @@ -348,6 +583,15 @@ name = "futures" version = "0.1.25" 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.25 (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 = "generic-array" version = "0.8.3" @@ -367,17 +611,30 @@ dependencies = [ [[package]] name = "hash-db" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.12.2" [[package]] name = "hash256-std-hasher" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crunchy 0.2.1 (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" @@ -386,9 +643,22 @@ dependencies = [ "winapi 0.3.6 (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.2.1 (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.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -413,6 +683,15 @@ dependencies = [ "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" @@ -443,7 +722,7 @@ name = "impl-codec" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -452,7 +731,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.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -465,7 +744,7 @@ name = "iovec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -493,13 +772,13 @@ name = "kvdb" version = "0.1.0" source = "git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d#b0317f649ab2c665b7987b8475878fc4d2e1f81d" dependencies = [ - "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -509,9 +788,328 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.48" +version = "0.2.50" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "libp2p" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (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.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-core-derive 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-dns 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-floodsub 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-identify 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-kad 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-mdns 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-mplex 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-noise 0.3.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-ping 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-plaintext 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-ratelimit 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-secio 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-tcp 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-uds 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-yamux 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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)", + "stdweb 0.4.15 (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.6 (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-core" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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.25 (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)", + "multistream-select 0.3.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.4.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.1 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "secp256k1 0.12.0 (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.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-timer 0.2.10 (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)", + "zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libp2p-core-derive" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libp2p-dns" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "protobuf 2.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)", + "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.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.4.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)", + "tokio-timer 0.2.10 (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)", +] + +[[package]] +name = "libp2p-kad" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-identify 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-ping 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.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)", + "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)", + "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)", +] + +[[package]] +name = "libp2p-mdns" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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-timer 0.2.10 (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)", +] + +[[package]] +name = "libp2p-mplex" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.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-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.3.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "curve25519-dalek 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (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.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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)", + "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.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-ping" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parking_lot 0.7.1 (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)", + "tokio-timer 0.2.10 (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-plaintext" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libp2p-ratelimit" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "aio-limited 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 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)", +] + +[[package]] +name = "libp2p-secio" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "hmac 0.7.0 (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.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.4.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.1 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "stdweb 0.4.15 (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)", +] + +[[package]] +name = "libp2p-tcp" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libp2p-yamux" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "libsecp256k1" version = "0.2.2" @@ -520,7 +1118,7 @@ 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.5 (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)", ] @@ -539,7 +1137,7 @@ name = "log" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -547,6 +1145,11 @@ 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" @@ -554,10 +1157,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memory-db" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.12.2" dependencies = [ - "hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", + "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)", ] @@ -568,13 +1171,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "merlin" -version = "1.0.2" +version = "1.0.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)", "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 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -588,7 +1190,7 @@ dependencies = [ "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)", "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (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)", @@ -613,7 +1215,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.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -628,13 +1230,27 @@ dependencies = [ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "multistream-select" +version = "0.3.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -642,11 +1258,10 @@ dependencies = [ name = "node-template-runtime" version = "0.9.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.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.85 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", @@ -655,7 +1270,6 @@ dependencies = [ "srml-balances 0.1.0", "srml-consensus 0.1.0", "srml-executive 0.1.0", - "srml-fees 0.1.0", "srml-indices 0.1.0", "srml-sudo 0.1.0", "srml-support 0.1.0", @@ -663,6 +1277,7 @@ dependencies = [ "srml-timestamp 0.1.0", "substrate-client 0.1.0", "substrate-consensus-aura-primitives 0.1.0", + "substrate-offchain-primitives 0.1.0", "substrate-primitives 0.1.0", ] @@ -678,6 +1293,11 @@ 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 = "num-integer" version = "0.1.39" @@ -693,16 +1313,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "once_cell" -version = "0.1.7" +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" @@ -711,28 +1334,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl" -version = "0.10.16" +version = "0.10.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (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.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.40 (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.50 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "openssl-sys" -version = "0.9.40" +version = "0.9.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.6 (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" @@ -748,21 +1380,50 @@ source = "git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7 [[package]] name = "parity-codec" -version = "3.0.0" +version = "3.2.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)", - "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "parity-codec-derive" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-crate 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parity-multiaddr" +version = "0.2.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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)", + "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "serde 1.0.89 (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-multihash" +version = "0.1.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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)", + "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.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]] @@ -773,6 +1434,24 @@ 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" @@ -782,15 +1461,38 @@ dependencies = [ "parking_lot_core 0.4.0 (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.50 (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.6 (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.50 (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.6 (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.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (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.8 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -809,9 +1511,19 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-hack 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (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]] @@ -856,9 +1568,9 @@ name = "proc-macro-hack" version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -868,75 +1580,92 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "0.4.26" +version = "0.4.27" 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.4.0" +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.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.4.5" +version = "0.3.23" 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)", - "libc 0.2.48 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (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.5.5" +version = "0.4.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-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.2.2 (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.50 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.6.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "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.50 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (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_os 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.1.1 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rand_chacha" -version = "0.1.1" +name = "rand" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (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.3 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rand_core" -version = "0.2.2" +name = "rand_chacha" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -969,26 +1698,36 @@ dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_jitter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.50 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_os" -version = "0.1.1" +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-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (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.50 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_pcg" -version = "0.1.1" +version = "0.1.2" 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)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -999,6 +1738,27 @@ 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.1 (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.50 (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" @@ -1012,16 +1772,37 @@ name = "redox_syscall" version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "regex" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.10 (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.5 (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.5" +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.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.31 (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.50 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1042,6 +1823,16 @@ dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rw-stream-sink" +version = "0.1.1" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (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.7" @@ -1058,15 +1849,33 @@ dependencies = [ [[package]] name = "schnorrkel" version = "0.0.0" +source = "git+https://github.com/w3f/schnorrkel#0a0de4294b475ef6abdeebb50067f213ca79b3c7" +dependencies = [ + "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek 1.1.3 (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.0.3 (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.1 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "schnorrkel" +version = "0.1.0" 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.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek 1.1.3 (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.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "merlin 1.0.3 (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.1 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1076,6 +1885,16 @@ name = "scopeguard" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "secp256k1" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "semver" version = "0.9.0" @@ -1091,27 +1910,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.85" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.85" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.37" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1180,8 +1999,8 @@ 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)", - "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (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)", ] @@ -1191,16 +2010,30 @@ 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.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)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "smallvec" -version = "0.6.8" +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 = [ - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1214,19 +2047,19 @@ version = "0.1.0" dependencies = [ "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-crate 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "sr-io" version = "0.1.0" dependencies = [ - "environmental 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "environmental 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (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 0.1.0", "substrate-primitives 0.1.0", @@ -1242,10 +2075,9 @@ 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.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-std 0.1.0", "substrate-primitives 0.1.0", @@ -1263,10 +2095,9 @@ name = "sr-version" version = "0.1.0" dependencies = [ "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", ] @@ -1275,12 +2106,13 @@ dependencies = [ name = "srml-aura" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", + "srml-session 0.1.0", "srml-staking 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", @@ -1292,11 +2124,10 @@ dependencies = [ name = "srml-balances" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.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.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", "srml-support 0.1.0", @@ -1308,11 +2139,10 @@ dependencies = [ name = "srml-consensus" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", "srml-support 0.1.0", @@ -1325,40 +2155,24 @@ dependencies = [ name = "srml-executive" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 0.1.0", - "sr-primitives 0.1.0", - "sr-std 0.1.0", - "srml-support 0.1.0", - "srml-system 0.1.0", -] - -[[package]] -name = "srml-fees" -version = "0.1.0" -dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", - "substrate-primitives 0.1.0", ] [[package]] name = "srml-indices" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.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.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", @@ -1372,10 +2186,9 @@ dependencies = [ name = "srml-metadata" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 0.1.0", "substrate-primitives 0.1.0", ] @@ -1384,11 +2197,11 @@ dependencies = [ name = "srml-session" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.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.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", "srml-consensus 0.1.0", @@ -1401,11 +2214,11 @@ dependencies = [ name = "srml-staking" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.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.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", "srml-consensus 0.1.0", @@ -1419,10 +2232,10 @@ dependencies = [ name = "srml-sudo" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", "srml-support 0.1.0", @@ -1434,13 +2247,13 @@ dependencies = [ name = "srml-support" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitmask 0.5.0 (git+https://github.com/paritytech/bitmask)", + "hex-literal 0.1.3 (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.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "paste 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", @@ -1453,11 +2266,11 @@ dependencies = [ name = "srml-support-procedural" version = "0.1.0" dependencies = [ - "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "sr-api-macros 0.1.0", "srml-support-procedural-tools 0.1.0", - "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1465,31 +2278,30 @@ name = "srml-support-procedural-tools" version = "0.1.0" dependencies = [ "proc-macro-crate 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "srml-support-procedural-tools-derive 0.1.0", - "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "srml-support-procedural-tools-derive" version = "0.1.0" dependencies = [ - "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "srml-system" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.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.85 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", @@ -1501,13 +2313,11 @@ dependencies = [ name = "srml-timestamp" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", - "srml-consensus 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", "substrate-inherents 0.1.0", @@ -1523,6 +2333,90 @@ 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 = "stdweb" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "stdweb-derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "stdweb-internal-macros 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "stdweb-internal-runtime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base-x 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.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.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "substrate-bip39" +version = "0.2.0" +source = "git+https://github.com/paritytech/substrate-bip39#a28806512c977992af8d6740d45352f5a1c832a0" +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.0.0 (git+https://github.com/w3f/schnorrkel)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "substrate-client" version = "0.1.0" @@ -1530,13 +2424,12 @@ dependencies = [ "error-chain 0.12.0 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-api-macros 0.1.0", "sr-primitives 0.1.0", @@ -1548,7 +2441,7 @@ dependencies = [ "substrate-keyring 0.1.0", "substrate-primitives 0.1.0", "substrate-state-machine 0.1.0", - "substrate-telemetry 0.3.0", + "substrate-telemetry 0.3.1", "substrate-trie 0.4.0", ] @@ -1563,17 +2456,18 @@ dependencies = [ name = "substrate-consensus-common" version = "0.1.0" dependencies = [ - "crossbeam-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-version 0.1.0", "substrate-inherents 0.1.0", "substrate-primitives 0.1.0", - "tokio 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1582,13 +2476,13 @@ version = "0.1.0" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-version 0.1.0", "substrate-panic-handler 0.1.0", @@ -1604,8 +2498,7 @@ dependencies = [ name = "substrate-inherents" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", @@ -1615,16 +2508,26 @@ dependencies = [ name = "substrate-keyring" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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 0.1.0", ] +[[package]] +name = "substrate-offchain-primitives" +version = "0.1.0" +dependencies = [ + "sr-primitives 0.1.0", + "substrate-client 0.1.0", +] + [[package]] name = "substrate-panic-handler" version = "0.1.0" dependencies = [ - "backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1635,21 +2538,24 @@ 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)", - "hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hash256-std-hasher 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", + "hash256-std-hasher 0.12.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.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "primitive-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.14.5 (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.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.14.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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "schnorrkel 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 0.1.0", + "substrate-bip39 0.2.0 (git+https://github.com/paritytech/substrate-bip39)", + "tiny-bip39 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "twox-hash 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmi 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1659,34 +2565,37 @@ dependencies = [ name = "substrate-serializer" version = "0.1.0" dependencies = [ - "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (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 = "0.1.0" dependencies = [ - "hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 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)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-panic-handler 0.1.0", "substrate-primitives 0.1.0", "substrate-trie 0.4.0", - "trie-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-root 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-db 0.12.2", + "trie-root 0.12.2", ] [[package]] name = "substrate-telemetry" -version = "0.3.0" +version = "0.3.1" dependencies = [ - "lazy_static 1.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)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (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.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1698,13 +2607,19 @@ dependencies = [ name = "substrate-trie" version = "0.4.0" dependencies = [ - "hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memory-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-root 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", + "memory-db 0.12.2", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-std 0.1.0", + "trie-db 0.12.2", + "trie-root 0.12.2", ] +[[package]] +name = "subtle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "subtle" version = "2.0.0" @@ -1712,11 +2627,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "0.15.26" +version = "0.15.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (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.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1730,7 +2656,7 @@ name = "thread_local" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.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)", ] [[package]] @@ -1738,11 +2664,25 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tiny-bip39" +version = "0.6.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)", + "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" @@ -1751,24 +2691,36 @@ 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.25 (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.16 (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.14" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.9.0 (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.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-current-thread 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-fs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 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.3 (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.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 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)", "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)", ] @@ -1778,64 +2730,85 @@ name = "tokio-codec" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (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.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.6 (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.25 (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.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tokio-executor" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.3 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-fs" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.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-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-io" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (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.25 (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.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.3 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.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)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.9.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)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (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.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-sync" +version = "0.1.3" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1843,35 +2816,36 @@ name = "tokio-tcp" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (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.25 (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.16 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 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)", ] [[package]] name = "tokio-threadpool" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "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.25 (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.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.4 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-timer" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.3 (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.25 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1882,13 +2856,13 @@ name = "tokio-udp" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (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.25 (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.16 (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.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 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)", ] [[package]] @@ -1896,16 +2870,16 @@ name = "tokio-uds" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (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.25 (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.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (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.16 (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.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 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)", ] [[package]] @@ -1913,26 +2887,35 @@ name = "toml" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "trie-db" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.12.2" dependencies = [ - "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", + "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.4 (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.11.0" +version = "0.12.2" +dependencies = [ + "hash-db 0.12.2", +] + +[[package]] +name = "twofish" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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]] @@ -1940,7 +2923,7 @@ name = "twox-hash" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1948,6 +2931,11 @@ 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.6.1" @@ -1972,20 +2960,26 @@ name = "unicode-normalization" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "unicode-segmentation" +version = "1.2.1" +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 = "unreachable" -version = "1.0.0" +name = "unsigned-varint" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "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]] @@ -2003,6 +2997,11 @@ dependencies = [ "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 = "vcpkg" version = "0.2.6" @@ -2058,13 +3057,13 @@ version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.11 (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)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.10.19 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2079,60 +3078,132 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "x25519-dalek" +version = "0.5.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.3 (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.1.9" +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.25 (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" + +[[patch.unused]] +name = "hash256-std-hasher" +version = "0.12.2" + +[[patch.unused]] +name = "trie-bench" +version = "0.12.2" + [metadata] +"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.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5" +"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 autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" -"checksum backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "b5b493b66e03090ebc4343eb02f94ff944e0cbc9ac6571491d170ba026741eb5" +"checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4" "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" +"checksum base-x 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d55aa264e822dbafa12db4d54767aff17c6ba55ea2d8559b3e17392c7d000e5d" "checksum base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" +"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 (git+https://github.com/paritytech/bitmask)" = "" +"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.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" +"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" "checksum block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d75255892aeb580d3c566f213a2b6fdc1c66667839f45719ee1d30ebf2aea591" +"checksum bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0de79cfb98e7aa9988188784d8664b4b5dad6eaaa0863b91d9a4ed871d4f7a42" "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.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" -"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" -"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" +"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" +"checksum cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ce8bb087aacff865633f0bd5aeaed910fe2fe55b55f4739527f2e023a2e53d" +"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" "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 crossbeam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad4c7ea749d9fb09e23c5cb17e3b70650860553a0e2744e38446b1803bf7db94" -"checksum crossbeam-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "137bc235f622ffaa0428e3854e24acb53291fc0b3ff6fb2cb75a8be6fb02f06b" +"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-epoch 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f10a4f8f409aaac4b16a5474fb233624238fcdeefb9ba50d5ea059aab63ba31c" -"checksum crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "41ee4864f4797060e52044376f7d107429ce1fb43460021b126424b7180ee21a" +"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.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c240f247c278fa08a6d4820a6a222bfc6e0d999e51ba67be94f44c905b2161f2" "checksum crypto-mac 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "779015233ac67d65098614aec748ac1c756ab6677fa2e14cf8b37c08dfed1198" -"checksum curve25519-dalek 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dae47cc3529cdab597dbc8b606e565707209b506e55848f3c15679214a56c956" +"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.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e1f8a6fc0376eb52dc18af94915cc04dfdf8353746c0e8c550ae683a0815e5c1" +"checksum data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f47ca1860a761136924ddd2422ba77b2ea54fe8cc75b9040804a0d9d32ad97" "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 discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" +"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 elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "88d4851b005ef16de812ea9acdb7bece2f0a40dd86c07b85631d7dafa54537bb" -"checksum environmental 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db746025e3ea695bfa0ae744dbacd5fcfc8db51b9760cf8bd0ab69708bb93c49" +"checksum either 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c67353c641dc847124ea1902d69bd753dee9bb3beff9aa3662ecf86c971d1fac" +"checksum elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "073be79b6538296faf81c631872676600616073817dd9a440c477ad09b408983" +"checksum environmental 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c7464757b80de8930c91c9afe77ddce501826bf9d134a87db2c67d9dc177e2c" "checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" "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.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a557e80084b05c32b455963ff565a9de6f2866da023d6671705c6aff6f65e01c" "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 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.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" +"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "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 hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b03501f6e1a2a97f1618879aba3156f14ca2847faa530c4e28859638bd11483" -"checksum hash256-std-hasher 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5c13dbac3cc50684760f54af18545c9e80fb75e93a3e586d71ebdc13138f6a4" +"checksum hash256-std-hasher 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1224388a21c88a80ae7087a2a245ca6d80acc97a9186b75789fb3eeefd0609af" +"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 hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4da5f0e01bd8a71a224a4eedecaacfcabda388dbb7a80faf04d3514287572d95" +"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.3 (registry+https://github.com/rust-lang/crates.io-index)" = "27455ce8b4a6666c87220e4b59c9a83995476bdadc10197905e61dbe906e36fa" "checksum hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1d340b6514f232f6db1bd16db65302a5278a04fef9ce867cb932e7e5fa21130a" "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 httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" @@ -2144,39 +3215,66 @@ dependencies = [ "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.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" +"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.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" +"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1" +"checksum libp2p 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-core-derive 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-dns 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-floodsub 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-identify 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-kad 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-mdns 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-mplex 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-noise 0.3.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-ping 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-plaintext 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-ratelimit 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-secio 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-tcp 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-uds 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-yamux 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" "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 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.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94da53143d45f6bad3753f532e56ad57a6a26c0ca6881794583310c7cb4c885f" "checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" -"checksum merlin 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a9e97b439f6d38cbe2a4a4aa93f6770c5305f62761b78b1851406c09c87ee2a" +"checksum merlin 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "83c2dda19c01176e8e7148f7bdb88bbdf215a8db0641f89fc40e4b81736aeda5" "checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432" "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" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +"checksum multistream-select 0.3.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" "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 num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" -"checksum num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a69d464bdc213aaaff628444e99578ede64e9c854025aa43b9796530afa9238" -"checksum once_cell 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "53075ac5dbd2798cfbcf9f710f2737de031d8076c192d8fe66fb23f639ccbdf4" +"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" +"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 openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ec7bd7ca4cce6dbdc77e7c1230682740d307d1218a87fb0349a571272be749f9" -"checksum openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)" = "1bb974e77de925ef426b6bc82fce15fd45bdcbeb5728bffcfc7cdeeb7ce1c2d6" +"checksum openssl 0.10.19 (registry+https://github.com/rust-lang/crates.io-index)" = "84321fb9004c3bce5611188a644d6171f895fa2889d155927d528782edb21c5d" +"checksum openssl-sys 0.9.42 (registry+https://github.com/rust-lang/crates.io-index)" = "cb534d752bf98cf363b473950659ac2546517f9c6be9723771614ab3f03bbc9e" +"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.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "88f69984317b736dceac3baa86600fc089856f69b44b07231f39b5648b02bcd4" -"checksum parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a58ba33211595f92cc2163ac583961d3dc767e656934146636b05256cc9acd7f" +"checksum parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "21c9c3a1623c71ed83964ff28cac6126e178920f7646d32c337eacb9152b2907" +"checksum parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "864e9f66b58c0b38f0d6b511b6576afa2b678ae801b64220553bced57ac12df9" +"checksum parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" "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_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 paste 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f50392d1265092fbee9273414cc40eb6d47d307bd66222c477bb8450c8504f9d" "checksum paste-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a3cd512fe3a55e8933b2dcad913e365639db86d512e4004c3084b86864d9467a" +"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 pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" "checksum primitive-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edb92f1ebfc177432c03287b15d48c202e6e2c95993a7af3ba039abb43b1492e" @@ -2184,35 +3282,46 @@ dependencies = [ "checksum proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c725b36c99df7af7bf9324e9c999b9e37d92c8f8caf106d82e1d7953218d2d8" "checksum proc-macro-hack 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3e90aa19cd73dedc2d0e1e8407473f073d735fef0ab521438de6da8ee449ab66" "checksum proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b753ad9ed99dd8efeaa7d2fb8453c8f6bc3e54b97966d35f1bc77ca6865254a" -"checksum proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)" = "38fddd23d98b2144d197c0eca5705632d4fe2667d14a6be5df8934f8d74f1978" +"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" +"checksum protobuf 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24d5d73d2b88fddb8b8141f2730d950d88772c940ac4f8f3e93230b9a99d92df" +"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.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" -"checksum rand 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "dee497e66d8d76bf08ce20c8d36e16f93749ab0bf89975b4f8ae5cee660c2da2" -"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" -"checksum rand 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3906503e80ac6cbcacb2c2973fa8e473f24d7e2747c8c92bb230c2441cad96b5" +"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.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372" "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_os 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f46fbd5550acf75b0c2730f5dd1873751daf9beb8f11b44027778fae50d7feca" -"checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05" +"checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832" +"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.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" -"checksum ring 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)" = "148fc853f6d85f53f5f315d46701eaacc565cdfb3cb1959730c96e81e7e49999" +"checksum regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53ee8cfdddb2e0291adfb9f13d31d3bbe0a03c9a402c01b1e24188d86c35b24f" +"checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861" +"checksum ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)" = "426bc186e3e95cac1e4a4be125a4aca7e84c2d616ffc02244eef36e2a60a093c" "checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" "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 rw-stream-sink 0.1.1 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" "checksum safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7bf422d23a88c16d5090d455f182bc99c60af4df6a345c63428acf5129e347" -"checksum schnorrkel 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe554f318830b48e5da8ab1ccb1ffd02b79228364dac7766b7cd1ec461ca5116" +"checksum schnorrkel 0.0.0 (git+https://github.com/w3f/schnorrkel)" = "" +"checksum schnorrkel 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a700659388785588c75b197cecda0f23c7112a9281ef703e8ffc651061ce014c" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" +"checksum secp256k1 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4070f3906e65249228094cf97b04a90799fba04468190bbbcfa812309cf86e32" "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.85 (registry+https://github.com/rust-lang/crates.io-index)" = "534b8b91a95e0f71bca3ed5824752d558da048d4248c91af873b63bd60519752" -"checksum serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)" = "a915306b0f1ac5607797697148c223bedeaa36bcc2e28a01441cd638cc6567b4" -"checksum serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "4b90a9fbe1211e57d3e1c15670f1cb00802988fb23a1a4aad7a2b63544f1920e" +"checksum serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "92514fb95f900c9b5126e32d020f5c6d40564c27a5ea6d1d7d9f157a96623560" +"checksum serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6eabf4b5914e88e24eea240bb7c9f9a2cbc1bbbe8d961d381975ec3c6b806c" +"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" "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" @@ -2222,40 +3331,58 @@ dependencies = [ "checksum slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e544d16c6b230d84c866662fe55e31aacfca6ae71e6fc49ae9a311cb379bfc2f" "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.8 (registry+https://github.com/rust-lang/crates.io-index)" = "88aea073965ab29f6edb5493faf96ad662fb18aa9eeb186a3b7057951605ed15" +"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 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 stdweb 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a3edad410e603184d656e2abded5fd4d3d6e93d5763d21130dbaf99795db74eb" +"checksum stdweb-derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e21ebd9179de08f2300a65454268a17ea3de204627458588c84319c4def3930" +"checksum stdweb-internal-macros 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1635afd059cbfac7d5b1274f0c44cec110c1e013c48e8bbc22e07e52696cf887" +"checksum stdweb-internal-runtime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a2a2f4a2eb556337b2d1a302630bbddf989ae383c70393e89b48152b9896cbda" +"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.0 (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.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "702662512f3ddeb74a64ce2fbbf3707ee1b6bb663d28bb054e0779bbc720d926" -"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" +"checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2" +"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "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.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a1415431cb2398d84da64173f8473c792808314427d4a6f2f3ea85ae67239fe3" "checksum tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e9175261fbdb60781fcd388a4d6cc7e14764a2b629a7ad94abb439aed223a44f" -"checksum tokio 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4790d0be6f4ba6ae4f48190efa2ed7780c9e3567796abdb285003cf39840d9c5" +"checksum tk-listen 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5462b0f968c0457efe38fcd2df7e487096b992419e4f5337b06775a614bbda4b" +"checksum tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fcaabb3cec70485d0df6e9454fe514393ad1c4070dee8915f11041e95630b230" "checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" -"checksum tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "331c8acc267855ec06eb0c94618dcbbfea45bed2d20b77252940095273fb58f6" +"checksum tokio-current-thread 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c756b04680eea21902a46fca4e9f410a2332c04995af590e07ff262e2193a9a3" +"checksum tokio-dns-unofficial 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82c65483db54eb91b4ef3a9389a3364558590faf30ce473141707c0e16fda975" "checksum tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30c6dbf2d1ad1de300b393910e8a3aa272b724a400b6531da03eed99e329fbf0" -"checksum tokio-fs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0e9cbbc8a3698b7ab652340f46633364f9eaa928ddaaee79d8b8f356dd79a09d" -"checksum tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b53aeb9d3f5ccf2ebb29e19788f96987fa1355f8fe45ea193928eaaaf3ae820f" -"checksum tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "afbcdb0f0d2a1e4c440af82d7bbf0bf91a8a8c0575bcd20c05d15be7e9d3a02f" +"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-sync 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1bf2b9dac2a0509b5cfd1df5aa25eafacb616a42a491a13604d6bbeab4486363" "checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" -"checksum tokio-threadpool 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "17465013014410310f9f61fa10bf4724803c149ea1d51efece131c38efca93aa" -"checksum tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4f37f0111d76cc5da132fe9bc0590b9b9cfd079bc7e75ac3846278430a299ff8" +"checksum tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "742e511f6ce2298aeb86fc9ea0d8df81c2388c6ebae3dc8a7316e8c9df0df801" +"checksum tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2910970404ba6fa78c5539126a9ae2045d62e3713041e447f695f41405a120c6" "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.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" -"checksum trie-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7319e28ca295f27359d944a682f7f65b419158bf1590c92cadc0000258d788" -"checksum trie-root 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3c6fef2705af3258ec46a7e22286090394a44216201a1cf7d04b78db825e543" +"checksum twofish 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d261e83e727c8e2dbb75dacac67c36e35db36a958ee504f2164fc052434e1" "checksum twox-hash 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "555cd4909480122bbbf21e34faac4cb08a171f324775670447ed116726c474af" "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.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e7780bb27fd8a22295e0d9d53ae3be253f715a0dccb1808527f478f1c2603708" "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.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +"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 vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum wasmi 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21ef487a11df1ed468cf613c78798c26282da5c30e9d49f824872d4c77b47d1d" @@ -2266,3 +3393,6 @@ dependencies = [ "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum ws 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "329d3e6dd450a9c5c73024e1047f0be7e24121a68484eb0b5368977bee3cf8c3" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +"checksum x25519-dalek 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4aca1ba6bec2719576bd20dfe5b24d9359552e616d10bff257e50cd85f745d17" +"checksum yamux 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "302defd1bed8a9a6d43b82f0e5a50510dfdfbbd02c270c93ff9d6f3f5e2dea89" +"checksum zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8ddfeb6eee2fb3b262ef6e0898a52b7563bb8e0d5955a313b3cf2f808246ea14" diff --git a/node-template/runtime/wasm/Cargo.toml b/node-template/runtime/wasm/Cargo.toml index dbb935c6befbc758caee7235cb7c70ff8f1703ba..8c724fa327e5dede81370bcc2a7d42c395501c63 100644 --- a/node-template/runtime/wasm/Cargo.toml +++ b/node-template/runtime/wasm/Cargo.toml @@ -22,3 +22,11 @@ lto = true [workspace] members = [] + +[patch.crates-io] +trie-db = { path = "../../../../parity-trie/trie-db" } +trie-root = { path = "../../../../parity-trie/trie-root" } +hash-db = { path = "../../../../parity-trie/hash-db" } +memory-db = { path = "../../../../parity-trie/memory-db" } +trie-bench = { path = "../../../../parity-trie/test-support/trie-bench" } +hash256-std-hasher = { path = "../../../../parity-trie/hash256-std-hasher" } diff --git a/node-template/src/chain_spec.rs b/node-template/src/chain_spec.rs index b9f61e45f546b3a07e1900568a97282bf47868ba..ca314ba001b578b81a4932c47cbba00da95e2dcc 100644 --- a/node-template/src/chain_spec.rs +++ b/node-template/src/chain_spec.rs @@ -1,10 +1,12 @@ -use primitives::{Ed25519AuthorityId, ed25519}; +use primitives::{ed25519, sr25519, Pair}; use node_template_runtime::{ AccountId, GenesisConfig, ConsensusConfig, TimestampConfig, BalancesConfig, - SudoConfig, IndicesConfig, FeesConfig, + SudoConfig, IndicesConfig, }; use substrate_service; +use ed25519::Public as AuthorityId; + // Note this is the URL for the telemetry server //const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; @@ -22,6 +24,18 @@ pub enum Alternative { LocalTestnet, } +fn authority_key(s: &str) -> AuthorityId { + ed25519::Pair::from_string(&format!("//{}", s), None) + .expect("static values are valid; qed") + .public() +} + +fn account_key(s: &str) -> AccountId { + sr25519::Pair::from_string(&format!("//{}", s), None) + .expect("static values are valid; qed") + .public() +} + impl Alternative { /// Get an actual chain config from one of the alternatives. pub(crate) fn load(self) -> Result { @@ -30,11 +44,11 @@ impl Alternative { "Development", "dev", || testnet_genesis(vec![ - ed25519::Pair::from_seed(b"Alice ").public().into(), + authority_key("Alice") ], vec![ - ed25519::Pair::from_seed(b"Alice ").public().0.into(), + account_key("Alice") ], - ed25519::Pair::from_seed(b"Alice ").public().0.into() + account_key("Alice") ), vec![], None, @@ -46,17 +60,17 @@ impl Alternative { "Local Testnet", "local_testnet", || testnet_genesis(vec![ - ed25519::Pair::from_seed(b"Alice ").public().into(), - ed25519::Pair::from_seed(b"Bob ").public().into(), + authority_key("Alice"), + authority_key("Bob"), ], vec![ - ed25519::Pair::from_seed(b"Alice ").public().0.into(), - ed25519::Pair::from_seed(b"Bob ").public().0.into(), - ed25519::Pair::from_seed(b"Charlie ").public().0.into(), - ed25519::Pair::from_seed(b"Dave ").public().0.into(), - ed25519::Pair::from_seed(b"Eve ").public().0.into(), - ed25519::Pair::from_seed(b"Ferdie ").public().0.into(), + account_key("Alice"), + account_key("Bob"), + account_key("Charlie"), + account_key("Dave"), + account_key("Eve"), + account_key("Ferdie"), ], - ed25519::Pair::from_seed(b"Alice ").public().0.into() + account_key("Alice"), ), vec![], None, @@ -76,7 +90,7 @@ 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 { consensus: Some(ConsensusConfig { code: include_bytes!("../runtime/wasm/target/wasm32-unknown-unknown/release/node_template_runtime_wasm.compact.wasm").to_vec(), @@ -84,24 +98,22 @@ fn testnet_genesis(initial_authorities: Vec, endowed_account }), system: None, timestamp: Some(TimestampConfig { - period: 5, // 5 second block time. + 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().map(|&k|(k, (1 << 60))).collect(), + balances: endowed_accounts.iter().cloned().map(|k|(k, 1 << 60)).collect(), vesting: vec![], }), sudo: Some(SudoConfig { key: root_key, }), - fees: Some(FeesConfig { - transaction_base_fee: 1, - transaction_byte_fee: 0, - }) } } diff --git a/node-template/src/cli.rs b/node-template/src/cli.rs index 698f0ce7632131ae4715fa9e15ad6deb0908d8f4..258d2194a66c682d2c917bd8855a2ddf075826d4 100644 --- a/node-template/src/cli.rs +++ b/node-template/src/cli.rs @@ -66,6 +66,11 @@ fn run_until_exit( 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); Ok(()) } diff --git a/node-template/src/service.rs b/node-template/src/service.rs index cc51fba51c3f4fd5450f2a9787bfb29110c5ce89..2ff5041f76e7640cce38cec82cc5bff30481cc07 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -12,10 +12,9 @@ use substrate_service::{ TaskExecutor, }; use basic_authorship::ProposerFactory; -use node_executor; use consensus::{import_queue, start_aura, AuraImportQueue, SlotDuration, NothingExtra}; use substrate_client as client; -use primitives::ed25519::Pair; +use primitives::{ed25519::Pair, Pair as PairT}; use inherents::InherentDataProviders; use network::construct_simple_protocol; use substrate_executor::native_executor_instance; @@ -45,7 +44,7 @@ construct_service_factory! { Block = Block, RuntimeApi = RuntimeApi, NetworkProtocol = NodeProtocol { |config| Ok(NodeProtocol::new()) }, - RuntimeDispatch = node_executor::Executor, + RuntimeDispatch = Executor, FullTransactionPoolApi = transaction_pool::ChainApi, FullExecutor, Block, RuntimeApi>, Block> { |config, client| Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(client))) }, LightTransactionPoolApi = transaction_pool::ChainApi, LightExecutor, Block, RuntimeApi>, Block> @@ -63,6 +62,7 @@ construct_service_factory! { let proposer = Arc::new(ProposerFactory { client: service.client(), transaction_pool: service.transaction_pool(), + inherents_pool: service.inherents_pool(), }); let client = service.client(); executor.spawn(start_aura( @@ -74,6 +74,7 @@ construct_service_factory! { service.network(), service.on_exit(), service.config.custom.inherent_data_providers.clone(), + service.config.force_authoring, )?); } @@ -86,7 +87,7 @@ construct_service_factory! { Self::Block, > { |config: &mut FactoryFullConfiguration , client: Arc>| - import_queue( + import_queue::<_, _, _, Pair>( SlotDuration::get_or_compute(&*client)?, client.clone(), None, @@ -99,7 +100,7 @@ construct_service_factory! { Self::Block, > { |config: &mut FactoryFullConfiguration, client: Arc>| - import_queue( + import_queue::<_, _, _, Pair>( SlotDuration::get_or_compute(&*client)?, client.clone(), None, diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index 2c81f127d1c260828699b406b0a3676e2ff7015d..28fb297e5731a7b0a617bd568c62e20010e2dc23 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -12,8 +12,7 @@ tokio = "0.1.7" futures = "0.1" exit-future = "0.1" cli = { package = "substrate-cli", path = "../../core/cli" } -parity-codec = { version = "3.0" } -slog = "^2" +parity-codec = { version = "3.2" } sr-io = { path = "../../core/sr-io" } client = { package = "substrate-client", path = "../../core/client" } primitives = { package = "substrate-primitives", path = "../../core/primitives" } @@ -30,6 +29,7 @@ grandpa = { package = "substrate-finality-grandpa", path = "../../core/finality- sr-primitives = { path = "../../core/sr-primitives" } node-executor = { path = "../executor" } substrate-keystore = { path = "../../core/keystore" } +substrate-telemetry = { package = "substrate-telemetry", path = "../../core/telemetry" } [dev-dependencies] service-test = { package = "substrate-service-test", path = "../../core/service/test" } diff --git a/node/cli/build.rs b/node/cli/build.rs index 6eab113babf88e1375077edea958590c6df89654..e7a7b271f15034498ad00dbf17827a96a7a0a127 100644 --- a/node/cli/build.rs +++ b/node/cli/build.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/node/cli/res/dried-danta.json b/node/cli/res/dried-danta.json index 6f7167d06ccccfc23a6152ab23dadad6c84edb23..1830a6411a39f6c32b2fc489eaf4a4fe7bf95543 100644 --- a/node/cli/res/dried-danta.json +++ b/node/cli/res/dried-danta.json @@ -11,7 +11,9 @@ "/ip4/104.211.48.247/tcp/30333/p2p/QmV2zjgFRfxbgYZQC9qFr4aHsQt7tDBJRAdgqqxqTq1Kta", "/ip4/40.114.120.164/tcp/30333/p2p/QmQbPCeurXuKhzCw6Ar6ovizNKATMTnkkqFJKgZzbF2MJs" ], - "telemetryUrl": "wss://telemetry.polkadot.io/submit/", + "telemetryEndpoints": [ + ["wss://telemetry.polkadot.io/submit/", 0] + ], "protocolId": null, "consensusEngine": null, "genesis": { diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index 5148c191238b40de22bbce92ce8ede64ade90817..818a194f992766755ce24fd113a66a5441705f93 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -16,16 +16,15 @@ //! Substrate chain configurations. -use primitives::{Ed25519AuthorityId, ed25519}; +use primitives::{ed25519::Public as AuthorityId, ed25519, sr25519, Pair, crypto::UncheckedInto}; use node_primitives::AccountId; use node_runtime::{ConsensusConfig, CouncilSeatsConfig, CouncilVotingConfig, DemocracyConfig, - SessionConfig, StakingConfig, TimestampConfig, BalancesConfig, TreasuryConfig, - SudoConfig, ContractConfig, GrandpaConfig, IndicesConfig, FeesConfig, Permill, Perbill}; + SessionConfig, StakingConfig, StakerStatus, TimestampConfig, BalancesConfig, TreasuryConfig, + SudoConfig, ContractConfig, GrandpaConfig, IndicesConfig, Permill, Perbill}; pub use node_runtime::GenesisConfig; use substrate_service; use hex_literal::{hex, hex_impl}; - -use substrate_keystore::pad_seed; +use substrate_telemetry::TelemetryEndpoints; const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; @@ -38,14 +37,31 @@ pub fn dried_danta_config() -> Result { } fn staging_testnet_config_genesis() -> GenesisConfig { - let initial_authorities = vec![ - hex!["82c39b31a2b79a90f8e66e7a77fdb85a4ed5517f2ae39f6a80565e8ecae85cf5"].into(), - hex!["4de37a07567ebcbf8c64568428a835269a566723687058e017b6d69db00a77e7"].into(), - hex!["063d7787ebca768b7445dfebe7d62cbb1625ff4dba288ea34488da266dd6dca5"].into(), - hex!["8101764f45778d4980dadaceee6e8af2517d3ab91ac9bec9cd1714fa5994081c"].into(), - ]; - let endowed_accounts = vec![ - hex!["f295940fa750df68a686fcf4abd4111c8a9c5a5a5a83c4c8639c451a94a7adfd"].into(), + // stash, controller, session-key + // generated with secret: + // for i in 1 2 3 4 ; do for j in stash controller; do subkey -p danta-$i-$j restore $secret; done; done + // and + // for i in 1 2 3 4 ; do for j in session; do subkey --ed25519 -p danta-$i-$j restore $secret; done; done + let initial_authorities: Vec<(AccountId, AccountId, AuthorityId)> = vec![( + hex!["d807f8bd6b4b02b3db716dd5372960b094ed0e62b5704a07bc990130a642992b"].unchecked_into(), // 5GwxZv7LxSUQn89TLUaLi3oEWhFcabqW3nHcEg2J88gZNhrb + hex!["1a934af462454e512e22b5d9455c0c3c2df479b1c61406b3d990f6bc2eb25e09"].unchecked_into(), // 5CfYrg5cW8UebBdfJpJbKFhZLyk7yHWXUgdxZnSGb2dWKgpt + hex!["831fcce3a9565baf093b52568a8cb9875cb54974d80da8fc4f0cc767128a23e9"].unchecked_into(), // 5F2daQPHK7yv4Yuwyz3cggvvn1R5u1ofGMQ5LK5XvnfebMcX + ),( + hex!["12652f26e427c56268095bb0ec5824471e37722b073a9fa5de61c61c1de94656"].unchecked_into(), // 5CUpn2JmpsWkHQjZgWjN3rqPEUnjjUQZYcMk14nbUgR2Gpab + hex!["5279e73e22971d729276ebad4eb6804d1b9c0c35bd32e8aba4513c674760a461"].unchecked_into(), // 5Dvqzke7Mdp3fP6Ysut7UXPSepPr3Qguys6LNkZGPSwXwAkR + hex!["dbe61640d854bb7bf83cbfaf638a8a4c76c49a919ec3bbdd86799061fc1903e4"].unchecked_into(), // 5H32hCtKf6nXSckviVhUvWb7N14wDCRunRkCM29mxEXwjcUZ + ),( + hex!["a81d738fdeeaed440cfce5635e0820d0d23e89207cf66a62b8c0d2a968e37d32"].unchecked_into(), // 5Fs8ehAjDEnenDwULCPnEr3HVXgepAVfyk9ABW84NfxCYtWD + hex!["443a2c779a5f5dada8ee6921efec9673f67e5ce1bd6012899ff6c1adc437696c"].unchecked_into(), // 5DcAPqR269myKXhZmwbU1x2xLbuTojr85jHNRuDhrFdZ3vwi + hex!["5bc01f56225e8602372fb343dba65a73e20c55bdbb3b8343a8f34df298a616fb"].unchecked_into(), // 5E91HbY2xo2qDJzi3KY8nRXjDNAQE9WtmMaji6YRwT8DAuK1 + ),( + hex!["e269e835e0bc07c497d55bc17c7bb29c85c5615f9e61582ffdeca7e5f5c66578"].unchecked_into(), // 5HBa95U5HDFCV1N5Xyrjti65F71tHRQcPbZBmkxRJ39SpqzM + hex!["3e9829e6fd4fc7501b504fc16f12177c6c7f38aeb3b8344efb9b15ee85118b2c"].unchecked_into(), // 5DUn2afs2QevZ6PrGu8snrt76157oacH6JXUD8JNM18VKMwK + hex!["0fd673ee5e95ed124bcd71463ff924c810573dad91527ab9d2b5af36f66ff84b"].unchecked_into(), // 5CRUHGLA1JYe2v4p479VCHybqjB9uBXjGkJ2npdduVdrTuUM + )]; + // generated with secret: subkey -p danta-root restore $secret + let endowed_accounts: Vec = vec![ + hex!["343df6f04ffae0840f214f6cb0da00b612c7e9347f980e7afafc520582f79136"].unchecked_into(), // 5DFCkiP9vky31C1ZP3LpuQYinLAFwQqq6vda7NXa8ALCpq5D ]; const MILLICENTS: u128 = 1_000_000_000; const CENTS: u128 = 1_000 * MILLICENTS; // assume this is worth about a cent. @@ -56,39 +72,49 @@ fn staging_testnet_config_genesis() -> GenesisConfig { const HOURS: u64 = MINUTES * 60; const DAYS: u64 = HOURS * 24; + const ENDOWMENT: u128 = 10_000_000 * DOLLARS; + const STASH: u128 = 100 * DOLLARS; + GenesisConfig { consensus: Some(ConsensusConfig { code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm").to_vec(), // FIXME change once we have #1252 - authorities: initial_authorities.clone(), + authorities: initial_authorities.iter().map(|x| x.2.clone()).collect(), }), system: None, balances: Some(BalancesConfig { - balances: endowed_accounts.iter().map(|&k| (k, 10_000_000 * DOLLARS)).collect(), + 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 { - ids: endowed_accounts.clone(), + ids: endowed_accounts.iter().cloned() + .chain(initial_authorities.iter().map(|x| x.0.clone())) + .collect::>(), }), session: Some(SessionConfig { - validators: initial_authorities.iter().cloned().map(Into::into).collect(), + validators: initial_authorities.iter().map(|x| x.1.clone()).collect(), session_length: 5 * MINUTES, + keys: initial_authorities.iter().map(|x| (x.1.clone(), x.2.clone())).collect::>(), }), staking: Some(StakingConfig { current_era: 0, - intentions: initial_authorities.iter().cloned().map(Into::into).collect(), offline_slash: Perbill::from_billionths(1_000_000), session_reward: Perbill::from_billionths(2_065), - current_offline_slash: 0, current_session_reward: 0, validator_count: 7, sessions_per_era: 12, bonding_duration: 60 * MINUTES, offline_slash_grace: 4, minimum_validator_count: 4, - invulnerables: initial_authorities.iter().cloned().map(Into::into).collect(), + 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(), }), democracy: Some(DemocracyConfig { launch_period: 10 * MINUTES, // 1 day per public referendum @@ -115,7 +141,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig { enact_delay_period: 0, }), timestamp: Some(TimestampConfig { - period: SECS_PER_BLOCK / 2, // due to the nature of aura the slots are 2*period + 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), @@ -124,6 +150,10 @@ fn staging_testnet_config_genesis() -> GenesisConfig { burn: Permill::from_percent(50), }), contract: Some(ContractConfig { + 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, @@ -136,11 +166,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig { key: endowed_accounts[0].clone(), }), grandpa: Some(GrandpaConfig { - authorities: initial_authorities.clone().into_iter().map(|k| (k, 1)).collect(), - }), - fees: Some(FeesConfig { - transaction_base_fee: 1 * CENTS, - transaction_byte_fee: 10 * MILLICENTS, + authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(), }), } } @@ -153,70 +179,97 @@ pub fn staging_testnet_config() -> ChainSpec { "staging_testnet", staging_testnet_config_genesis, boot_nodes, - Some(STAGING_TELEMETRY_URL.into()), + Some(TelemetryEndpoints::new(vec![(STAGING_TELEMETRY_URL.to_string(), 0)])), None, None, None, ) } -/// Helper function to generate AuthorityID from seed -pub fn get_authority_id_from_seed(seed: &str) -> Ed25519AuthorityId { - let padded_seed = pad_seed(seed); - // NOTE from ed25519 impl: - // prefer pkcs#8 unless security doesn't matter -- this is used primarily for tests. - ed25519::Pair::from_seed(&padded_seed).public().0.into() +/// Helper function to generate AccountId from seed +pub fn get_account_id_from_seed(seed: &str) -> AccountId { + sr25519::Pair::from_string(&format!("//{}", seed), None) + .expect("static values are valid; qed") + .public() +} + +/// Helper function to generate AuthorityId from seed +pub fn get_session_key_from_seed(seed: &str) -> AuthorityId { + ed25519::Pair::from_string(&format!("//{}", seed), None) + .expect("static values are valid; qed") + .public() +} + +/// Helper function to generate stash, controller and session key from seed +pub fn get_authority_keys_from_seed(seed: &str) -> (AccountId, AccountId, AuthorityId) { + ( + get_account_id_from_seed(&format!("{}//stash", seed)), + get_account_id_from_seed(seed), + get_session_key_from_seed(seed) + ) } /// Helper function to create GenesisConfig for testing pub fn testnet_genesis( - initial_authorities: Vec, + initial_authorities: Vec<(AccountId, AccountId, AuthorityId)>, root_key: AccountId, - endowed_accounts: Option>, + endowed_accounts: Option>, ) -> GenesisConfig { - let endowed_accounts = endowed_accounts.unwrap_or_else(|| { + let endowed_accounts: Vec = endowed_accounts.unwrap_or_else(|| { vec![ - get_authority_id_from_seed("Alice"), - get_authority_id_from_seed("Bob"), - get_authority_id_from_seed("Charlie"), - get_authority_id_from_seed("Dave"), - get_authority_id_from_seed("Eve"), - get_authority_id_from_seed("Ferdie"), + get_account_id_from_seed("Alice"), + get_account_id_from_seed("Bob"), + get_account_id_from_seed("Charlie"), + get_account_id_from_seed("Dave"), + get_account_id_from_seed("Eve"), + get_account_id_from_seed("Ferdie"), + get_account_id_from_seed("Alice//stash"), + get_account_id_from_seed("Bob//stash"), + get_account_id_from_seed("Charlie//stash"), + get_account_id_from_seed("Dave//stash"), + get_account_id_from_seed("Eve//stash"), + get_account_id_from_seed("Ferdie//stash"), ] }); + + const STASH: u128 = 1 << 20; + const ENDOWMENT: u128 = 1 << 20; + GenesisConfig { consensus: Some(ConsensusConfig { code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm").to_vec(), - authorities: initial_authorities.clone(), + authorities: initial_authorities.iter().map(|x| x.2.clone()).collect(), }), system: None, indices: Some(IndicesConfig { - ids: endowed_accounts.iter().map(|x| x.0.into()).collect(), + 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.into(), (1 << 60))).collect(), + balances: endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect(), vesting: vec![], }), session: Some(SessionConfig { - validators: initial_authorities.iter().cloned().map(Into::into).collect(), + validators: initial_authorities.iter().map(|x| x.1.clone()).collect(), session_length: 10, + keys: initial_authorities.iter().map(|x| (x.1.clone(), x.2.clone())).collect::>(), }), staking: Some(StakingConfig { current_era: 0, - intentions: initial_authorities.iter().cloned().map(Into::into).collect(), minimum_validator_count: 1, validator_count: 2, sessions_per_era: 5, bonding_duration: 2 * 60 * 12, offline_slash: Perbill::zero(), session_reward: Perbill::zero(), - current_offline_slash: 0, current_session_reward: 0, offline_slash_grace: 0, - invulnerables: initial_authorities.iter().cloned().map(Into::into).collect(), + 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(), }), democracy: Some(DemocracyConfig { launch_period: 9, @@ -227,8 +280,8 @@ pub fn testnet_genesis( }), council_seats: Some(CouncilSeatsConfig { active_council: endowed_accounts.iter() - .filter(|a| initial_authorities.iter().find(|&b| a.0 == b.0).is_none()) - .map(|a| (a.clone().into(), 1000000)).collect(), + .filter(|&endowed| initial_authorities.iter().find(|&(_, controller, _)| controller == endowed).is_none()) + .map(|a| (a.clone(), 1000000)).collect(), candidacy_bond: 10, voter_bond: 2, present_slash_per_voter: 1, @@ -236,7 +289,7 @@ pub fn testnet_genesis( presentation_duration: 10, approval_voting_period: 20, term_duration: 1000000, - desired_seats: (endowed_accounts.len() - initial_authorities.len()) as u32, + desired_seats: (endowed_accounts.len() / 2 - initial_authorities.len()) as u32, inactive_grace_period: 1, }), council_voting: Some(CouncilVotingConfig { @@ -245,7 +298,7 @@ pub fn testnet_genesis( enact_delay_period: 0, }), timestamp: Some(TimestampConfig { - period: 2, // 2*2=4 second block time. + minimum_period: 2, // 2*2=4 second block time. }), treasury: Some(TreasuryConfig { proposal_bond: Permill::from_percent(5), @@ -254,6 +307,10 @@ pub fn testnet_genesis( burn: Permill::from_percent(50), }), contract: Some(ContractConfig { + 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, @@ -266,11 +323,7 @@ pub fn testnet_genesis( key: root_key, }), grandpa: Some(GrandpaConfig { - authorities: initial_authorities.clone().into_iter().map(|k| (k, 1)).collect(), - }), - fees: Some(FeesConfig { - transaction_base_fee: 1, - transaction_byte_fee: 0, + authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(), }), } } @@ -278,9 +331,9 @@ pub fn testnet_genesis( fn development_config_genesis() -> GenesisConfig { testnet_genesis( vec![ - get_authority_id_from_seed("Alice"), + get_authority_keys_from_seed("Alice"), ], - get_authority_id_from_seed("Alice").into(), + get_account_id_from_seed("Alice"), None, ) } @@ -293,10 +346,10 @@ pub fn development_config() -> ChainSpec { fn local_testnet_genesis() -> GenesisConfig { testnet_genesis( vec![ - get_authority_id_from_seed("Alice"), - get_authority_id_from_seed("Bob"), + get_authority_keys_from_seed("Alice"), + get_authority_keys_from_seed("Bob"), ], - get_authority_id_from_seed("Alice").into(), + get_account_id_from_seed("Alice"), None, ) } @@ -314,7 +367,7 @@ mod tests { fn local_testnet_genesis_instant() -> GenesisConfig { let mut genesis = local_testnet_genesis(); - genesis.timestamp = Some(TimestampConfig { period: 0 }); + genesis.timestamp = Some(TimestampConfig { minimum_period: 1 }); genesis } diff --git a/node/cli/src/error.rs b/node/cli/src/error.rs index eba18eacdfffc4ceb279f810bf90d8399eff8da5..dd5448ac8ad6366813387e7694a4f69872117ff7 100644 --- a/node/cli/src/error.rs +++ b/node/cli/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/node/cli/src/lib.rs b/node/cli/src/lib.rs index 5586a9b1913575fcdcc364d01f1cc7ea1d7ea73a..1b103b7bfc1961fc6bbb35f00be0ca613334b82a 100644 --- a/node/cli/src/lib.rs +++ b/node/cli/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index ff241a4c98a33d4fc1ad676cf0b8dd5f3e6fb465..c4dd70fc51728ce925f89274a2e0759ce0f1c7b2 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -25,7 +25,7 @@ use client; use consensus::{import_queue, start_aura, AuraImportQueue, SlotDuration, NothingExtra}; use grandpa; use node_executor; -use primitives::ed25519::Pair; +use primitives::{Pair as PairT, ed25519}; use node_primitives::Block; use node_runtime::{GenesisConfig, RuntimeApi}; use substrate_service::{ @@ -76,7 +76,7 @@ construct_service_factory! { { |config: FactoryFullConfiguration, executor: TaskExecutor| FullComponents::::new(config, executor) }, AuthoritySetup = { - |mut service: Self::FullService, executor: TaskExecutor, local_key: Option>| { + |mut service: Self::FullService, executor: TaskExecutor, local_key: Option>| { let (block_import, link_half) = service.config.custom.grandpa_import_setup.take() .expect("Link Half and Block Import are present for Full Services or setup failed before. qed"); @@ -85,6 +85,7 @@ construct_service_factory! { let proposer = Arc::new(substrate_basic_authorship::ProposerFactory { client: service.client(), transaction_pool: service.transaction_pool(), + inherents_pool: service.inherents_pool(), }); let client = service.client(); @@ -97,21 +98,29 @@ construct_service_factory! { service.network(), service.on_exit(), service.config.custom.inherent_data_providers.clone(), + service.config.force_authoring, )?); info!("Running Grandpa session as Authority {}", key.public()); } + let local_key = if service.config.disable_grandpa { + None + } else { + local_key + }; + executor.spawn(grandpa::run_grandpa( grandpa::Config { local_key, // FIXME #1578 make this available through chainspec - gossip_duration: Duration::new(4, 0), + gossip_duration: Duration::from_millis(333), justification_period: 4096, name: Some(service.config.name.clone()) }, link_half, grandpa::NetworkBridge::new(service.network()), + service.config.custom.inherent_data_providers.clone(), service.on_exit(), )?); @@ -132,7 +141,7 @@ construct_service_factory! { config.custom.grandpa_import_setup = Some((block_import.clone(), link_half)); - import_queue( + import_queue::<_, _, _, ed25519::Pair>( slot_duration, block_import, Some(justification_import), @@ -143,16 +152,16 @@ construct_service_factory! { }}, LightImportQueue = AuraImportQueue { |config: &FactoryFullConfiguration, client: Arc>| { - import_queue( - SlotDuration::get_or_compute(&*client)?, - client.clone(), - None, - client, - NothingExtra, - config.custom.inherent_data_providers.clone(), - ).map_err(Into::into) - } - }, + import_queue::<_, _, _, ed25519::Pair>( + SlotDuration::get_or_compute(&*client)?, + client.clone(), + None, + client, + NothingExtra, + config.custom.inherent_data_providers.clone(), + ).map_err(Into::into) + } + }, } } diff --git a/node/executor/Cargo.toml b/node/executor/Cargo.toml index 2a975437445a9c3b824315e54773f0e4b1f8a219..3c2e9a688cb9bb05ee795b9ee26b5c46b1f0b4fa 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.11" -parity-codec = "3.0" +trie-root = "0.12" +parity-codec = "3.2" runtime_io = { package = "sr-io", path = "../../core/sr-io" } state_machine = { package = "substrate-state-machine", path = "../../core/state-machine" } substrate-executor = { path = "../../core/executor" } @@ -30,7 +30,6 @@ treasury = { package = "srml-treasury", path = "../../srml/treasury" } contract = { package = "srml-contract", path = "../../srml/contract" } grandpa = { package = "srml-grandpa", path = "../../srml/grandpa" } indices = { package = "srml-indices", path = "../../srml/indices" } -fees = { package = "srml-fees", path = "../../srml/fees" } wabt = "~0.7.4" [features] diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index e198183624acf6e50783eba30372c0035a1b991f..22bf1a9b799af5701a8749791f284cbc06be558d 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -31,22 +31,20 @@ mod tests { use super::Executor; use substrate_executor::{WasmExecutor, NativeExecutionDispatch}; use parity_codec::{Encode, Decode, Joiner}; - use keyring::ed25519::Keyring; + use keyring::{AuthorityKeyring, AccountKeyring}; use runtime_support::{Hashable, StorageValue, StorageMap, traits::Currency}; use state_machine::{CodeExecutor, Externalities, TestExternalities}; - use primitives::{ - twox_128, Blake2Hasher, ChangesTrieConfiguration, ed25519::{Public, Pair}, NeverNativeValue, - NativeOrEncoded - }; + use primitives::{twox_128, Blake2Hasher, ChangesTrieConfiguration, NeverNativeValue, + NativeOrEncoded}; use node_primitives::{Hash, BlockNumber, AccountId}; - use runtime_primitives::traits::{Header as HeaderT, Digest as DigestT, Hash as HashT}; + use runtime_primitives::traits::{Header as HeaderT, Hash as HashT}; use runtime_primitives::{generic, generic::Era, ApplyOutcome, ApplyError, ApplyResult, Perbill}; - use {balances, indices, staking, session, system, consensus, timestamp, treasury, contract}; + use {balances, indices, session, system, staking, consensus, timestamp, treasury, contract}; use contract::ContractAddressFor; use system::{EventRecord, Phase}; use node_runtime::{Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Call, Runtime, Balances, BuildStorage, GenesisConfig, BalancesConfig, SessionConfig, StakingConfig, System, - SystemConfig, GrandpaConfig, IndicesConfig, FeesConfig, Event, Log}; + SystemConfig, GrandpaConfig, IndicesConfig, Event, Log}; use wabt; use primitives::map; @@ -55,15 +53,27 @@ mod tests { const GENESIS_HASH: [u8; 32] = [69u8; 32]; fn alice() -> AccountId { - AccountId::from(Keyring::Alice.to_raw_public()) + AccountKeyring::Alice.into() } fn bob() -> AccountId { - AccountId::from(Keyring::Bob.to_raw_public()) + AccountKeyring::Bob.into() } fn charlie() -> AccountId { - AccountId::from(Keyring::Charlie.to_raw_public()) + AccountKeyring::Charlie.into() + } + + fn dave() -> AccountId { + AccountKeyring::Dave.into() + } + + fn eve() -> AccountId { + AccountKeyring::Eve.into() + } + + fn ferdie() -> AccountId { + AccountKeyring::Ferdie.into() } fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic { @@ -71,12 +81,12 @@ mod tests { Some((signed, index)) => { let era = Era::mortal(256, 0); let payload = (index.into(), xt.function, era, GENESIS_HASH); - let pair = Pair::from(Keyring::from_public(Public::from_raw(signed.clone().into())).unwrap()); + let key = AccountKeyring::from_public(&signed).unwrap(); let signature = payload.using_encoded(|b| { if b.len() > 256 { - pair.sign(&runtime_io::blake2_256(b)) + key.sign(&runtime_io::blake2_256(b)) } else { - pair.sign(b) + key.sign(b) } }).into(); UncheckedExtrinsic { @@ -116,8 +126,8 @@ mod tests { twox_128(>::key()).to_vec() => vec![0u8; 16], twox_128(>::key()).to_vec() => vec![0u8; 16], twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32], - twox_128(>::key()).to_vec() => vec![70u8; 16], - twox_128(>::key()).to_vec() => vec![0u8; 16] + twox_128(>::key()).to_vec() => vec![70u8; 16], + twox_128(>::key()).to_vec() => vec![0u8; 16] ]); let r = executor().call::<_, NeverNativeValue, fn() -> _>( @@ -149,8 +159,8 @@ mod tests { twox_128(>::key()).to_vec() => vec![0u8; 16], twox_128(>::key()).to_vec() => vec![0u8; 16], twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32], - twox_128(>::key()).to_vec() => vec![70u8; 16], - twox_128(>::key()).to_vec() => vec![0u8; 16] + twox_128(>::key()).to_vec() => vec![70u8; 16], + twox_128(>::key()).to_vec() => vec![0u8; 16] ]); let r = executor().call::<_, NeverNativeValue, fn() -> _>( @@ -182,8 +192,8 @@ mod tests { twox_128(>::key()).to_vec() => vec![0u8; 16], twox_128(>::key()).to_vec() => vec![0u8; 16], twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32], - 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] ]); let r = executor().call::<_, NeverNativeValue, fn() -> _>( @@ -219,8 +229,8 @@ mod tests { twox_128(>::key()).to_vec() => vec![0u8; 16], twox_128(>::key()).to_vec() => vec![0u8; 16], twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32], - 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] ]); let r = executor().call::<_, NeverNativeValue, fn() -> _>( @@ -247,7 +257,7 @@ mod tests { } fn new_test_ext(code: &[u8], support_changes_trie: bool) -> TestExternalities { - let three = [3u8; 32].into(); + let three = AccountId::from_raw([3u8; 32]); TestExternalities::new_with_code(code, GenesisConfig { consensus: Some(Default::default()), system: Some(SystemConfig { @@ -258,12 +268,18 @@ mod tests { ..Default::default() }), indices: Some(IndicesConfig { - ids: vec![alice(), charlie()], + 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), ], existential_deposit: 0, transfer_fee: 0, @@ -272,21 +288,29 @@ mod tests { }), session: Some(SessionConfig { session_length: 2, - validators: vec![Keyring::One.to_raw_public().into(), Keyring::Two.to_raw_public().into(), three], + validators: vec![AccountKeyring::One.into(), AccountKeyring::Two.into(), three], + keys: vec![ + (alice(), AuthorityKeyring::Alice.into()), + (bob(), AuthorityKeyring::Bob.into()), + (charlie(), AuthorityKeyring::Charlie.into()) + ] }), staking: Some(StakingConfig { sessions_per_era: 2, current_era: 0, - intentions: vec![alice(), bob(), Keyring::Charlie.to_raw_public().into()], + stakers: vec![ + (dave(), alice(), 111, staking::StakerStatus::Validator), + (eve(), bob(), 100, staking::StakerStatus::Validator), + (ferdie(), charlie(), 100, staking::StakerStatus::Validator) + ], validator_count: 3, minimum_validator_count: 0, bonding_duration: 0, offline_slash: Perbill::zero(), session_reward: Perbill::zero(), - current_offline_slash: 0, current_session_reward: 0, offline_slash_grace: 0, - invulnerables: vec![alice(), bob(), Keyring::Charlie.to_raw_public().into()], + invulnerables: vec![alice(), bob(), charlie()], }), democracy: Some(Default::default()), council_seats: Some(Default::default()), @@ -296,15 +320,7 @@ mod tests { contract: Some(Default::default()), sudo: Some(Default::default()), grandpa: Some(GrandpaConfig { - authorities: vec![ // set these so no GRANDPA events fire when session changes - (Keyring::Alice.to_raw_public().into(), 1), - (Keyring::Bob.to_raw_public().into(), 1), - (Keyring::Charlie.to_raw_public().into(), 1), - ], - }), - fees: Some(FeesConfig { - transaction_base_fee: 1, - transaction_byte_fee: 0, + authorities: vec![], }), }.build_storage().unwrap().0) } @@ -353,7 +369,7 @@ mod tests { ).0.unwrap(); } - let correct_header = match Executor::new(None).call::<_, NeverNativeValue, fn() -> _>( + let header = match Executor::new(None).call::<_, NeverNativeValue, fn() -> _>( env, "BlockBuilder_finalise_block", &[0u8;0], @@ -364,9 +380,8 @@ mod tests { NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(), }; - - let hash = correct_header.blake2_256(); - (Block { header: correct_header, extrinsics }.encode(), hash.into()) + let hash = header.blake2_256(); + (Block { header, extrinsics }.encode(), hash.into()) } fn changes_trie_block() -> (Vec, Hash) { @@ -427,12 +442,7 @@ mod tests { ] ); - let mut digest = generic::Digest::::default(); - digest.push(Log::from(::grandpa::RawLog::AuthoritiesChangeSignal(0, vec![ - (Keyring::One.to_raw_public().into(), 1), - (Keyring::Two.to_raw_public().into(), 1), - ([3u8; 32].into(), 1), - ]))); + let digest = generic::Digest::::default(); assert_eq!(Header::decode(&mut &block2.0[..]).unwrap().digest, digest); (block1, block2) @@ -471,24 +481,15 @@ mod tests { ).0.unwrap(); runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 41); - assert_eq!(Balances::total_balance(&bob()), 69); + // 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![ EventRecord { phase: Phase::ApplyExtrinsic(0), event: Event::system(system::Event::ExtrinsicSuccess) }, - EventRecord { - phase: Phase::ApplyExtrinsic(1), - event: Event::indices(indices::RawEvent::NewAccountIndex(bob(), 2)) - }, - EventRecord { - phase: Phase::ApplyExtrinsic(1), - event: Event::balances(balances::RawEvent::NewAccount( - bob().into(), - 69 - )) - }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: Event::balances(balances::RawEvent::Transfer( @@ -514,13 +515,9 @@ mod tests { phase: Phase::Finalization, event: Event::treasury(treasury::RawEvent::Rollover(0)) }, - EventRecord { - phase: Phase::Finalization, - event: Event::fees(fees::RawEvent::Charged(1, 1)) - } ]); }); - + executor().call::<_, NeverNativeValue, fn() -> _>( &mut t, "Core_execute_block", @@ -530,8 +527,11 @@ mod tests { ).0.unwrap(); runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 30); - assert_eq!(Balances::total_balance(&bob()), 78); + // 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![ EventRecord { phase: Phase::ApplyExtrinsic(0), @@ -571,18 +571,6 @@ mod tests { phase: Phase::Finalization, event: Event::session(session::RawEvent::NewSession(1)) }, - EventRecord { - phase: Phase::Finalization, - event: Event::staking(staking::RawEvent::Reward(0)) - }, - EventRecord { - phase: Phase::Finalization, - event: Event::grandpa(::grandpa::RawEvent::NewAuthorities(vec![ - (Keyring::One.to_raw_public().into(), 1), - (Keyring::Two.to_raw_public().into(), 1), - ([3u8; 32].into(), 1), - ])), - }, EventRecord { phase: Phase::Finalization, event: Event::treasury(treasury::RawEvent::Spending(0)) @@ -595,14 +583,6 @@ mod tests { phase: Phase::Finalization, event: Event::treasury(treasury::RawEvent::Rollover(0)) }, - EventRecord { - phase: Phase::Finalization, - event: Event::fees(fees::RawEvent::Charged(1, 1)) - }, - EventRecord { - phase: Phase::Finalization, - event: Event::fees(fees::RawEvent::Charged(2, 1)) - } ]); }); } @@ -616,15 +596,20 @@ mod tests { WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1.0).unwrap(); runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 41); - assert_eq!(Balances::total_balance(&bob()), 69); + // 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); }); WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block2.0).unwrap(); runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 30); - assert_eq!(Balances::total_balance(&bob()), 78); + // 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); }); } @@ -748,7 +733,7 @@ mod tests { CheckedExtrinsic { signed: Some((charlie(), 2)), function: Call::Contract( - contract::Call::call::(indices::address::Address::Id(addr), 10, 10_000, vec![0x00, 0x01, 0x02, 0x03]) + contract::Call::call::(indices::address::Address::Id(addr.clone()), 10, 10_000, vec![0x00, 0x01, 0x02, 0x03]) ), }, ] @@ -818,8 +803,8 @@ mod tests { twox_128(>::key()).to_vec() => vec![0u8; 16], twox_128(>::key()).to_vec() => vec![0u8; 16], twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32], - twox_128(>::key()).to_vec() => vec![70u8; 16], - twox_128(>::key()).to_vec() => vec![0u8; 16] + twox_128(>::key()).to_vec() => vec![70u8; 16], + twox_128(>::key()).to_vec() => vec![0u8; 16] ]); let r = WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_initialise_block", &vec![].and(&from_block_number(1u64))); @@ -840,8 +825,8 @@ mod tests { twox_128(>::key()).to_vec() => vec![0u8; 16], twox_128(>::key()).to_vec() => vec![0u8; 16], twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32], - 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] ]); let r = WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_initialise_block", &vec![].and(&from_block_number(1u64))); @@ -877,7 +862,7 @@ mod tests { #[test] fn full_wasm_block_import_works_with_changes_trie() { let block1 = changes_trie_block(); - + let mut t = new_test_ext(COMPACT_CODE, true); WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1.0).unwrap(); diff --git a/node/primitives/Cargo.toml b/node/primitives/Cargo.toml index cb28cfd744f80c354936b32b9b3958996b35e904..b7da80c9a879e3b03f6d02758334b9828f02fea5 100644 --- a/node/primitives/Cargo.toml +++ b/node/primitives/Cargo.toml @@ -5,10 +5,10 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", default-features = false } +parity-codec-derive = { version = "3.1", default-features = false } 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 } @@ -26,5 +26,5 @@ std = [ "rstd/std", "runtime_primitives/std", "serde_derive", - "serde/std", + "serde", ] diff --git a/node/primitives/src/lib.rs b/node/primitives/src/lib.rs index 4c72239e6d57524dcb7cacc41f0c9c5e7a48e922..0d8906c47df817f4c6c62c2a3b6d54365b47bb77 100644 --- a/node/primitives/src/lib.rs +++ b/node/primitives/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -22,14 +22,14 @@ #![cfg_attr(not(feature = "std"), feature(alloc))] use runtime_primitives::{ - generic, traits::{Verify, BlakeTwo256}, Ed25519Signature, OpaqueExtrinsic + generic, traits::{Verify, BlakeTwo256}, OpaqueExtrinsic, AnySignature }; /// An index to a block. pub type BlockNumber = u64; -/// Alias to 512-bit hash when used in the context of a signature on the chain. -pub type Signature = Ed25519Signature; +/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. +pub type Signature = AnySignature; /// Some way of identifying an account on the chain. We intentionally make it equivalent /// to the public key of our transaction signing scheme. @@ -44,7 +44,10 @@ pub type Balance = u128; /// The Ed25519 pub key of an session that belongs to an authority of the chain. This is /// exactly equivalent to what the substrate calls an "authority". -pub type SessionKey = primitives::Ed25519AuthorityId; +pub type AuthorityId = ::Signer; + +/// Alias to 512-bit hash when used in the context of a session signature on the chain. +pub type AuthoritySignature = primitives::ed25519::Signature; /// Index of a transaction in the chain. pub type Index = u64; @@ -56,7 +59,8 @@ pub type Hash = primitives::H256; pub type Timestamp = u64; /// Header type. -pub type Header = generic::Header>; +/// +pub type Header = generic::Header>; /// Block type. pub type Block = generic::Block; /// Block ID. diff --git a/node/runtime/Cargo.toml b/node/runtime/Cargo.toml index 1c62c328947ae2b3460efb9716a9f13b64b44aec..6c0307d47e1f7506f3845a4e2bfa457c01768e45 100644 --- a/node/runtime/Cargo.toml +++ b/node/runtime/Cargo.toml @@ -7,12 +7,12 @@ edition = "2018" [dependencies] integer-sqrt = { version = "0.1.2" } safe-mix = { version = "1.0", default-features = false } -parity-codec-derive = { version = "3.0" } -parity-codec = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", 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 } runtime_primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } +offchain-primitives = { package = "substrate-offchain-primitives", path = "../../core/offchain/primitives", default-features = false } 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 } @@ -22,6 +22,7 @@ contract = { package = "srml-contract", path = "../../srml/contract", default-fe council = { package = "srml-council", path = "../../srml/council", default-features = false } democracy = { package = "srml-democracy", path = "../../srml/democracy", 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 } @@ -30,8 +31,6 @@ system = { package = "srml-system", path = "../../srml/system", default-features timestamp = { package = "srml-timestamp", path = "../../srml/timestamp", default-features = false } treasury = { package = "srml-treasury", path = "../../srml/treasury", default-features = false } sudo = { package = "srml-sudo", path = "../../srml/sudo", default-features = false } -srml-upgrade-key = { path = "../../srml/upgrade-key", default-features = false } -fees = { package = "srml-fees", path = "../../srml/fees", default-features = false } node-primitives = { path = "../primitives", default-features = false } consensus_aura = { package = "substrate-consensus-aura-primitives", path = "../../core/consensus/aura/primitives", default-features = false } rustc-hex = { version = "2.0", optional = true } @@ -61,11 +60,9 @@ std = [ "timestamp/std", "treasury/std", "sudo/std", - "srml-upgrade-key/std", - "fees/std", "version/std", "node-primitives/std", - "serde/std", + "serde", "safe-mix/std", "client/std", "consensus_aura/std", diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 56ac26b4e8e00ae26ad41bcf9ea4280c54a26c53..dc1683c38e2b517ab145bcecd33a76d102d64656 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -21,13 +21,10 @@ #![recursion_limit="256"] use rstd::prelude::*; -use parity_codec_derive::{Encode, Decode}; -#[cfg(feature = "std")] -use support::{Serialize, Deserialize}; use support::construct_runtime; use substrate_primitives::u32_trait::{_2, _4}; use node_primitives::{ - AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, SessionKey, Signature + AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, AuthorityId, Signature, AuthoritySignature }; use grandpa::fg_primitives::{self, ScheduledChange}; use client::{ @@ -37,7 +34,7 @@ use client::{ use runtime_primitives::{ApplyResult, generic, create_runtime_str}; use runtime_primitives::transaction_validity::TransactionValidity; use runtime_primitives::traits::{ - Convert, BlakeTwo256, Block as BlockT, DigestFor, NumberFor, StaticLookup, + BlakeTwo256, Block as BlockT, DigestFor, NumberFor, StaticLookup, }; use version::RuntimeVersion; use council::{motions as council_motions, voting as council_voting}; @@ -54,14 +51,15 @@ pub use timestamp::Call as TimestampCall; pub use balances::Call as BalancesCall; pub use runtime_primitives::{Permill, Perbill}; pub use support::StorageValue; +pub use staking::StakerStatus; /// 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: 30, - impl_version: 32, + spec_version: 48, + impl_version: 49, apis: RUNTIME_API_VERSIONS, }; @@ -101,22 +99,19 @@ impl indices::Trait for Runtime { impl balances::Trait for Runtime { type Balance = Balance; - type OnFreeBalanceZero = ((Staking, Contract), Democracy); + type OnFreeBalanceZero = ((Staking, Contract), Session); type OnNewAccount = Indices; - type EnsureAccountLiquid = (Staking, Democracy); - type Event = Event; -} - -impl fees::Trait for Runtime { type Event = Event; - type TransferAsset = Balances; + type TransactionPayment = (); + type DustRemoval = (); + type TransferPayment = (); } impl consensus::Trait for Runtime { type Log = Log; - type SessionKey = SessionKey; + type SessionKey = AuthorityId; - // the aura module handles offline-reports internally + // The Aura module handles offline-reports internally // rather than using an explicit report system. type InherentOfflineReport = (); } @@ -126,16 +121,8 @@ impl timestamp::Trait for Runtime { type OnTimestampSet = Aura; } -/// Session key conversion. -pub struct SessionKeyConversion; -impl Convert for SessionKeyConversion { - fn convert(a: AccountId) -> SessionKey { - a.to_fixed_bytes().into() - } -} - impl session::Trait for Runtime { - type ConvertAccountIdToSessionKey = SessionKeyConversion; + type ConvertAccountIdToSessionKey = (); type OnSessionChange = (Staking, grandpa::SyncedAuthorities); type Event = Event; } @@ -144,6 +131,8 @@ impl staking::Trait for Runtime { type Currency = balances::Module; type OnRewardMinted = Treasury; type Event = Event; + type Slash = (); + type Reward = (); } impl democracy::Trait for Runtime { @@ -154,6 +143,8 @@ impl democracy::Trait for Runtime { impl council::Trait for Runtime { type Event = Event; + type BadPresentation = (); + type BadReaper = (); } impl council::voting::Trait for Runtime { @@ -171,14 +162,19 @@ impl treasury::Trait for Runtime { type ApproveOrigin = council_motions::EnsureMembers<_4>; type RejectOrigin = council_motions::EnsureMembers<_2>; type Event = Event; + type MintedForSpending = (); + type ProposalRejection = (); } impl contract::Trait for Runtime { + type Currency = balances::Module; type Call = Call; type Event = Event; type Gas = u64; type DetermineContractAddress = contract::SimpleAddressDeterminator; type ComputeDispatchFee = contract::DefaultDispatchFeeComputor; + type TrieIdGenerator = contract::TrieIdFromParentCounter; + type GasPayment = (); } impl sudo::Trait for Runtime { @@ -187,13 +183,17 @@ impl sudo::Trait for Runtime { } impl grandpa::Trait for Runtime { - type SessionKey = SessionKey; + type SessionKey = AuthorityId; type Log = Log; type Event = Event; } +impl finality_tracker::Trait for Runtime { + type OnFinalizationStalled = grandpa::SyncedAuthorities; +} + construct_runtime!( - pub enum Runtime with Log(InternalLog: DigestItem) where + pub enum Runtime with Log(InternalLog: DigestItem) where Block = Block, NodeBlock = node_primitives::Block, UncheckedExtrinsic = UncheckedExtrinsic @@ -211,11 +211,11 @@ construct_runtime!( CouncilVoting: council_voting, CouncilMotions: council_motions::{Module, Call, Storage, Event, Origin}, CouncilSeats: council_seats::{Config}, + FinalityTracker: finality_tracker::{Module, Call, Inherent}, Grandpa: grandpa::{Module, Call, Storage, Config, Log(), Event}, Treasury: treasury, Contract: contract::{Module, Call, Storage, Config, Event}, Sudo: sudo, - Fees: fees::{Module, Storage, Config, Event}, } ); @@ -234,7 +234,7 @@ pub type UncheckedExtrinsic = generic::UncheckedMortalCompactExtrinsic; /// Executive: handles dispatch to the various modules. -pub type Executive = executive::Executive, Fees, AllModules>; +pub type Executive = executive::Executive, Balances, AllModules>; impl_runtime_apis! { impl client_api::Core for Runtime { @@ -242,7 +242,7 @@ impl_runtime_apis! { VERSION } - fn authorities() -> Vec { + fn authorities() -> Vec { Consensus::authorities() } @@ -289,13 +289,19 @@ impl_runtime_apis! { } } + impl offchain_primitives::OffchainWorkerApi for Runtime { + fn offchain_worker(number: NumberFor) { + Executive::offchain_worker(number) + } + } + impl fg_primitives::GrandpaApi for Runtime { fn grandpa_pending_change(digest: &DigestFor) -> Option>> { for log in digest.logs.iter().filter_map(|l| match l { Log(InternalLog::grandpa(grandpa_signal)) => Some(grandpa_signal), - _=> None + _ => None }) { if let Some(change) = Grandpa::scrape_digest_change(log) { return Some(change); @@ -304,7 +310,21 @@ impl_runtime_apis! { None } - fn grandpa_authorities() -> Vec<(SessionKey, u64)> { + fn grandpa_forced_change(digest: &DigestFor) + -> Option<(NumberFor, ScheduledChange>)> + { + for log in digest.logs.iter().filter_map(|l| match l { + Log(InternalLog::grandpa(grandpa_signal)) => Some(grandpa_signal), + _ => None + }) { + if let Some(change) = Grandpa::scrape_digest_forced_change(log) { + return Some(change); + } + } + None + } + + fn grandpa_authorities() -> Vec<(AuthorityId, u64)> { Grandpa::grandpa_authorities() } } diff --git a/node/runtime/wasm/Cargo.lock b/node/runtime/wasm/Cargo.lock index 29e7b12698abc7db3bd0718d09d02904a38bbab8..0df096147a10f5fd20e70629520bc1f58d4f7afe 100644 --- a/node/runtime/wasm/Cargo.lock +++ b/node/runtime/wasm/Cargo.lock @@ -1,5 +1,57 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[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.6.10" +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.25 (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.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-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "arrayref" version = "0.3.5" @@ -7,49 +59,102 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "arrayvec" -version = "0.4.8" +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.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "autocfg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "backtrace" -version = "0.3.9" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.2 (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.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "backtrace-sys" -version = "0.1.24" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "base-x" +version = "0.2.4" +source = "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 = "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 = "git+https://github.com/paritytech/bitmask#a84e147be602631617badd18b6b9af83391db4a9" + +[[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.8 (registry+https://github.com/rust-lang/crates.io-index)", + "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)", ] @@ -69,7 +174,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-padding 0.1.3 (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.2.7 (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)", ] @@ -81,6 +194,11 @@ 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 = "byte-tools" version = "0.2.0" @@ -93,26 +211,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "byteorder" -version = "1.2.7" +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.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "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 = "cc" -version = "1.0.29" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -122,7 +245,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -130,7 +253,7 @@ name = "clear_on_drop" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -148,46 +271,105 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "crossbeam" -version = "0.2.12" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.7 (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.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "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.6.2" +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.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.2 (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)", ] [[package]] name = "crossbeam-epoch" -version = "0.6.1" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (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.7 (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.6.2" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.7 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -209,18 +391,50 @@ dependencies = [ "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.0.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "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 0.6.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.0.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 = "digest" version = "0.6.2" @@ -237,21 +451,40 @@ dependencies = [ "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "discard" +version = "1.0.4" +source = "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.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek 1.1.3 (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.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)", ] +[[package]] +name = "either" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "elastic-array" -version = "0.10.0" +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)", @@ -259,7 +492,7 @@ dependencies = [ [[package]] name = "environmental" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -267,13 +500,28 @@ name = "error-chain" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.14 (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.14 (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.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "fake-simd" @@ -285,10 +533,10 @@ name = "fixed-hash" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "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.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (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)", ] @@ -311,6 +559,11 @@ name = "foreign-types-shared" version = "0.1.1" 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" @@ -330,6 +583,15 @@ name = "futures" version = "0.1.25" 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.25 (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 = "generic-array" version = "0.8.3" @@ -349,17 +611,30 @@ dependencies = [ [[package]] name = "hash-db" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.12.2" [[package]] name = "hash256-std-hasher" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crunchy 0.2.1 (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" @@ -368,9 +643,22 @@ dependencies = [ "winapi 0.3.6 (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.2.1 (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.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -395,6 +683,15 @@ dependencies = [ "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" @@ -417,7 +714,7 @@ 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.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -425,7 +722,7 @@ name = "impl-codec" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -434,7 +731,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.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -447,7 +744,7 @@ name = "iovec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -475,18 +772,13 @@ name = "kvdb" version = "0.1.0" source = "git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d#b0317f649ab2c665b7987b8475878fc4d2e1f81d" dependencies = [ - "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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 = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lazy_static" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -496,37 +788,356 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.48" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libsecp256k1" -version = "0.2.2" +version = "0.2.50" 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.3 (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" +name = "libp2p" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" 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)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (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.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-core-derive 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-dns 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-floodsub 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-identify 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-kad 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-mdns 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-mplex 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-noise 0.3.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-ping 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-plaintext 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-ratelimit 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-secio 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-tcp 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-uds 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-yamux 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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)", + "stdweb 0.4.15 (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.6 (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 = "log" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "libp2p-core" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "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.25 (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)", + "multistream-select 0.3.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.4.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.1 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "secp256k1 0.12.0 (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.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-timer 0.2.10 (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)", + "zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libp2p-core-derive" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libp2p-dns" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "protobuf 2.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)", + "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.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.4.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)", + "tokio-timer 0.2.10 (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)", +] + +[[package]] +name = "libp2p-kad" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-identify 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "libp2p-ping 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.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)", + "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)", + "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)", +] + +[[package]] +name = "libp2p-mdns" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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-timer 0.2.10 (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)", +] + +[[package]] +name = "libp2p-mplex" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.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-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.3.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "curve25519-dalek 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (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.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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)", + "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.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-ping" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "parking_lot 0.7.1 (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)", + "tokio-timer 0.2.10 (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-plaintext" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libp2p-ratelimit" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "aio-limited 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 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)", +] + +[[package]] +name = "libp2p-secio" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "hmac 0.7.0 (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.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.4.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.1 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "stdweb 0.4.15 (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)", +] + +[[package]] +name = "libp2p-tcp" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libp2p-yamux" +version = "0.5.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "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.1.9 (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 = "log" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -534,6 +1145,11 @@ 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" @@ -541,10 +1157,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memory-db" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.12.2" dependencies = [ - "hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", + "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)", ] @@ -555,14 +1171,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "merlin" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "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 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.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]] @@ -575,11 +1190,11 @@ dependencies = [ "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)", "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (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.1 (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)", ] @@ -591,7 +1206,7 @@ dependencies = [ "lazycell 1.2.1 (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.16 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -600,7 +1215,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.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -615,13 +1230,27 @@ dependencies = [ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "multistream-select" +version = "0.3.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -629,10 +1258,10 @@ dependencies = [ name = "node-primitives" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", "substrate-primitives 0.1.0", @@ -642,14 +1271,13 @@ dependencies = [ name = "node-runtime" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "node-primitives 0.1.0", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (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.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", "sr-version 0.1.0", @@ -660,7 +1288,7 @@ dependencies = [ "srml-council 0.1.0", "srml-democracy 0.1.0", "srml-executive 0.1.0", - "srml-fees 0.1.0", + "srml-finality-tracker 0.1.0", "srml-grandpa 0.1.0", "srml-indices 0.1.0", "srml-session 0.1.0", @@ -670,10 +1298,10 @@ dependencies = [ "srml-system 0.1.0", "srml-timestamp 0.1.0", "srml-treasury 0.1.0", - "srml-upgrade-key 0.1.0", "substrate-client 0.1.0", "substrate-consensus-aura-primitives 0.1.0", "substrate-keyring 0.1.0", + "substrate-offchain-primitives 0.1.0", "substrate-primitives 0.1.0", ] @@ -689,6 +1317,11 @@ 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 = "num-integer" version = "0.1.39" @@ -704,16 +1337,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "once_cell" -version = "0.1.6" +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" @@ -722,28 +1358,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl" -version = "0.10.16" +version = "0.10.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (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.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.40 (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.50 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "openssl-sys" -version = "0.9.40" +version = "0.9.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.6 (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" @@ -759,21 +1404,50 @@ source = "git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7 [[package]] name = "parity-codec" -version = "3.0.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "parity-codec-derive" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-crate 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parity-multiaddr" +version = "0.2.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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)", + "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", + "serde 1.0.89 (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-multihash" +version = "0.1.0" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +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)", + "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.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]] @@ -781,7 +1455,16 @@ name = "parity-wasm" version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "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]] @@ -802,15 +1485,26 @@ dependencies = [ "parking_lot_core 0.4.0 (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.50 (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.6 (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.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (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.7 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -819,10 +1513,10 @@ name = "parking_lot_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (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.7 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -841,9 +1535,19 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-hack 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (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]] @@ -888,9 +1592,9 @@ name = "proc-macro-hack" version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -900,145 +1604,244 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "0.4.24" +version = "0.4.27" 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.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "pwasm-utils" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "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.10" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.4.3" +version = "0.3.23" 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)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (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.50 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.5.5" +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-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.2.2 (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.50 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.6.1" +version = "0.6.5" 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-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (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_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.3 (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.6 (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.2 (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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.50 (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.6 (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.50 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rand_chacha" -version = "0.1.0" +name = "rand_pcg" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.2 (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_core" -version = "0.2.2" +name = "rand_xorshift" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.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 = "rand_core" -version = "0.3.0" +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.1 (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 = "rand_hc" -version = "0.1.0" +name = "rayon-core" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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.50 (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 = "rand_isaac" -version = "0.1.1" +name = "rdrand" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.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 = "rand_pcg" -version = "0.1.1" +name = "redox_syscall" +version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.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 = "rand_xorshift" -version = "0.1.0" +name = "regex" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.6.10 (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.5 (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 = "redox_syscall" -version = "0.1.43" +name = "regex-syntax" +version = "0.6.5" 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.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.30 (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.50 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-demangle" -version = "0.1.9" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1054,6 +1857,16 @@ dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rw-stream-sink" +version = "0.1.1" +source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#e8e6ccec7409aa19939230d6720035e3ed28dfd6" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (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.7" @@ -1070,15 +1883,33 @@ dependencies = [ [[package]] name = "schnorrkel" version = "0.0.0" +source = "git+https://github.com/w3f/schnorrkel#3179838da9dd4896c12bb910e7c42477a3250641" +dependencies = [ + "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek 1.1.3 (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.0.3 (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.1 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "schnorrkel" +version = "0.1.0" 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.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek 1.1.3 (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.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "merlin 1.0.3 (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.1 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1088,6 +1919,16 @@ name = "scopeguard" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "secp256k1" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "semver" version = "0.9.0" @@ -1103,27 +1944,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.81" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.81" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.33" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1168,7 +2009,7 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1192,27 +2033,41 @@ 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)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (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.0.1" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "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.7" +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 = [ - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1226,19 +2081,19 @@ version = "0.1.0" dependencies = [ "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-crate 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "sr-io" version = "0.1.0" dependencies = [ - "environmental 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "environmental 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (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 0.1.0", "substrate-primitives 0.1.0", @@ -1254,10 +2109,9 @@ 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.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-std 0.1.0", "substrate-primitives 0.1.0", @@ -1267,7 +2121,7 @@ dependencies = [ name = "sr-sandbox" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (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 0.1.0", "substrate-primitives 0.1.0", @@ -1286,10 +2140,9 @@ name = "sr-version" version = "0.1.0" dependencies = [ "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", ] @@ -1298,12 +2151,12 @@ dependencies = [ name = "srml-aura" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", + "srml-session 0.1.0", "srml-staking 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", @@ -1315,11 +2168,10 @@ dependencies = [ name = "srml-balances" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.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.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", "srml-support 0.1.0", @@ -1331,11 +2183,10 @@ dependencies = [ name = "srml-consensus" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", "srml-support 0.1.0", @@ -1348,18 +2199,15 @@ dependencies = [ name = "srml-contract" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (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.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (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.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-sandbox 0.1.0", "sr-std 0.1.0", - "srml-balances 0.1.0", - "srml-fees 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", "srml-timestamp 0.1.0", @@ -1370,10 +2218,10 @@ dependencies = [ name = "srml-council" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.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.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", @@ -1387,12 +2235,11 @@ dependencies = [ name = "srml-democracy" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.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.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", @@ -1404,8 +2251,8 @@ dependencies = [ name = "srml-executive" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", @@ -1414,31 +2261,31 @@ dependencies = [ ] [[package]] -name = "srml-fees" +name = "srml-finality-tracker" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 0.1.0", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", - "substrate-primitives 0.1.0", + "substrate-inherents 0.1.0", ] [[package]] name = "srml-grandpa" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", + "srml-consensus 0.1.0", + "srml-finality-tracker 0.1.0", "srml-session 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", @@ -1450,11 +2297,11 @@ dependencies = [ name = "srml-indices" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.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.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", @@ -1468,10 +2315,9 @@ dependencies = [ name = "srml-metadata" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 0.1.0", "substrate-primitives 0.1.0", ] @@ -1480,11 +2326,11 @@ dependencies = [ name = "srml-session" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.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.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", "srml-consensus 0.1.0", @@ -1497,11 +2343,11 @@ dependencies = [ name = "srml-staking" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.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.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", "srml-consensus 0.1.0", @@ -1515,10 +2361,10 @@ dependencies = [ name = "srml-sudo" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", "srml-support 0.1.0", @@ -1530,13 +2376,13 @@ dependencies = [ name = "srml-support" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitmask 0.5.0 (git+https://github.com/paritytech/bitmask)", + "hex-literal 0.1.3 (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.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "paste 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", @@ -1549,11 +2395,11 @@ dependencies = [ name = "srml-support-procedural" version = "0.1.0" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "sr-api-macros 0.1.0", "srml-support-procedural-tools 0.1.0", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1561,31 +2407,30 @@ name = "srml-support-procedural-tools" version = "0.1.0" dependencies = [ "proc-macro-crate 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "srml-support-procedural-tools-derive 0.1.0", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "srml-support-procedural-tools-derive" version = "0.1.0" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "srml-system" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.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.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", @@ -1597,13 +2442,11 @@ dependencies = [ name = "srml-timestamp" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", - "srml-consensus 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", "substrate-inherents 0.1.0", @@ -1613,11 +2456,10 @@ dependencies = [ name = "srml-treasury" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", "srml-balances 0.1.0", @@ -1625,19 +2467,6 @@ dependencies = [ "srml-system 0.1.0", ] -[[package]] -name = "srml-upgrade-key" -version = "0.1.0" -dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 0.1.0", - "sr-std 0.1.0", - "srml-consensus 0.1.0", - "srml-support 0.1.0", - "srml-system 0.1.0", -] - [[package]] name = "stable_deref_trait" version = "1.1.1" @@ -1648,6 +2477,90 @@ 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 = "stdweb" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "stdweb-derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "stdweb-internal-macros 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "stdweb-internal-runtime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base-x 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.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.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "substrate-bip39" +version = "0.2.0" +source = "git+https://github.com/paritytech/substrate-bip39#a28806512c977992af8d6740d45352f5a1c832a0" +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.0.0 (git+https://github.com/w3f/schnorrkel)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "substrate-client" version = "0.1.0" @@ -1655,13 +2568,12 @@ dependencies = [ "error-chain 0.12.0 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-api-macros 0.1.0", "sr-primitives 0.1.0", @@ -1673,7 +2585,7 @@ dependencies = [ "substrate-keyring 0.1.0", "substrate-primitives 0.1.0", "substrate-state-machine 0.1.0", - "substrate-telemetry 0.3.0", + "substrate-telemetry 0.3.1", "substrate-trie 0.4.0", ] @@ -1688,32 +2600,33 @@ dependencies = [ name = "substrate-consensus-common" version = "0.1.0" dependencies = [ - "crossbeam-channel 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-version 0.1.0", "substrate-inherents 0.1.0", "substrate-primitives 0.1.0", - "tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "substrate-executor" version = "0.1.0" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-version 0.1.0", "substrate-panic-handler 0.1.0", @@ -1729,8 +2642,7 @@ dependencies = [ name = "substrate-finality-grandpa-primitives" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", "substrate-client 0.1.0", @@ -1741,8 +2653,7 @@ dependencies = [ name = "substrate-inherents" version = "0.1.0" dependencies = [ - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", @@ -1752,16 +2663,26 @@ dependencies = [ name = "substrate-keyring" version = "0.1.0" dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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 0.1.0", ] +[[package]] +name = "substrate-offchain-primitives" +version = "0.1.0" +dependencies = [ + "sr-primitives 0.1.0", + "substrate-client 0.1.0", +] + [[package]] name = "substrate-panic-handler" version = "0.1.0" dependencies = [ - "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1771,22 +2692,25 @@ version = "0.1.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.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hash256-std-hasher 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", + "hash256-std-hasher 0.12.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.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "primitive-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.14.5 (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.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.14.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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "schnorrkel 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 0.1.0", + "substrate-bip39 0.2.0 (git+https://github.com/paritytech/substrate-bip39)", + "tiny-bip39 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "twox-hash 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmi 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1796,38 +2720,41 @@ dependencies = [ name = "substrate-serializer" version = "0.1.0" dependencies = [ - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (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 = "0.1.0" dependencies = [ - "hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 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)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-panic-handler 0.1.0", "substrate-primitives 0.1.0", "substrate-trie 0.4.0", - "trie-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-root 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-db 0.12.2", + "trie-root 0.12.2", ] [[package]] name = "substrate-telemetry" -version = "0.3.0" +version = "0.3.1" dependencies = [ - "lazy_static 1.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)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (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.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "slog-async 2.3.0 (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.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slog-scope 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ws 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1835,13 +2762,19 @@ dependencies = [ name = "substrate-trie" version = "0.4.0" dependencies = [ - "hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memory-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-root 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", + "memory-db 0.12.2", + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-std 0.1.0", + "trie-db 0.12.2", + "trie-root 0.12.2", ] +[[package]] +name = "subtle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "subtle" version = "2.0.0" @@ -1849,11 +2782,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "0.15.22" +version = "0.15.29" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1867,19 +2811,33 @@ name = "thread_local" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.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)", ] [[package]] name = "time" -version = "0.1.40" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tiny-bip39" +version = "0.6.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)", + "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" @@ -1888,26 +2846,38 @@ 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.25 (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.16 (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.13" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (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.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-fs 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-current-thread 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (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.3 (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.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.10 (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.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1915,101 +2885,125 @@ name = "tokio-codec" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (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.4" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (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.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-executor" -version = "0.1.5" +version = "0.1.6" 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.25 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-fs" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.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-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-io" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (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.25 (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.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.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)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (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.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-sync 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-sync" +version = "0.1.3" +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.25 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-tcp" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (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.25 (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.16 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 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-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-threadpool" -version = "0.1.9" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-deque 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "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.25 (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.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-timer" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2017,30 +3011,30 @@ name = "tokio-udp" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (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.25 (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.16 (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.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 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-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-uds" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (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.25 (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.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (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.16 (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.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 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-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2048,26 +3042,35 @@ name = "toml" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "trie-db" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.12.2" dependencies = [ - "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.12.2", + "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.1 (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.11.0" +version = "0.12.2" +dependencies = [ + "hash-db 0.12.2", +] + +[[package]] +name = "twofish" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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]] @@ -2075,7 +3078,7 @@ name = "twox-hash" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2083,12 +3086,17 @@ 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.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "crunchy 0.2.1 (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)", @@ -2104,7 +3112,15 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.7" +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.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2113,11 +3129,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "unreachable" -version = "1.0.0" +name = "unsigned-varint" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "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]] @@ -2135,6 +3152,11 @@ dependencies = [ "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 = "vcpkg" version = "0.2.6" @@ -2150,7 +3172,7 @@ name = "wasmi" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "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)", ] @@ -2189,16 +3211,16 @@ name = "ws" version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.11 (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)", "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)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.10.19 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2211,59 +3233,132 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "x25519-dalek" +version = "0.5.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.3 (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.1.9" +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.25 (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" + +[[patch.unused]] +name = "hash256-std-hasher" +version = "0.12.2" + +[[patch.unused]] +name = "trie-bench" +version = "0.12.2" + [metadata] +"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.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5" +"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.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f405cc4c21cd8b784f6c8fc2adf9bc00f59558f0049b5ec21517f875963040cc" -"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" -"checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0" +"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 autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" +"checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4" +"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" +"checksum base-x 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d55aa264e822dbafa12db4d54767aff17c6ba55ea2d8559b3e17392c7d000e5d" "checksum base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" +"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 (git+https://github.com/paritytech/bitmask)" = "" +"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.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" +"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" "checksum block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d75255892aeb580d3c566f213a2b6fdc1c66667839f45719ee1d30ebf2aea591" +"checksum bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0de79cfb98e7aa9988188784d8664b4b5dad6eaaa0863b91d9a4ed871d4f7a42" "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 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" -"checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" -"checksum cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "4390a3b5f4f6bce9c1d0c00128379df433e53777fdd30e92f16a529332baec4e" -"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" +"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 cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)" = "d01c69d08ff207f231f07196e30f84c70f1c815b04f980f8b7b01ff01f05eb92" +"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" "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 crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bd66663db5a988098a89599d4857919b3acf7f61402e61365acfd3919857b9be" -"checksum crossbeam-channel 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8d4f5844607ce8da3fff431e7dba56cda8bfcc570aa50bee36adba8a32b8cad7" -"checksum crossbeam-deque 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fe1b6f945f824c7a25afe44f62e25d714c0cc523f8e99d8db5cd1026e1269d3" -"checksum crossbeam-epoch 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2449aaa4ec7ef96e5fb24db16024b935df718e9ae1cec0a1e68feeca2efca7b8" -"checksum crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e07fc155212827475223f0bcfae57e945e694fc90950ddf3f6695bbfd5555c72" +"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.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c240f247c278fa08a6d4820a6a222bfc6e0d999e51ba67be94f44c905b2161f2" "checksum crypto-mac 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "779015233ac67d65098614aec748ac1c756ab6677fa2e14cf8b37c08dfed1198" -"checksum curve25519-dalek 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dae47cc3529cdab597dbc8b606e565707209b506e55848f3c15679214a56c956" +"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.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e1f8a6fc0376eb52dc18af94915cc04dfdf8353746c0e8c550ae683a0815e5c1" +"checksum data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f47ca1860a761136924ddd2422ba77b2ea54fe8cc75b9040804a0d9d32ad97" "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 discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" +"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 elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "88d4851b005ef16de812ea9acdb7bece2f0a40dd86c07b85631d7dafa54537bb" -"checksum environmental 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db746025e3ea695bfa0ae744dbacd5fcfc8db51b9760cf8bd0ab69708bb93c49" +"checksum either 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c67353c641dc847124ea1902d69bd753dee9bb3beff9aa3662ecf86c971d1fac" +"checksum elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "073be79b6538296faf81c631872676600616073817dd9a440c477ad09b408983" +"checksum environmental 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c7464757b80de8930c91c9afe77ddce501826bf9d134a87db2c67d9dc177e2c" "checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" "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.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a557e80084b05c32b455963ff565a9de6f2866da023d6671705c6aff6f65e01c" "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 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.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" +"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "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 hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b03501f6e1a2a97f1618879aba3156f14ca2847faa530c4e28859638bd11483" -"checksum hash256-std-hasher 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5c13dbac3cc50684760f54af18545c9e80fb75e93a3e586d71ebdc13138f6a4" +"checksum hash256-std-hasher 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1224388a21c88a80ae7087a2a245ca6d80acc97a9186b75789fb3eeefd0609af" +"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 hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4da5f0e01bd8a71a224a4eedecaacfcabda388dbb7a80faf04d3514287572d95" +"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.3 (registry+https://github.com/rust-lang/crates.io-index)" = "27455ce8b4a6666c87220e4b59c9a83995476bdadc10197905e61dbe906e36fa" "checksum hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1d340b6514f232f6db1bd16db65302a5278a04fef9ce867cb932e7e5fa21130a" "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 httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" @@ -2275,42 +3370,66 @@ dependencies = [ "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 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" +"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.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" +"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1" +"checksum libp2p 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-core-derive 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-dns 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-floodsub 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-identify 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-kad 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-mdns 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-mplex 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-noise 0.3.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-ping 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-plaintext 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-ratelimit 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-secio 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-tcp 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-uds 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum libp2p-yamux 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" "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 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.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94da53143d45f6bad3753f532e56ad57a6a26c0ca6881794583310c7cb4c885f" "checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" -"checksum merlin 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a9e97b439f6d38cbe2a4a4aa93f6770c5305f62761b78b1851406c09c87ee2a" +"checksum merlin 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "83c2dda19c01176e8e7148f7bdb88bbdf215a8db0641f89fc40e4b81736aeda5" "checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432" "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" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +"checksum multistream-select 0.3.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" "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 num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" -"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -"checksum once_cell 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d7ce3535d54560c937c1652ba4a0da66bfc63e0f8e07bed127483afb6e5ee925" +"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" +"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 openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ec7bd7ca4cce6dbdc77e7c1230682740d307d1218a87fb0349a571272be749f9" -"checksum openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)" = "1bb974e77de925ef426b6bc82fce15fd45bdcbeb5728bffcfc7cdeeb7ce1c2d6" +"checksum openssl 0.10.19 (registry+https://github.com/rust-lang/crates.io-index)" = "84321fb9004c3bce5611188a644d6171f895fa2889d155927d528782edb21c5d" +"checksum openssl-sys 0.9.42 (registry+https://github.com/rust-lang/crates.io-index)" = "cb534d752bf98cf363b473950659ac2546517f9c6be9723771614ab3f03bbc9e" +"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.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "88f69984317b736dceac3baa86600fc089856f69b44b07231f39b5648b02bcd4" -"checksum parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a58ba33211595f92cc2163ac583961d3dc767e656934146636b05256cc9acd7f" +"checksum parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "21c9c3a1623c71ed83964ff28cac6126e178920f7646d32c337eacb9152b2907" +"checksum parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "864e9f66b58c0b38f0d6b511b6576afa2b678ae801b64220553bced57ac12df9" +"checksum parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" +"checksum parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" "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_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 paste 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f50392d1265092fbee9273414cc40eb6d47d307bd66222c477bb8450c8504f9d" "checksum paste-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a3cd512fe3a55e8933b2dcad913e365639db86d512e4004c3084b86864d9467a" +"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 pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" "checksum primitive-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edb92f1ebfc177432c03287b15d48c202e6e2c95993a7af3ba039abb43b1492e" @@ -2318,76 +3437,108 @@ dependencies = [ "checksum proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c725b36c99df7af7bf9324e9c999b9e37d92c8f8caf106d82e1d7953218d2d8" "checksum proc-macro-hack 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3e90aa19cd73dedc2d0e1e8407473f073d735fef0ab521438de6da8ee449ab66" "checksum proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b753ad9ed99dd8efeaa7d2fb8453c8f6bc3e54b97966d35f1bc77ca6865254a" -"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09" -"checksum pwasm-utils 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e9135bed7b452e20dbb395a2d519abaf0c46d60e7ecc02daeeab447d29bada1" -"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c" -"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" -"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" -"checksum rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae9d223d52ae411a33cf7e54ec6034ec165df296ccd23533d671a28252b6f66a" -"checksum rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "771b009e3a508cb67e8823dda454aaa5368c7bc1c16829fb77d3e980440dd34a" -"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372" -"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db" +"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" +"checksum protobuf 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24d5d73d2b88fddb8b8141f2730d950d88772c940ac4f8f3e93230b9a99d92df" +"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.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" +"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_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05" -"checksum rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effa3fcaa47e18db002bdde6060944b6d2f9cfd8db471c30e873448ad9187be3" -"checksum redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "679da7508e9a6390aeaf7fbd02a800fdc64b73fe2204dd2c8ae66d22d9d5ad5d" -"checksum ring 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)" = "148fc853f6d85f53f5f315d46701eaacc565cdfb3cb1959730c96e81e7e49999" -"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" +"checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832" +"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.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" +"checksum regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53ee8cfdddb2e0291adfb9f13d31d3bbe0a03c9a402c01b1e24188d86c35b24f" +"checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861" +"checksum ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)" = "426bc186e3e95cac1e4a4be125a4aca7e84c2d616ffc02244eef36e2a60a093c" +"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" "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 rw-stream-sink 0.1.1 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" "checksum safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7bf422d23a88c16d5090d455f182bc99c60af4df6a345c63428acf5129e347" -"checksum schnorrkel 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe554f318830b48e5da8ab1ccb1ffd02b79228364dac7766b7cd1ec461ca5116" +"checksum schnorrkel 0.0.0 (git+https://github.com/w3f/schnorrkel)" = "" +"checksum schnorrkel 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a700659388785588c75b197cecda0f23c7112a9281ef703e8ffc651061ce014c" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" +"checksum secp256k1 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4070f3906e65249228094cf97b04a90799fba04468190bbbcfa812309cf86e32" "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.81 (registry+https://github.com/rust-lang/crates.io-index)" = "c91eb5b0190ae87b4e2e39cbba6e3bed3ac6186935fe265f0426156c4c49961b" -"checksum serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)" = "477b13b646f5b5b56fc95bedfc3b550d12141ce84f466f6c44b9a17589923885" -"checksum serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "c37ccd6be3ed1fdf419ee848f7c758eb31b054d7cd3ae3600e3bae0adf569811" +"checksum serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "92514fb95f900c9b5126e32d020f5c6d40564c27a5ea6d1d7d9f157a96623560" +"checksum serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6eabf4b5914e88e24eea240bb7c9f9a2cbc1bbbe8d961d381975ec3c6b806c" +"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" "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.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34a5e54083ce2b934bf059fdf38e7330a154177e029ab6c4e18638f2f624053a" -"checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" +"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-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e544d16c6b230d84c866662fe55e31aacfca6ae71e6fc49ae9a311cb379bfc2f" "checksum slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddc0d2aff1f8f325ef660d9a0eb6e6dcd20b30b3f581a5897f58bf42d061c37a" -"checksum slog-scope 4.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "053344c94c0e2b22da6305efddb698d7c485809427cf40555dc936085f67a9df" -"checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db" +"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 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 stdweb 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a3edad410e603184d656e2abded5fd4d3d6e93d5763d21130dbaf99795db74eb" +"checksum stdweb-derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e21ebd9179de08f2300a65454268a17ea3de204627458588c84319c4def3930" +"checksum stdweb-internal-macros 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1635afd059cbfac7d5b1274f0c44cec110c1e013c48e8bbc22e07e52696cf887" +"checksum stdweb-internal-runtime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a2a2f4a2eb556337b2d1a302630bbddf989ae383c70393e89b48152b9896cbda" +"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.0 (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.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "702662512f3ddeb74a64ce2fbbf3707ee1b6bb663d28bb054e0779bbc720d926" -"checksum syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)" = "ae8b29eb5210bc5cf63ed6149cbf9adfc82ac0be023d8735c176ee74a2db4da7" +"checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2" +"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" +"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum tiny-bip39 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a1415431cb2398d84da64173f8473c792808314427d4a6f2f3ea85ae67239fe3" "checksum tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e9175261fbdb60781fcd388a4d6cc7e14764a2b629a7ad94abb439aed223a44f" -"checksum tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "a7817d4c98cc5be21360b3b37d6036fe9b7aefa5b7a201b7b16ff33423822f7d" +"checksum tk-listen 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5462b0f968c0457efe38fcd2df7e487096b992419e4f5337b06775a614bbda4b" +"checksum tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fcaabb3cec70485d0df6e9454fe514393ad1c4070dee8915f11041e95630b230" "checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" -"checksum tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "331c8acc267855ec06eb0c94618dcbbfea45bed2d20b77252940095273fb58f6" -"checksum tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c117b6cf86bb730aab4834f10df96e4dd586eff2c3c27d3781348da49e255bde" -"checksum tokio-fs 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "60ae25f6b17d25116d2cba342083abe5255d3c2c79cb21ea11aa049c53bf7c75" -"checksum tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "7392fe0a70d5ce0c882c4778116c519bd5dbaa8a7c3ae3d04578b3afafdcda21" -"checksum tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "502b625acb4ee13cbb3b90b8ca80e0addd263ddacf6931666ef751e610b07fb5" -"checksum tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7ad235e9dadd126b2d47f6736f65aa1fdcd6420e66ca63f44177bc78df89f912" -"checksum tokio-threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "56c5556262383032878afad66943926a1d1f0967f17e94bd7764ceceb3b70e7f" -"checksum tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4f37f0111d76cc5da132fe9bc0590b9b9cfd079bc7e75ac3846278430a299ff8" +"checksum tokio-current-thread 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c756b04680eea21902a46fca4e9f410a2332c04995af590e07ff262e2193a9a3" +"checksum tokio-dns-unofficial 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82c65483db54eb91b4ef3a9389a3364558590faf30ce473141707c0e16fda975" +"checksum tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30c6dbf2d1ad1de300b393910e8a3aa272b724a400b6531da03eed99e329fbf0" +"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-sync 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1bf2b9dac2a0509b5cfd1df5aa25eafacb616a42a491a13604d6bbeab4486363" +"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" +"checksum tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "742e511f6ce2298aeb86fc9ea0d8df81c2388c6ebae3dc8a7316e8c9df0df801" +"checksum tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2910970404ba6fa78c5539126a9ae2045d62e3713041e447f695f41405a120c6" "checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92" -"checksum tokio-uds 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "99ce87382f6c1a24b513a72c048b2c8efe66cb5161c9061d00bee510f08dc168" +"checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" -"checksum trie-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7319e28ca295f27359d944a682f7f65b419158bf1590c92cadc0000258d788" -"checksum trie-root 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3c6fef2705af3258ec46a7e22286090394a44216201a1cf7d04b78db825e543" +"checksum twofish 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d261e83e727c8e2dbb75dacac67c36e35db36a958ee504f2164fc052434e1" "checksum twox-hash 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "555cd4909480122bbbf21e34faac4cb08a171f324775670447ed116726c474af" "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.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e7780bb27fd8a22295e0d9d53ae3be253f715a0dccb1808527f478f1c2603708" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" +"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" +"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +"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 vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum wasmi 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21ef487a11df1ed468cf613c78798c26282da5c30e9d49f824872d4c77b47d1d" @@ -2398,3 +3549,6 @@ dependencies = [ "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum ws 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "329d3e6dd450a9c5c73024e1047f0be7e24121a68484eb0b5368977bee3cf8c3" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +"checksum x25519-dalek 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4aca1ba6bec2719576bd20dfe5b24d9359552e616d10bff257e50cd85f745d17" +"checksum yamux 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "302defd1bed8a9a6d43b82f0e5a50510dfdfbbd02c270c93ff9d6f3f5e2dea89" +"checksum zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8ddfeb6eee2fb3b262ef6e0898a52b7563bb8e0d5955a313b3cf2f808246ea14" diff --git a/node/runtime/wasm/Cargo.toml b/node/runtime/wasm/Cargo.toml index 3512971a44d43e3e40a460c12a5cd00f430d789c..04a51c1d0ee726a0164e804e34383f8923f07358 100644 --- a/node/runtime/wasm/Cargo.toml +++ b/node/runtime/wasm/Cargo.toml @@ -23,3 +23,11 @@ lto = true [workspace] members = [] + +[patch.crates-io] +trie-db = { path = "../../../../parity-trie/trie-db" } +trie-root = { path = "../../../../parity-trie/trie-root" } +hash-db = { path = "../../../../parity-trie/hash-db" } +memory-db = { path = "../../../../parity-trie/memory-db" } +trie-bench = { path = "../../../../parity-trie/test-support/trie-bench" } +hash256-std-hasher = { path = "../../../../parity-trie/hash256-std-hasher" } diff --git a/node/runtime/wasm/src/lib.rs b/node/runtime/wasm/src/lib.rs index 7364f0a4db0c44b381dff03a094f2118e4a87511..a87b3f7c79dbd94a34a14537822b8c94fc67fab7 100644 --- a/node/runtime/wasm/src/lib.rs +++ b/node/runtime/wasm/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm b/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm index 65ff842ce4b41e591d290f69e6cc772f69fdf9fa..58a75988f3221b4d94a71f99b648d64e9a31ea3f 100644 Binary files a/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm and b/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm differ diff --git a/node/src/main.rs b/node/src/main.rs index 2df55bb852fdafa8b7d8236abcef6ba4fcf1f738..5ff0d7ff3b0e68fae90eca12154bd1409d866d80 100644 --- a/node/src/main.rs +++ b/node/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/scripts/gitlab/check_merge_conflict.sh b/scripts/gitlab/check_merge_conflict.sh index 29ed6906328c35ca169f2d6b83bf7c53e9bb40fb..dd677ff7620d1d8ee467ba65bb9db67e8aed2918 100755 --- a/scripts/gitlab/check_merge_conflict.sh +++ b/scripts/gitlab/check_merge_conflict.sh @@ -45,6 +45,11 @@ EOT test "${mergeable}" = "true" && echo "| yes, it is." && exit 0 +if [ "${baseref}" = "null" -o "${baserepo}" = "null" ] +then + echo "| either connectivity issues with github or pull request not existant" + exit 3 +fi cat <<-EOT | not mergeable @@ -94,7 +99,6 @@ curl -sS -X POST \ -F "token=${CI_JOB_TOKEN}" \ -F "ref=master" \ -F "variables[REBUILD_WASM]=\"${baserepo}:${baseref}\"" \ - -F "variables[PRNO]=${CI_COMMIT_REF_NAME}" \ ${GITLAB_API}/projects/${GITHUB_API_PROJECT}/trigger/pipeline \ | jq -r .web_url diff --git a/scripts/gitlab/check_runtime.sh b/scripts/gitlab/check_runtime.sh index 323e38fd19d3991a7f45662e1b61da5701a6ceac..61068e7eb8885d18ebaafd4511be1efcb48d45d0 100755 --- a/scripts/gitlab/check_runtime.sh +++ b/scripts/gitlab/check_runtime.sh @@ -1,9 +1,9 @@ #!/bin/sh -# -# -# check for any changes in the node/src/runtime, srml/ and core/sr_* trees. if -# there are any changes found, it should mark the PR breaksconsensus and -# "auto-fail" the PR in some way unless a) the runtime is rebuilt and b) there +# +# +# check for any changes in the node/src/runtime, srml/ and core/sr_* trees. if +# there are any changes found, it should mark the PR breaksconsensus and +# "auto-fail" the PR in some way unless a) the runtime is rebuilt and b) there # isn't a change in the runtime/src/lib.rs file that alters the version. set -e # fail on any error @@ -66,14 +66,14 @@ then then cat <<-EOT - changes to the runtime sources and changes in the spec version. Wasm + changes to the runtime sources and changes in the spec version. Wasm binary blob is rebuilt. Looks good. spec_version: ${sub_spec_version} -> ${add_spec_version} EOT exit 0 - else + else cat <<-EOT changes to the runtime sources and changes in the spec version. Wasm @@ -122,6 +122,11 @@ else versions file: ${VERSIONS_FILE} + note: if the master branch was merged in as automated wasm rebuilds do it + might be the case that a {spec,impl}_version has been changed. but for pull + requests that involve wasm source file changes a version has to be changed + in the pull request itself. + EOT # drop through into pushing `gotissues` and exit 1... diff --git a/scripts/kubernetes/Chart.yaml b/scripts/kubernetes/Chart.yaml new file mode 100644 index 0000000000000000000000000000000000000000..8e000ae09f1c1ff77028ad561b752b407d06e993 --- /dev/null +++ b/scripts/kubernetes/Chart.yaml @@ -0,0 +1,12 @@ +name: substrate +version: 0.2 +appVersion: 0.9.1 +description: "Substrate: The platform for blockchain innovators" +home: https://substrate.network/ +icon: https://substrate.network/favicon.ico +sources: + - https://github.com/paritytech/substrate/ +maintainers: + - name: Paritytech Devops Team + email: devops-team@parity.io +tillerVersion: ">=2.8.0" diff --git a/scripts/kubernetes/README.md b/scripts/kubernetes/README.md new file mode 100644 index 0000000000000000000000000000000000000000..0f3ec38990375bc9c76ae67f6ce144805957a7ab --- /dev/null +++ b/scripts/kubernetes/README.md @@ -0,0 +1,47 @@ + + +# Substrate Kubernetes Helm Chart + +This [Helm Chart](https://helm.sh/) can be used for deploying containerized +**Substrate** to a [Kubernetes](https://kubernetes.io/) cluster. + + +## Prerequisites + +- Tested on Kubernetes 1.10.7-gke.6 + +## Installation + +To install the chart with the release name `my-release` into namespace +`my-namespace` from within this directory: + +```console +$ helm install --namespace my-namespace --name my-release --values values.yaml ./ +``` + +The command deploys Substrate on the Kubernetes cluster in the configuration +given in `values.yaml`. When the namespace is omitted it'll be installed in +the default one. + + +## Removal of the Chart + +To uninstall/delete the `my-release` deployment: + +```console +$ helm delete --namespace my-namespace my-release +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + + +## Upgrading + +Once the chart is installed and a new version should be deployed helm takes +care of this by + +```console +$ helm upgrade --namespace my-namespace --values values.yaml my-release ./ +``` + + diff --git a/scripts/kubernetes/templates/poddisruptionbudget.yaml b/scripts/kubernetes/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000000000000000000000000000000000000..56958b1fbafd963896eeab25059380bb4e9547e2 --- /dev/null +++ b/scripts/kubernetes/templates/poddisruptionbudget.yaml @@ -0,0 +1,10 @@ +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ .Values.GitlabEnvSlug | default .Values.app }} +spec: + selector: + matchLabels: + app: {{ .Values.GitlabEnvSlug | default .Values.app }} + maxUnavailable: 1 + diff --git a/scripts/kubernetes/templates/secrets.yaml b/scripts/kubernetes/templates/secrets.yaml new file mode 100644 index 0000000000000000000000000000000000000000..97e73ae7ff03805c1bde9d7deb894eb94948f28b --- /dev/null +++ b/scripts/kubernetes/templates/secrets.yaml @@ -0,0 +1,11 @@ +{{- if .Values.validator.keys }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.app }}-secrets + labels: + app: {{ .Values.GitlabEnvSlug | default .Values.app }} +type: Opaque +data: + secrets: {{ .Values.validator.keys | default "" }} +{{- end }} diff --git a/scripts/kubernetes/templates/service.yaml b/scripts/kubernetes/templates/service.yaml new file mode 100644 index 0000000000000000000000000000000000000000..01ba9d5a567c57045b585aa7e1fa894d404cbf90 --- /dev/null +++ b/scripts/kubernetes/templates/service.yaml @@ -0,0 +1,54 @@ +# see: +# https://kubernetes.io/docs/tutorials/services/ +# https://kubernetes.io/docs/concepts/services-networking/service/ +# headless service for rpc +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app }}-rpc +spec: + ports: + - port: 9933 + name: http-rpc + - port: 9944 + name: websocket-rpc + selector: + app: {{ .Values.GitlabEnvSlug | default .Values.app }} + sessionAffinity: None + type: ClusterIP + clusterIP: None +--- +{{- if .Values.listen_node_port }} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app }} +spec: + ports: + - port: 30333 + name: p2p + nodePort: 30333 + protocol: TCP + selector: + app: {{ .Values.GitlabEnvSlug | default .Values.app }} + sessionAffinity: None + type: NodePort + # don't route exteral traffic to non-local pods + externalTrafficPolicy: Local +{{- else if .Values.validator.keys }} +{{- $root := . -}} +{{- range until (int .Values.nodes.replicas) }} +--- +kind: Service +apiVersion: v1 +metadata: + name: {{ $root.Values.app }}-{{ . }} +spec: + selector: + statefulset.kubernetes.io/pod-name: {{ $root.Values.app }}-{{ . }} + ports: + - port: 30333 + targetPort: 30333 + protocol: TCP +{{- end }} +{{- end }} diff --git a/scripts/kubernetes/templates/serviceaccount.yaml b/scripts/kubernetes/templates/serviceaccount.yaml new file mode 100644 index 0000000000000000000000000000000000000000..53d016bffedf988fad2fcd71c316f565bee683a7 --- /dev/null +++ b/scripts/kubernetes/templates/serviceaccount.yaml @@ -0,0 +1,10 @@ +{{- if .Values.rbac.enable }} +# service account for substrate pods themselves +# no permissions for the api are required +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app: {{ .Values.GitlabEnvSlug | default .Values.app }} + name: {{ .Values.rbac.name }} +{{- end }} diff --git a/scripts/kubernetes/templates/statefulset.yaml b/scripts/kubernetes/templates/statefulset.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0f34b3507a1d17e49334bca86792ac2964a6a618 --- /dev/null +++ b/scripts/kubernetes/templates/statefulset.yaml @@ -0,0 +1,139 @@ +# https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/ +# https://cloud.google.com/kubernetes-engine/docs/concepts/statefulset +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ .Values.app }} +spec: + selector: + matchLabels: + app: {{ .Values.GitlabEnvSlug | default .Values.app }} + serviceName: {{ .Values.app }} + replicas: {{ .Values.nodes.replicas }} + updateStrategy: + type: RollingUpdate + podManagementPolicy: Parallel + template: + metadata: + labels: + app: {{ .Values.GitlabEnvSlug | default .Values.app }} + spec: + {{- if .Values.rbac.enable }} + serviceAccountName: {{ .Values.rbac.name }} + {{- else }} + serviceAccountName: default + {{- end }} + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: node + operator: In + values: + - substrate + {{- if .Values.listen_node_port }} + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: "app" + operator: In + values: + - {{ .Values.app }} + topologyKey: "kubernetes.io/hostname" + {{- end }} + terminationGracePeriodSeconds: 300 + {{- if .Values.validator.keys }} + volumes: + - name: {{ .Values.app }}-validator-secrets + secret: + secretName: {{ .Values.app }}-secrets + initContainers: + - name: prepare-secrets + image: busybox + command: [ "/bin/sh" ] + args: + - -c + - sed -n -r "s/^${POD_NAME}-key ([^ ]+)$/\1/p" /etc/validator/secrets > {{ .Values.image.basepath }}/key; + sed -n -r "s/^${POD_NAME}-node-key ([^ ]+)$/\1/p" /etc/validator/secrets > {{ .Values.image.basepath }}/node-key; + sed -n -r "s/^${POD_NAME}-name ([^ ]+)$/\1/p" /etc/validator/secrets > {{ .Values.image.basepath }}/name; + test -s {{ .Values.image.basepath }}/name || echo "${POD_NAME}" > {{ .Values.image.basepath }}/name + env: + # from (workaround for hostname) + # https://kubernetes.io/docs/tasks/inject-data-application/environment-variable-expose-pod-information/ + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + volumeMounts: + - name: {{ .Values.app }}-validator-secrets + readOnly: true + mountPath: "/etc/validator" + - name: {{ .Values.app }}dir + mountPath: {{ .Values.image.basepath }} + {{- end }} + containers: + - name: {{ .Values.app }} + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + {{- if .Values.resources }} + resources: + requests: + memory: {{ .Values.resources.memory }} + cpu: {{ .Values.resources.cpu }} + {{- end }} + ports: + - containerPort: 30333 + name: p2p + - containerPort: 9933 + name: http-rpc + - containerPort: 9944 + name: websocket-rpc + command: ["/bin/sh"] + args: + - -c + - exec /usr/local/bin/substrate + --base-path {{ .Values.image.basepath }} + {{- if .Values.validator.keys }} + --validator + --name $(cat {{ .Values.image.basepath }}/name) + --key $(cat {{ .Values.image.basepath }}/key) + --node-key $(cat {{ .Values.image.basepath }}/node-key) + {{- else }} + --name $(POD_NAME) + {{- end }} + {{- range .Values.nodes.args }} {{ . }} {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + volumeMounts: + - name: {{ .Values.app }}dir + mountPath: {{ .Values.image.basepath }} + readinessProbe: + httpGet: + path: /health + port: http-rpc + initialDelaySeconds: 10 + periodSeconds: 10 + livenessProbe: + httpGet: + path: /health + port: http-rpc + initialDelaySeconds: 10 + periodSeconds: 10 + securityContext: + runAsUser: 1000 + fsGroup: 1000 + volumeClaimTemplates: + - metadata: + name: {{ .Values.app }}dir + spec: + accessModes: [ "ReadWriteOnce" ] + storageClassName: ssd + resources: + requests: + storage: 32Gi + diff --git a/scripts/kubernetes/values.yaml b/scripts/kubernetes/values.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f56cea29934dccce9154c36ce08c819c35c84aac --- /dev/null +++ b/scripts/kubernetes/values.yaml @@ -0,0 +1,59 @@ +# set tag manually --set image.tag=latest +image: + repository: parity/substrate + tag: latest + pullPolicy: Always + basepath: /substrate + + +# if set to true a service account for substrate will be created +rbac: + enable: true + name: substrate + + +# name of the statefulset +app: substrate +listen_node_port: true + +nodes: + replicas: 2 + args: + # name and data directory are set by the chart itself + # key and node-key may be provided on commandline invocation + # + # - --chain + # - krummelanke + # serve rpc within the local network + # - fenced off the world via firewall + # - used for health checks + - --rpc-external + - --ws-external + # - --log + # - sub-libp2p=trace + + +validator: {} + # providing 'keys' string via --set commandline parameter will run the nodes + # in validator mode (--validator). + # + # name, key and node-key can be given in a base64 encoded keyfile string (at + # validator.keys) which has the following format: + # + # substrate-0-name + # substrate-0-key + # substrate-0-node-key + # substrate-1-name + # substrate-1-key + # substrate-1-node-key + # + # pod names are canonical. changing these or providing different amount of + # keys than the replicas count will lead to behaviour noone ever has + # experienced before. + + +# maybe adopt resource limits here to the nodes of the pool +# resources: +# memory: "5Gi" +# cpu: "1.5" + diff --git a/srml/assets/Cargo.toml b/srml/assets/Cargo.toml index 49fc423e1b5c7767b71b493e267968f7823fa95b..f274661e6c84e85740305cff5a79c5f3589f2a0c 100644 --- a/srml/assets/Cargo.toml +++ b/srml/assets/Cargo.toml @@ -6,8 +6,8 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } -parity-codec = { version = "3.0", default-features = false } +serde = { version = "1.0", optional = true } +parity-codec = { version = "3.2", default-features = false } # Needed for various traits. In our case, `OnFinalise`. primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } # Needed for type-safe access to storage DB. @@ -23,7 +23,7 @@ runtime_io = { package = "sr-io", path = "../../core/sr-io" } [features] default = ["std"] std = [ - "serde/std", + "serde", "parity-codec/std", "primitives/std", "srml-support/std", diff --git a/srml/assets/src/lib.rs b/srml/assets/src/lib.rs index ad78dd50855e0779d5b16cc159a254a3a1b9c950..9caa3dc20d5426ba22f527ab37bc4851a955a084 100644 --- a/srml/assets/src/lib.rs +++ b/srml/assets/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -82,9 +82,6 @@ decl_module! { } } -/// An event in this module. Events are simple means of reporting specific conditions and -/// circumstances that have happened that users, Dapps and/or chain explorers would find -/// interesting and otherwise difficult to detect. decl_event!( pub enum Event where ::AccountId, ::Balance { /// Some assets were issued. @@ -154,7 +151,7 @@ mod tests { type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; diff --git a/srml/aura/Cargo.toml b/srml/aura/Cargo.toml index 27e5b11e8a7b8eb73d1977f791fe2ed056af6962..9d1eda38c055fe18c1d3d67496bc4b654f8513bf 100644 --- a/srml/aura/Cargo.toml +++ b/srml/aura/Cargo.toml @@ -6,9 +6,9 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } -serde = { version = "1.0", default-features = false } +parity-codec = { version = "3.2", default-features = false, features = ["derive"] } +parity-codec-derive = { version = "3.1", default-features = false } +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 } primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } @@ -16,6 +16,7 @@ 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 } staking = { package = "srml-staking", path = "../staking", default-features = false } +session = { package = "srml-session", path = "../session", default-features = false } [dev-dependencies] lazy_static = "1.0" @@ -27,7 +28,7 @@ consensus = { package = "srml-consensus", path = "../consensus" } [features] default = ["std"] std = [ - "serde/std", + "serde", "parity-codec/std", "rstd/std", "srml-support/std", diff --git a/srml/aura/src/lib.rs b/srml/aura/src/lib.rs index dfece22e7af0fff52bcef2833be674a1cb03ac64..344ea64869656aa79da8e696da59fef704954760 100644 --- a/srml/aura/src/lib.rs +++ b/srml/aura/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -27,9 +27,7 @@ use primitives::traits::{As, Zero}; use timestamp::OnTimestampSet; #[cfg(feature = "std")] use timestamp::TimestampInherentData; -#[cfg(feature = "std")] -use parity_codec::Decode; -use parity_codec_derive::{Encode, Decode}; +use parity_codec::{Encode, Decode}; use inherents::{RuntimeString, InherentIdentifier, InherentData, ProvideInherent, MakeFatalError}; #[cfg(feature = "std")] use inherents::{InherentDataProviders, ProvideInherentData}; @@ -167,7 +165,7 @@ impl Module { pub fn slot_duration() -> u64 { // we double the minimum block-period so each author can always propose within // the majority of their slot. - >::block_period().as_().saturating_mul(2) + >::minimum_period().as_().saturating_mul(2) } fn on_timestamp_set(now: T::Moment, slot_duration: T::Moment) { @@ -209,7 +207,7 @@ pub struct StakingSlasher(::rstd::marker::PhantomData); impl HandleReport for StakingSlasher { fn handle_report(report: AuraReport) { - let validators = staking::Module::::validators(); + let validators = session::Module::::validators(); report.punish( validators.len(), diff --git a/srml/aura/src/mock.rs b/srml/aura/src/mock.rs index 04b5d35efe1e2a01f6752a5ad5c29cde03e3b6d8..e72e25ef94080f84f1aa2d883695da56bd459a2b 100644 --- a/srml/aura/src/mock.rs +++ b/srml/aura/src/mock.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -46,7 +46,7 @@ impl system::Trait for Test { type Hashing = ::primitives::traits::BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; @@ -68,7 +68,7 @@ pub fn new_test_ext(authorities: Vec) -> runtime_io::TestExternalities{ - period: 1, + minimum_period: 1, }.build_storage().unwrap().0); t.into() } diff --git a/srml/aura/src/tests.rs b/srml/aura/src/tests.rs index 91f02259250a367968d6957766d8a81d0bb312f9..98b57a1251248a290f9fddc0bb4b4cb78a1a4ccd 100644 --- a/srml/aura/src/tests.rs +++ b/srml/aura/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/srml/balances/Cargo.toml b/srml/balances/Cargo.toml index adc1398dd11fb65846c839579e0776e541a28bf0..43759643ddfad3b3b14efeace9967d6bf0b7c5dc 100644 --- a/srml/balances/Cargo.toml +++ b/srml/balances/Cargo.toml @@ -6,10 +6,9 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false} -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", 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 } @@ -23,11 +22,10 @@ substrate-primitives = { path = "../../core/primitives" } [features] default = ["std"] std = [ - "serde/std", + "serde", "safe-mix/std", "substrate-keyring", "parity-codec/std", - "parity-codec-derive/std", "rstd/std", "srml-support/std", "primitives/std", diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index 60fb5f6c0073626b4feb6486070dad1e0becb4ce..fa34bc43a09dee3ce6e586133df4c1bd985fc766 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -14,35 +14,201 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! Balances: Handles setting and retrieval of free balance, -//! retrieving total balance, reserve and unreserve balance, -//! repatriating a reserved balance to a beneficiary account that exists, -//! transfering a balance between accounts (when not reserved), -//! slashing an account balance, account removal, rewards, -//! lookup of an index to reclaim an account (when not balance not reserved), -//! increasing total stake. +//! # Balances Module +//! +//! The balances module provides functionality for handling accounts and balances. To use the balances module, you need +//! to implement the [balances Trait](https://crates.parity.io/srml_balances/trait.Trait.html). Supported dispatchables +//! are documented in the [`Call` enum](https://crates.parity.io/srml_balances/enum.Call.html). +//! +//! ## Overview +//! +//! The balances module provides functions for: +//! +//! - Getting and setting free balances +//! - Retrieving total, reserved and unreserved balances +//! - Repatriating a reserved balance to a beneficiary account that exists +//! - Transferring a balance between accounts (when not reserved) +//! - Slashing an account balance +//! - Account creation and removal +//! - Lookup of an index to reclaim an account +//! - Managing total issuance +//! - Setting and managing locks +//! +//! ### Terminology +//! +//! - **Existential Deposit:** The minimum balance required to create or keep an account open. This prevents +//! "dust accounts" from filling storage. +//! - **Total Issuance:** The total amount of units in existence in a system. +//! - **Reaping an account:** The act of removing an account by resetting its nonce. Happens after its balance is set +//! to zero. +//! - **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 of 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 funds were created or deducted without equal and opposite accounting. +//! Functions that result in an imbalance will return an object of the `Imbalance` trait that must be handled. +//! - **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". +//! - **Vesting:** Similar to a lock, this is another, but independent, liquidity restriction that reduces linearly +//! over time. +//! +//! ### Implementations +//! +//! The balances module provides implementations for the following traits. If these traits provide the functionality +//! that you need, then you can avoid coupling with the balances module. +//! +//! - [`Currency`](https://crates.parity.io/srml_support/traits/trait.Currency.html): Functions for dealing with a +//! fungible assets system. +//! - [`ReservableCurrency`](https://crates.parity.io/srml_support/traits/trait.ReservableCurrency.html): +//! Functions for dealing with assets that can be reserved from an account. +//! - [`LockableCurrency`](https://crates.parity.io/srml_support/traits/trait.LockableCurrency.html): Functions for +//! dealing with accounts that allow liquidity restrictions. +//! - [`Imbalance`](https://crates.parity.io/srml_support/traits/trait.Imbalance.html): Functions for handling +//! imbalances between total issuance in the system and account balances. Must be used when a function +//! creates new funds (e.g. a reward) or destroys some funds (e.g. a system fee). +//! - [`MakePayment`](https://crates.parity.io/srml_support/traits/trait.MakePayment.html): Simple trait designed +//! for hooking into a transaction payment. +//! - [`IsDeadAccount`](https://crates.parity.io/srml_system/trait.IsDeadAccount.html): Determiner to say whether a +//! given account is unused. +//! +//! Example of using the `Currency` trait from the treasury module: +//! +//! ```rust,ignore +//! pub trait Trait: system::Trait { +//! /// The staking balance. +//! type Currency: Currency; +//! } +//! ``` +//! +//! ## Interface +//! +//! ### Dispatchable Functions +//! +//! The `Call` enum is documented [here](https://crates.parity.io/srml_balances/enum.Call.html). +//! +//! - `transfer` - Transfer some liquid free balance to another account. +//! - `set_balance` - Set the balances of a given account. The origin of this call must be root. +//! +//! ### Public Functions +//! +//! See the [module](https://crates.parity.io/srml_balances/struct.Module.html) for details on publicly available +//! functions. +//! +//! ## Usage +//! +//! The following examples show how to use the balances module in your custom module. +//! +//! ### Import and Balance Transfer +//! +//! Import the `balances` module and derive your module configuration trait with the balances trait. You can now call +//! functions from the module. +//! +//! ```rust,ignore +//! use support::{decl_module, dispatch::Result}; +//! use system::ensure_signed; +//! +//! pub trait Trait: balances::Trait {} +//! +//! decl_module! { +//! pub struct Module for enum Call where origin: T::Origin { +//! fn transfer_proxy(origin, to: T::AccountId, value: T::Balance) -> Result { +//! let sender = ensure_signed(origin)?; +//! >::make_transfer(&sender, &to, value)?; +//! +//! Ok(()) +//! } +//! } +//! } +//! ``` +//! +//! ### Real Use Example +//! +//! Use in the `contract` module (gas.rs): +//! +//! ```rust,ignore +//! pub fn refund_unused_gas( +//! transactor: &T::AccountId, +//! gas_meter: GasMeter, +//! imbalance: balances::NegativeImbalance, +//! ) { +//! let gas_spent = gas_meter.spent(); +//! let gas_left = gas_meter.gas_left(); +//! +//! // Increase total spent gas. +//! >::mutate(|block_gas_spent| *block_gas_spent += gas_spent); +//! +//! let refund = >::as_(gas_left) * gas_meter.gas_price; +//! // Refund gas using balances module +//! let refund_imbalance = >::deposit_creating(transactor, refund); +//! // Handle imbalance +//! if let Ok(imbalance) = imbalance.offset(refund_imbalance) { +//! T::GasPayment::on_unbalanced(imbalance); +//! } +//! } +//! ``` +//! +//! ## Genesis config +//! +//! The following storage items depend on the genesis config: +//! +//! - `TotalIssuance` +//! - `ExistentialDeposit` +//! - `TransferFee` +//! - `CreationFee` +//! - `Vesting` +//! - `FreeBalance` +//! - `TransactionBaseFee` +//! - `TransactionByteFee` +//! +//! ## Related Modules +//! +//! The balances module depends on the [`system`](https://crates.parity.io/srml_system/index.html) and +//! [`srml_support`](https://crates.parity.io/srml_support/index.html) modules as well as Substrate Core +//! libraries and the Rust standard library. #![cfg_attr(not(feature = "std"), no_std)] use rstd::prelude::*; use rstd::{cmp, result}; -use parity_codec::Codec; -use parity_codec_derive::{Encode, Decode}; -use srml_support::{StorageValue, StorageMap, Parameter, decl_event, decl_storage, decl_module, ensure}; -use srml_support::traits::{UpdateBalanceOutcome, Currency, EnsureAccountLiquid, OnFreeBalanceZero, ArithmeticType}; +use parity_codec::{Codec, Encode, Decode}; +use srml_support::{StorageValue, StorageMap, Parameter, decl_event, decl_storage, decl_module}; +use srml_support::traits::{ + UpdateBalanceOutcome, Currency, OnFreeBalanceZero, MakePayment, OnUnbalanced, + WithdrawReason, WithdrawReasons, LockIdentifier, LockableCurrency, ExistenceRequirement, + Imbalance, SignedImbalance, ReservableCurrency +}; use srml_support::dispatch::Result; -use primitives::traits::{Zero, SimpleArithmetic, - As, StaticLookup, Member, CheckedAdd, CheckedSub, MaybeSerializeDebug, TransferAsset}; +use primitives::traits::{ + Zero, SimpleArithmetic, As, StaticLookup, Member, CheckedAdd, CheckedSub, + MaybeSerializeDebug, Saturating +}; use system::{IsDeadAccount, OnNewAccount, ensure_signed}; mod mock; mod tests; -pub trait Trait: system::Trait { +pub trait Subtrait: system::Trait { /// The balance of an account. type Balance: Parameter + Member + SimpleArithmetic + Codec + Default + Copy + As + As + MaybeSerializeDebug; - /// A function which is invoked when the free-balance has fallen below the existential deposit and + /// A function that is invoked when the free-balance has fallen below the existential deposit and + /// has been reduced to zero. + /// + /// Gives a chance to clean up resources associated with the given account. + type OnFreeBalanceZero: OnFreeBalanceZero; + + /// Handler for when a new account is created. + type OnNewAccount: OnNewAccount; +} + +pub trait Trait: system::Trait { + /// The balance of an account. + type Balance: Parameter + Member + SimpleArithmetic + Codec + Default + Copy + As + As + MaybeSerializeDebug; + + /// A function that is invoked when the free-balance has fallen below the existential deposit and /// has been reduced to zero. /// /// Gives a chance to clean up resources associated with the given account. @@ -51,21 +217,30 @@ pub trait Trait: system::Trait { /// Handler for when a new account is created. type OnNewAccount: OnNewAccount; - /// A function that returns true iff a given account can transfer its funds to another account. - type EnsureAccountLiquid: EnsureAccountLiquid; + /// Handler for the unbalanced reduction when taking transaction fees. + type TransactionPayment: OnUnbalanced>; + + /// Handler for the unbalanced reduction when taking fees associated with balance + /// transfer (which may also include account creation). + type TransferPayment: OnUnbalanced>; + + /// Handler for the unbalanced reduction when removing a dust account. + type DustRemoval: OnUnbalanced>; /// The overarching event type. - type Event: From> + Into<::Event>; + type Event: From> + Into<::Event>; } -impl ArithmeticType for Module { - type Type = ::Balance; +impl, I: Instance> Subtrait for T { + type Balance = T::Balance; + type OnFreeBalanceZero = T::OnFreeBalanceZero; + type OnNewAccount = T::OnNewAccount; } decl_event!( - pub enum Event where + pub enum Event where ::AccountId, - ::Balance + >::Balance { /// A new account was created. NewAccount(AccountId, Balance), @@ -97,21 +272,34 @@ impl> VestingSchedule { } } +#[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 Balances { - /// The total amount of stake on the system. - pub TotalIssuance get(total_issuance) build(|config: &GenesisConfig| { + trait Store for Module, I: Instance=DefaultInstance> as Balances { + /// The total units issued in the system. + 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 allowed to keep an account open. + /// 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. At least as big as ReclaimRebate. + /// 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| { + pub Vesting get(vesting) build(|config: &GenesisConfig| { config.vesting.iter().filter_map(|&(ref who, begin, length)| { let begin: u64 = begin.as_(); let length: u64 = length.as_(); @@ -124,7 +312,7 @@ decl_storage! { // <= begin it should be >= balance // >= begin+length it should be <= 0 - let per_block = balance / length; + let per_block = balance / length.max(primitives::traits::One::one()); let offset = begin * per_block + balance; (who.clone(), VestingSchedule { offset, per_block }) @@ -134,42 +322,52 @@ decl_storage! { /// The 'free' balance of a given account. /// - /// This is the only balance that matters in terms of most operations on tokens. It is - /// alone used to determine the balance when in the contract execution environment. When this + /// This is the only balance that matters in terms of most operations on tokens. It + /// alone is used to determine the balance when in the contract execution environment. When this /// balance falls below the value of `ExistentialDeposit`, then the 'current account' is - /// deleted: specifically `FreeBalance`. Furthermore, `OnFreeBalanceZero` callback - /// is invoked, giving a chance to external modules to cleanup data associated with + /// deleted: specifically `FreeBalance`. Further, the `OnFreeBalanceZero` callback + /// is invoked, giving a chance to external modules to clean up data associated with /// the deleted account. /// /// `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. /// /// This balance is a 'reserve' balance that other subsystems use in order to set aside tokens - /// that are still 'owned' by the account holder, but which are suspendable. (This is different - /// and wholly unrelated to the `Bondage` system used in the staking module.) + /// that are still 'owned' by the account holder, but which are suspendable. /// /// When this balance falls below the value of `ExistentialDeposit`, then this 'reserve account' /// is deleted: specifically, `ReservedBalance`. /// /// `system::AccountNonce` is also deleted if `FreeBalance` is also zero (it also gets - /// collapsed to zero if it ever becomes less than `ExistentialDeposit`. + /// collapsed to zero if it ever becomes less than `ExistentialDeposit`.) pub ReservedBalance get(reserved_balance): map T::AccountId => T::Balance; + + /// Any liquidity locks on some account balances. + pub Locks get(locks): map T::AccountId => Vec>; } add_extra_genesis { config(balances): Vec<(T::AccountId, T::Balance)>; config(vesting): Vec<(T::AccountId, T::BlockNumber, T::BlockNumber)>; // begin, length } + extra_genesis_skip_phantom_data_field; } decl_module! { - pub struct Module for enum Call where origin: T::Origin { - fn deposit_event() = default; + pub struct Module, I: Instance = DefaultInstance> for enum Call where origin: T::Origin { + fn deposit_event() = default; - /// Transfer some liquid free balance to another staker. + /// Transfer some liquid free balance to another account. + /// + /// `transfer` will set the `FreeBalance` of the sender and receiver. + /// It will decrease the total issuance of the system by the `TransferFee`. + /// If the sender's account is below the existential deposit as a result + /// of the transfer, the account will be reaped. + /// + /// The dispatch origin for this call must be `Signed` by the transactor. pub fn transfer( origin, dest: ::Source, @@ -177,10 +375,17 @@ decl_module! { ) { let transactor = ensure_signed(origin)?; let dest = T::Lookup::lookup(dest)?; - Self::make_transfer(&transactor, &dest, value)?; + >::transfer(&transactor, &dest, value)?; } /// Set the balances of a given account. + /// + /// This will alter `FreeBalance` and `ReservedBalance` in storage. + /// If the new free or reserved balance is below the existential deposit, + /// it will also decrease the total issuance of the system (`TotalIssuance`) + /// and reset the account nonce (`system::AccountNonce`). + /// + /// The dispatch origin for this call is `root`. fn set_balance( who: ::Source, #[compact] free: T::Balance, @@ -193,10 +398,11 @@ decl_module! { } } -// For funding methods, see Currency trait -impl Module { +impl, I: Instance> Module { - /// Get the amount that is currently being vested and cannot be transfered out of this account. + // PUBLIC IMMUTABLES + + /// Get the amount that is currently being vested and cannot be transferred out of this account. 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())) @@ -205,156 +411,77 @@ impl Module { } } - /// Set the free balance of an account to some new value. + // PRIVATE MUTABLES + + /// Set the reserved balance of an account to some new value. Will enforce `ExistentialDeposit` + /// law, annulling the account as needed. + /// + /// Doesn't do any preparatory work for creating a new account, so should only be used when it + /// is known that the account already exists. /// - /// Will enforce ExistentialDeposit law, anulling the account as needed. - /// In that case it will return `AccountKilled`. - pub fn set_reserved_balance(who: &T::AccountId, balance: T::Balance) -> UpdateBalanceOutcome { + /// 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() { - >::insert(who, balance); + >::insert(who, balance); Self::on_reserved_too_low(who); UpdateBalanceOutcome::AccountKilled } else { - >::insert(who, balance); + >::insert(who, balance); UpdateBalanceOutcome::Updated } } - /// Set the free balance of an account to some new value. Will enforce ExistentialDeposit - /// law anulling the account as needed. + /// Set the free balance of an account to some new value. Will enforce `ExistentialDeposit` + /// law, annulling the account as needed. /// /// Doesn't do any preparatory work for creating a new account, so should only be used when it /// is known that the account already exists. /// - /// Returns if the account was successfully updated or update has led to killing of the account. - pub fn set_free_balance(who: &T::AccountId, balance: T::Balance) -> UpdateBalanceOutcome { - // Commented out for no - but consider it instructive. + /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that + /// the caller will do this. + 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() { - >::insert(who, balance); + >::insert(who, balance); Self::on_free_too_low(who); UpdateBalanceOutcome::AccountKilled } else { - >::insert(who, balance); + >::insert(who, balance); UpdateBalanceOutcome::Updated } } - /// Set the free balance on an account to some new value. - /// - /// Same as [`set_free_balance`], but will create a new account. - /// - /// Returns if the account was successfully updated or update has led to killing of the account. - /// - /// [`set_free_balance`]: #method.set_free_balance - pub fn set_free_balance_creating(who: &T::AccountId, balance: T::Balance) -> UpdateBalanceOutcome { - let ed = >::existential_deposit(); - // If the balance is too low, then the account is reaped. - // NOTE: There are two balances for every account: `reserved_balance` and - // `free_balance`. This contract subsystem only cares about the latter: whenever - // the term "balance" is used *here* it should be assumed to mean "free balance" - // in the rest of the module. - // 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). - // NOTE: This is orthogonal to the `Bondage` value that an account has, a high - // value of which makes even the `free_balance` unspendable. - if balance < ed { - Self::set_free_balance(who, balance); - UpdateBalanceOutcome::AccountKilled - } else { - if !>::exists(who) { - Self::new_account(&who, balance); - } - Self::set_free_balance(who, balance); - - UpdateBalanceOutcome::Updated - } - } - - /// Adds up to `value` to the free balance of `who`. If `who` doesn't exist, it is created. - /// - /// This is a sensitive function since it circumvents any fees associated with account - /// setup. Ensure it is only called by trusted code. - /// - /// NOTE: This assumes that the total stake remains unchanged after this operation. If - /// you mean to actually mint value into existence, then use `reward` instead. - pub fn increase_free_balance_creating(who: &T::AccountId, value: T::Balance) -> UpdateBalanceOutcome { - Self::set_free_balance_creating(who, Self::free_balance(who) + value) - } - - /// Substrates `value` from the free balance of `who`. If the whole amount cannot be - /// deducted, an error is returned. - /// - /// NOTE: This assumes that the total stake remains unchanged after this operation. If - /// you mean to actually burn value out of existence, then use `slash` instead. - pub fn decrease_free_balance( - who: &T::AccountId, - value: T::Balance - ) -> result::Result { - T::EnsureAccountLiquid::ensure_account_liquid(who)?; - let b = Self::free_balance(who); - if b < value { - return Err("account has too few funds") - } - Ok(Self::set_free_balance(who, b - value)) - } - - /// Transfer some liquid free balance to another staker. - pub fn make_transfer(transactor: &T::AccountId, dest: &T::AccountId, value: T::Balance) -> Result { - 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 liability = match value.checked_add(&fee) { - Some(l) => l, - None => return Err("got overflow after adding a fee to value"), - }; - - let vesting_balance = Self::vesting_balance(transactor); - let new_from_balance = match from_balance.checked_sub(&liability) { - None => return Err("balance too low to send value"), - Some(b) if b < vesting_balance => return Err("vesting balance too high to send value"), - Some(b) => b, - }; - if would_create && value < Self::existential_deposit() { - return Err("value too low to create account"); - } - T::EnsureAccountLiquid::ensure_account_liquid(transactor)?; - - // NOTE: total stake being stored in the same type means that this could never overflow - // but better to be safe than sorry. - let new_to_balance = match to_balance.checked_add(&value) { - Some(b) => b, - None => return Err("destination balance too high to receive value"), - }; - - if transactor != dest { - Self::set_free_balance(transactor, new_from_balance); - Self::decrease_total_stake_by(fee); - Self::set_free_balance_creating(dest, new_to_balance); - Self::deposit_event(RawEvent::Transfer(transactor.clone(), dest.clone(), value, fee)); - } - - Ok(()) - } - - /// Register a new account (with existential balance). + /// + /// This just calls appropriate hooks. It doesn't (necessarily) make any state changes. fn new_account(who: &T::AccountId, balance: T::Balance) { T::OnNewAccount::on_new_account(&who); Self::deposit_event(RawEvent::NewAccount(who.clone(), balance.clone())); } + /// Unregister an account. + /// + /// This just removes the nonce and leaves an event. fn reap_account(who: &T::AccountId) { >::remove(who); Self::deposit_event(RawEvent::ReapedAccount(who.clone())); } - /// Kill an account's free portion. + /// Account's free balance has dropped below existential deposit. Kill its + /// free side and the account completely if its reserved size is already dead. + /// + /// Will maintain total issuance. fn on_free_too_low(who: &T::AccountId) { - Self::decrease_total_stake_by(Self::free_balance(who)); - >::remove(who); + let dust = >::take(who); + >::remove(who); + + // underflow should never happen, but if it does, there's not much we can do about it. + if !dust.is_zero() { + T::DustRemoval::on_unbalanced(NegativeImbalance(dust)); + } T::OnFreeBalanceZero::on_free_balance_zero(who); @@ -363,35 +490,170 @@ impl Module { } } - /// Kill an account's reserved portion. + /// Account's reserved balance has dropped below existential deposit. Kill its + /// reserved side and the account completely if its free size is already dead. + /// + /// Will maintain total issuance. fn on_reserved_too_low(who: &T::AccountId) { - Self::decrease_total_stake_by(Self::reserved_balance(who)); - >::remove(who); + let dust = >::take(who); + + // underflow should never happen, but it if does, there's nothing to be done here. + if !dust.is_zero() { + T::DustRemoval::on_unbalanced(NegativeImbalance(dust)); + } if Self::free_balance(who).is_zero() { Self::reap_account(who); } } +} + +/// 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, I: Instance=DefaultInstance>(T::Balance); + +/// 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, I: Instance=DefaultInstance>(T::Balance); + +impl, I: Instance> Imbalance for PositiveImbalance { + type Opposite = NegativeImbalance; - /// Increase TotalIssuance by Value. - pub fn increase_total_stake_by(value: T::Balance) { - if let Some(v) = >::total_issuance().checked_add(&value) { - >::put(v); + fn zero() -> Self { + Self(Zero::zero()) + } + fn drop_zero(self) -> result::Result<(), Self> { + if self.0.is_zero() { + Ok(()) + } else { + Err(self) } } - /// Decrease TotalIssuance by Value. - pub fn decrease_total_stake_by(value: T::Balance) { - if let Some(v) = >::total_issuance().checked_sub(&value) { - >::put(v); + fn split(self, amount: T::Balance) -> (Self, Self) { + let first = self.0.min(amount); + let second = self.0 - first; + (Self(first), Self(second)) + } + fn merge(self, other: Self) -> Self { + Self(self.0.saturating_add(other.0)) + } + fn subsume(&mut self, other: Self) { + self.0 = self.0.saturating_add(other.0) + } + fn offset(self, other: Self::Opposite) -> result::Result { + if self.0 >= other.0 { + Ok(Self(self.0 - other.0)) + } else { + Err(NegativeImbalance(other.0 - self.0)) + } + } + fn peek(&self) -> T::Balance { + self.0.clone() + } +} + +impl, I: Instance> Imbalance for NegativeImbalance { + type Opposite = PositiveImbalance; + + fn zero() -> Self { + Self(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; + (Self(first), Self(second)) + } + fn merge(self, other: Self) -> Self { + Self(self.0.saturating_add(other.0)) + } + fn subsume(&mut self, other: Self) { + self.0 = self.0.saturating_add(other.0) + } + fn offset(self, other: Self::Opposite) -> result::Result { + if self.0 >= other.0 { + Ok(Self(self.0 - other.0)) + } else { + Err(PositiveImbalance(other.0 - self.0)) } } + fn peek(&self) -> T::Balance { + self.0.clone() + } +} + +// 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, I: Instance>(T, I); +impl, I: Instance> Clone for ElevatedTrait { + fn clone(&self) -> Self { unimplemented!() } +} +impl, I: Instance> PartialEq for ElevatedTrait { + fn eq(&self, _: &Self) -> bool { unimplemented!() } +} +impl, I: Instance> Eq for ElevatedTrait {} +impl, I: Instance> 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 Digest = T::Digest; + type AccountId = T::AccountId; + type Lookup = T::Lookup; + type Header = T::Header; + type Event = (); + type Log = T::Log; +} +impl, I: Instance> Trait for ElevatedTrait { + type Balance = T::Balance; + type OnFreeBalanceZero = T::OnFreeBalanceZero; + type OnNewAccount = T::OnNewAccount; + type Event = (); + type TransactionPayment = (); + type TransferPayment = (); + type DustRemoval = (); +} + +impl, I: Instance> Drop for PositiveImbalance { + /// Basic drop handler will just square up the total issuance. + fn drop(&mut self) { + , I>>::mutate(|v| *v = v.saturating_add(self.0)); + } +} + +impl, I: Instance> Drop for NegativeImbalance { + /// Basic drop handler will just square up the total issuance. + fn drop(&mut self) { + , I>>::mutate(|v| *v = v.saturating_sub(self.0)); + } } -impl Currency for Module +impl, I: Instance> Currency for Module where T::Balance: MaybeSerializeDebug { 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) @@ -401,49 +663,205 @@ where Self::free_balance(who) >= value } - fn can_reserve(who: &T::AccountId, value: Self::Balance) -> bool { - if T::EnsureAccountLiquid::ensure_account_liquid(who).is_ok() { - Self::free_balance(who) >= value - } else { - false - } + fn total_issuance() -> Self::Balance { + >::get() } - fn total_issuance() -> Self:: Balance { - Self::total_issuance() + fn minimum_balance() -> Self::Balance { + Self::existential_deposit() } fn free_balance(who: &T::AccountId) -> Self::Balance { - Self::free_balance(who) + >::get(who) } - fn reserved_balance(who: &T::AccountId) -> Self::Balance { - Self::reserved_balance(who) + fn ensure_can_withdraw( + who: &T::AccountId, + _amount: T::Balance, + reason: WithdrawReason, + new_balance: T::Balance, + ) -> Result { + match reason { + WithdrawReason::Reserve | WithdrawReason::Transfer if Self::vesting_balance(who) > new_balance => + return Err("vesting balance too high to send value"), + _ => {} + } + 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") + } + } + + fn transfer(transactor: &T::AccountId, dest: &T::AccountId, value: Self::Balance) -> Result { + 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 liability = match value.checked_add(&fee) { + Some(l) => l, + None => return Err("got overflow after adding a fee to value"), + }; + + let new_from_balance = match from_balance.checked_sub(&liability) { + None => return Err("balance too low to send value"), + Some(b) => b, + }; + if would_create && value < Self::existential_deposit() { + return Err("value too low to create account"); + } + Self::ensure_can_withdraw(transactor, value, WithdrawReason::Transfer, new_from_balance)?; + + // NOTE: total stake being stored in the same type means that this could never overflow + // but better to be safe than sorry. + let new_to_balance = match to_balance.checked_add(&value) { + Some(b) => b, + None => return Err("destination balance too high to receive value"), + }; + + if transactor != dest { + Self::set_free_balance(transactor, new_from_balance); + if !>::exists(dest) { + Self::new_account(dest, new_to_balance); + } + Self::set_free_balance(dest, new_to_balance); + T::TransferPayment::on_unbalanced(NegativeImbalance(fee)); + Self::deposit_event(RawEvent::Transfer(transactor.clone(), dest.clone(), value, fee)); + } + + Ok(()) + } + + fn withdraw( + who: &T::AccountId, + value: Self::Balance, + reason: WithdrawReason, + 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() { + return Err("payment would kill account") + } + Self::ensure_can_withdraw(who, value, reason, new_balance)?; + Self::set_free_balance(who, new_balance); + Ok(NegativeImbalance(value)) + } else { + Err("too few free funds in account") + } } - fn slash(who: &T::AccountId, value: Self::Balance) -> Option { + fn slash( + who: &T::AccountId, + value: Self::Balance + ) -> (Self::NegativeImbalance, Self::Balance) { let free_balance = Self::free_balance(who); let free_slash = cmp::min(free_balance, value); Self::set_free_balance(who, free_balance - free_slash); - Self::decrease_total_stake_by(free_slash); - if free_slash < value { - Self::slash_reserved(who, value - free_slash) + let remaining_slash = value - free_slash; + // NOTE: `slash()` prefers free balance, but assumes that reserve balance can be drawn + // from in extreme circumstances. `can_slash()` should be used prior to `slash()` is avoid having + // to draw from reserved funds, however we err on the side of punishment if things are inconsistent + // or `can_slash` wasn't used appropriately. + if !remaining_slash.is_zero() { + let reserved_balance = Self::reserved_balance(who); + let reserved_slash = cmp::min(reserved_balance, remaining_slash); + Self::set_reserved_balance(who, reserved_balance - reserved_slash); + (NegativeImbalance(free_slash + reserved_slash), remaining_slash - reserved_slash) } else { - None + (NegativeImbalance(value), Zero::zero()) } } - fn reward(who: &T::AccountId, value: Self::Balance) -> result::Result<(), &'static str> { + fn deposit_into_existing( + who: &T::AccountId, + value: Self::Balance + ) -> result::Result { if Self::total_balance(who).is_zero() { return Err("beneficiary account must pre-exist"); } Self::set_free_balance(who, Self::free_balance(who) + value); - Self::increase_total_stake_by(value); - Ok(()) + Ok(PositiveImbalance(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 increase_free_balance_creating(who: &T::AccountId, value: Self::Balance) -> UpdateBalanceOutcome { - Self::set_free_balance_creating(who, Self::free_balance(who) + value) + fn make_free_balance_be(who: &T::AccountId, balance: T::Balance) -> ( + SignedImbalance, + UpdateBalanceOutcome + ) { + let original = Self::free_balance(who); + if balance < Self::existential_deposit() && 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 + // (in the dust cleaner of set_free_balance) before we account for its actual + // equal and opposite cause (returned as an Imbalance), then in the + // instance that there's no other accounts on the system at all, we might + // underflow the issuance and our arithmetic will be off. + return ( + SignedImbalance::Positive(Self::PositiveImbalance::zero()), + UpdateBalanceOutcome::AccountKilled, + ) + } + let imbalance = if original <= balance { + SignedImbalance::Positive(PositiveImbalance(balance - original)) + } else { + SignedImbalance::Negative(NegativeImbalance(original - balance)) + }; + // If the balance is too low, then the account is reaped. + // NOTE: There are two balances for every account: `reserved_balance` and + // `free_balance`. This contract subsystem only cares about the latter: whenever + // the term "balance" is used *here* it should be assumed to mean "free balance" + // in the rest of the module. + // 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() { + Self::set_free_balance(who, balance); + UpdateBalanceOutcome::AccountKilled + } else { + if !>::exists(who) { + Self::new_account(&who, balance); + } + Self::set_free_balance(who, balance); + UpdateBalanceOutcome::Updated + }; + (imbalance, outcome) + } +} + +impl, I: Instance> ReservableCurrency for Module +where + T::Balance: MaybeSerializeDebug +{ + fn can_reserve(who: &T::AccountId, value: Self::Balance) -> bool { + Self::free_balance(who) + .checked_sub(&value) + .map_or(false, |new_balance| + Self::ensure_can_withdraw(who, value, WithdrawReason::Reserve, new_balance).is_ok() + ) + } + + fn reserved_balance(who: &T::AccountId) -> Self::Balance { + >::get(who) } fn reserve(who: &T::AccountId, value: Self::Balance) -> result::Result<(), &'static str> { @@ -451,41 +869,37 @@ where if b < value { return Err("not enough free funds") } - T::EnsureAccountLiquid::ensure_account_liquid(who)?; + let new_balance = b - value; + Self::ensure_can_withdraw(who, value, WithdrawReason::Reserve, new_balance)?; Self::set_reserved_balance(who, Self::reserved_balance(who) + value); - Self::set_free_balance(who, b - value); + Self::set_free_balance(who, new_balance); Ok(()) } - fn unreserve(who: &T::AccountId, value: Self::Balance) -> Option { + fn unreserve(who: &T::AccountId, value: Self::Balance) -> Self::Balance { let b = Self::reserved_balance(who); let actual = cmp::min(b, value); Self::set_free_balance(who, Self::free_balance(who) + actual); Self::set_reserved_balance(who, b - actual); - if actual == value { - None - } else { - Some(value - actual) - } + value - actual } - fn slash_reserved(who: &T::AccountId, value: Self::Balance) -> Option { + fn slash_reserved( + who: &T::AccountId, + value: Self::Balance + ) -> (Self::NegativeImbalance, Self::Balance) { let b = Self::reserved_balance(who); let slash = cmp::min(b, value); + // underflow should never happen, but it if does, there's nothing to be done here. Self::set_reserved_balance(who, b - slash); - Self::decrease_total_stake_by(slash); - if value == slash { - None - } else { - Some(value - slash) - } + (NegativeImbalance(slash), value - slash) } fn repatriate_reserved( slashed: &T::AccountId, beneficiary: &T::AccountId, - value: Self::Balance - ) -> result::Result, &'static str> { + value: Self::Balance, + ) -> result::Result { if Self::total_balance(beneficiary).is_zero() { return Err("beneficiary account must pre-exist"); } @@ -493,38 +907,100 @@ where let slash = cmp::min(b, value); Self::set_free_balance(beneficiary, Self::free_balance(beneficiary) + slash); Self::set_reserved_balance(slashed, b - slash); - if value == slash { - Ok(None) - } else { - Ok(Some(value - slash)) - } + Ok(value - slash) } } -impl TransferAsset for Module { - type Amount = T::Balance; +impl, I: Instance> LockableCurrency for Module +where + T::Balance: MaybeSerializeDebug +{ + type Moment = T::BlockNumber; - fn transfer(from: &T::AccountId, to: &T::AccountId, amount: T::Balance) -> Result { - Self::make_transfer(from, to, amount) + 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 = Self::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 remove_from(who: &T::AccountId, value: T::Balance) -> Result { - T::EnsureAccountLiquid::ensure_account_liquid(who)?; - let b = Self::free_balance(who); - ensure!(b >= value, "account has too few funds"); - Self::set_free_balance(who, b - value); - Self::decrease_total_stake_by(value); - Ok(()) + 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 = Self::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 add_to(who: &T::AccountId, value: T::Balance) -> Result { - Self::set_free_balance_creating(who, Self::free_balance(who) + value); - Self::increase_total_stake_by(value); + fn remove_lock( + id: LockIdentifier, + who: &T::AccountId, + ) { + let now = >::block_number(); + let locks = Self::locks(who).into_iter().filter_map(|l| + if l.until > now && l.id != id { + Some(l) + } else { + None + }).collect::>(); + >::insert(who, locks); + } +} + +impl, I: Instance> MakePayment for Module { + fn make_payment(transactor: &T::AccountId, encoded_len: usize) -> Result { + let encoded_len = >::sa(encoded_len as u64); + let transaction_fee = Self::transaction_base_fee() + Self::transaction_byte_fee() * encoded_len; + let imbalance = Self::withdraw( + transactor, + transaction_fee, + WithdrawReason::TransactionPayment, + ExistenceRequirement::KeepAlive + )?; + T::TransactionPayment::on_unbalanced(imbalance); Ok(()) } } -impl IsDeadAccount for Module +impl, I: Instance> IsDeadAccount for Module where T::Balance: MaybeSerializeDebug { @@ -532,3 +1008,4 @@ where Self::total_balance(who).is_zero() } } + diff --git a/srml/balances/src/mock.rs b/srml/balances/src/mock.rs index 6dcff18c6eb492d5768d6641b07737a02fac6a55..db20efc47566aec3e05e4e9e34b74627f8b30ae4 100644 --- a/srml/balances/src/mock.rs +++ b/srml/balances/src/mock.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -40,7 +40,7 @@ impl system::Trait for Runtime { type Hashing = ::primitives::traits::BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; @@ -49,11 +49,15 @@ impl Trait for Runtime { type Balance = u64; type OnFreeBalanceZero = (); type OnNewAccount = (); - type EnsureAccountLiquid = (); type Event = (); + type TransactionPayment = (); + type DustRemoval = (); + type TransferPayment = (); } pub struct ExtBuilder { + transaction_base_fee: u64, + transaction_byte_fee: u64, existential_deposit: u64, transfer_fee: u64, creation_fee: u64, @@ -63,6 +67,8 @@ pub struct ExtBuilder { impl Default for ExtBuilder { fn default() -> Self { Self { + transaction_base_fee: 0, + transaction_byte_fee: 0, existential_deposit: 0, transfer_fee: 0, creation_fee: 0, @@ -85,8 +91,16 @@ impl ExtBuilder { self.creation_fee = creation_fee; self } + pub fn transaction_fees(mut self, base_fee: u64, byte_fee: u64) -> Self { + self.transaction_base_fee = base_fee; + self.transaction_byte_fee = byte_fee; + self + } pub fn monied(mut self, monied: bool) -> Self { self.monied = monied; + if self.existential_deposit == 0 { + self.existential_deposit = 1; + } self } pub fn vesting(mut self, vesting: bool) -> Self { @@ -95,16 +109,13 @@ impl ExtBuilder { } pub fn build(self) -> runtime_io::TestExternalities { let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; - let balance_factor = if self.existential_deposit > 0 { - 256 - } else { - 1 - }; t.extend(GenesisConfig:: { + transaction_base_fee: self.transaction_base_fee, + transaction_byte_fee: self.transaction_byte_fee, balances: if self.monied { - vec![(1, 10 * balance_factor), (2, 20 * balance_factor), (3, 30 * balance_factor), (4, 40 * balance_factor)] + vec![(1, 10 * self.existential_deposit), (2, 20 * self.existential_deposit), (3, 30 * self.existential_deposit), (4, 40 * self.existential_deposit)] } else { - vec![(10, balance_factor), (20, balance_factor)] + vec![] }, existential_deposit: self.existential_deposit, transfer_fee: self.transfer_fee, diff --git a/srml/balances/src/tests.rs b/srml/balances/src/tests.rs index 8f6f87bcc5b91aa8ec862cf80ec38979bda474b9..89491fe5f80fc99b673d2c0643c355a03ca61d5f 100644 --- a/srml/balances/src/tests.rs +++ b/srml/balances/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -21,7 +21,137 @@ use super::*; use mock::{Balances, ExtBuilder, Runtime, System}; use runtime_io::with_externalities; -use srml_support::{assert_noop, assert_ok, assert_err}; +use srml_support::{ + assert_noop, assert_ok, assert_err, + traits::{LockableCurrency, LockIdentifier, WithdrawReason, WithdrawReasons, + Currency, MakePayment, ReservableCurrency} +}; + +const ID_1: LockIdentifier = *b"1 "; +const ID_2: LockIdentifier = *b"2 "; +const ID_3: LockIdentifier = *b"3 "; + +#[test] +fn basic_locking_should_work() { + with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + assert_eq!(Balances::free_balance(&1), 10); + Balances::set_lock(ID_1, &1, 9, u64::max_value(), WithdrawReasons::all()); + assert_noop!(>::transfer(&1, &2, 5), "account liquidity restrictions prevent withdrawal"); + }); +} + +#[test] +fn partial_locking_should_work() { + with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all()); + assert_ok!(>::transfer(&1, &2, 1)); + }); +} + +#[test] +fn lock_removal_should_work() { + with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + Balances::set_lock(ID_1, &1, u64::max_value(), u64::max_value(), WithdrawReasons::all()); + Balances::remove_lock(ID_1, &1); + assert_ok!(>::transfer(&1, &2, 1)); + }); +} + +#[test] +fn lock_replacement_should_work() { + with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + Balances::set_lock(ID_1, &1, u64::max_value(), u64::max_value(), WithdrawReasons::all()); + Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all()); + assert_ok!(>::transfer(&1, &2, 1)); + }); +} + +#[test] +fn double_locking_should_work() { + with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all()); + Balances::set_lock(ID_2, &1, 5, u64::max_value(), WithdrawReasons::all()); + assert_ok!(>::transfer(&1, &2, 1)); + }); +} + +#[test] +fn combination_locking_should_work() { + with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + Balances::set_lock(ID_1, &1, u64::max_value(), 0, WithdrawReasons::none()); + Balances::set_lock(ID_2, &1, 0, u64::max_value(), WithdrawReasons::none()); + Balances::set_lock(ID_3, &1, 0, 0, WithdrawReasons::all()); + assert_ok!(>::transfer(&1, &2, 1)); + }); +} + +#[test] +fn lock_value_extension_should_work() { + with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all()); + assert_noop!(>::transfer(&1, &2, 6), "account liquidity restrictions prevent withdrawal"); + Balances::extend_lock(ID_1, &1, 2, u64::max_value(), WithdrawReasons::all()); + assert_noop!(>::transfer(&1, &2, 6), "account liquidity restrictions prevent withdrawal"); + Balances::extend_lock(ID_1, &1, 8, u64::max_value(), WithdrawReasons::all()); + assert_noop!(>::transfer(&1, &2, 3), "account liquidity restrictions prevent withdrawal"); + }); +} + +#[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)); + + 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"); + }); +} + +#[test] +fn lock_block_number_should_work() { + with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + Balances::set_lock(ID_1, &1, 10, 2, WithdrawReasons::all()); + assert_noop!(>::transfer(&1, &2, 1), "account liquidity restrictions prevent withdrawal"); + + System::set_block_number(2); + assert_ok!(>::transfer(&1, &2, 1)); + }); +} + +#[test] +fn lock_block_number_extension_should_work() { + with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + Balances::set_lock(ID_1, &1, 10, 2, WithdrawReasons::all()); + assert_noop!(>::transfer(&1, &2, 6), "account liquidity restrictions prevent withdrawal"); + Balances::extend_lock(ID_1, &1, 10, 1, WithdrawReasons::all()); + assert_noop!(>::transfer(&1, &2, 6), "account liquidity restrictions prevent withdrawal"); + System::set_block_number(2); + Balances::extend_lock(ID_1, &1, 10, 8, WithdrawReasons::all()); + assert_noop!(>::transfer(&1, &2, 3), "account liquidity restrictions prevent withdrawal"); + }); +} + +#[test] +fn lock_reasons_extension_should_work() { + with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + Balances::set_lock(ID_1, &1, 10, 10, WithdrawReason::Transfer.into()); + assert_noop!(>::transfer(&1, &2, 6), "account liquidity restrictions prevent withdrawal"); + Balances::extend_lock(ID_1, &1, 10, 10, WithdrawReasons::none()); + assert_noop!(>::transfer(&1, &2, 6), "account liquidity restrictions prevent withdrawal"); + Balances::extend_lock(ID_1, &1, 10, 10, WithdrawReason::Reserve.into()); + assert_noop!(>::transfer(&1, &2, 6), "account liquidity restrictions prevent withdrawal"); + }); +} #[test] fn default_indexing_on_new_accounts_should_not_work2() { @@ -39,7 +169,7 @@ fn default_indexing_on_new_accounts_should_not_work2() { "value too low to create account" ); assert_eq!(Balances::is_dead_account(&5), true); // account 5 should not exist - assert_eq!(Balances::free_balance(&1), 256 * 10); + assert_eq!(Balances::free_balance(&1), 100); }, ); } @@ -67,7 +197,7 @@ fn reserved_balance_should_prevent_reclaim_count() { assert_eq!(Balances::total_balance(&5), 256 * 1 + 0x69); assert_eq!(Balances::is_dead_account(&5), false); - assert_eq!(Balances::slash(&2, 256 * 18 + 2), None); // account 2 gets slashed + 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 assert_eq!(System::account_nonce(&2), 0); // nonce zero assert_eq!(Balances::is_dead_account(&2), true); @@ -84,7 +214,7 @@ fn reserved_balance_should_prevent_reclaim_count() { fn reward_should_work() { with_externalities(&mut ExtBuilder::default().monied(true).build(), || { assert_eq!(Balances::total_balance(&1), 10); - assert_ok!(Balances::reward(&1, 10)); + assert_ok!(Balances::deposit_into_existing(&1, 10).map(drop)); assert_eq!(Balances::total_balance(&1), 20); assert_eq!(>::get(), 110); }); @@ -94,17 +224,17 @@ fn reward_should_work() { fn dust_account_removal_should_work() { with_externalities( &mut ExtBuilder::default() - .existential_deposit(256 * 10) + .existential_deposit(100) .monied(true) .build(), || { System::inc_account_nonce(&2); assert_eq!(System::account_nonce(&2), 1); - assert_eq!(Balances::total_balance(&2), 256 * 20); + assert_eq!(Balances::total_balance(&2), 2000); - assert_ok!(Balances::transfer(Some(2).into(), 5, 256 * 10 + 1)); // index 1 (account 2) becomes zombie + assert_ok!(Balances::transfer(Some(2).into(), 5, 1901)); // index 1 (account 2) becomes zombie assert_eq!(Balances::total_balance(&2), 0); - assert_eq!(Balances::total_balance(&5), 256 * 10 + 1); + assert_eq!(Balances::total_balance(&5), 1901); assert_eq!(System::account_nonce(&2), 0); }, ); @@ -114,17 +244,17 @@ fn dust_account_removal_should_work() { fn dust_account_removal_should_work2() { with_externalities( &mut ExtBuilder::default() - .existential_deposit(256 * 10) + .existential_deposit(100) .creation_fee(50) .monied(true) .build(), || { System::inc_account_nonce(&2); assert_eq!(System::account_nonce(&2), 1); - assert_eq!(Balances::total_balance(&2), 256 * 20); - assert_ok!(Balances::transfer(Some(2).into(), 5, 256 * 10)); // index 1 (account 2) becomes zombie for 256*10 + 50(fee) < 256 * 10 (ext_deposit) + 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) assert_eq!(Balances::total_balance(&2), 0); - assert_eq!(Balances::total_balance(&5), 256 * 10); + assert_eq!(Balances::total_balance(&5), 1851); assert_eq!(System::account_nonce(&2), 0); }, ); @@ -133,7 +263,7 @@ fn dust_account_removal_should_work2() { #[test] fn balance_works() { with_externalities(&mut ExtBuilder::default().build(), || { - Balances::set_free_balance(&1, 42); + let _ = Balances::deposit_creating(&1, 42); assert_eq!(Balances::free_balance(&1), 42); assert_eq!(Balances::reserved_balance(&1), 0); assert_eq!(Balances::total_balance(&1), 42); @@ -146,29 +276,17 @@ fn balance_works() { #[test] fn balance_transfer_works() { with_externalities(&mut ExtBuilder::default().build(), || { - Balances::set_free_balance(&1, 111); - Balances::increase_total_stake_by(111); + let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::transfer(Some(1).into(), 2, 69)); assert_eq!(Balances::total_balance(&1), 42); assert_eq!(Balances::total_balance(&2), 69); }); } -#[test] -fn balance_reduction_works() { - with_externalities(&mut ExtBuilder::default().build(), || { - Balances::set_free_balance(&1, 111); - Balances::increase_total_stake_by(111); - assert_ok!(Balances::decrease_free_balance(&1, 69).map(|_| ())); - assert_eq!(Balances::total_balance(&1), 42); - assert_noop!(Balances::decrease_free_balance(&1, 69).map(|_| ()), "account has too few funds"); - }); -} - #[test] fn reserving_balance_should_work() { with_externalities(&mut ExtBuilder::default().build(), || { - Balances::set_free_balance(&1, 111); + let _ = Balances::deposit_creating(&1, 111); assert_eq!(Balances::total_balance(&1), 111); assert_eq!(Balances::free_balance(&1), 111); @@ -185,7 +303,7 @@ fn reserving_balance_should_work() { #[test] fn balance_transfer_when_reserved_should_not_work() { with_externalities(&mut ExtBuilder::default().build(), || { - Balances::set_free_balance(&1, 111); + let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 69)); assert_noop!(Balances::transfer(Some(1).into(), 2, 69), "balance too low to send value"); }); @@ -194,7 +312,7 @@ fn balance_transfer_when_reserved_should_not_work() { #[test] fn deducting_balance_should_work() { with_externalities(&mut ExtBuilder::default().build(), || { - Balances::set_free_balance(&1, 111); + let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 69)); assert_eq!(Balances::free_balance(&1), 42); }); @@ -203,7 +321,7 @@ fn deducting_balance_should_work() { #[test] fn refunding_balance_should_work() { with_externalities(&mut ExtBuilder::default().build(), || { - Balances::set_free_balance(&1, 42); + let _ = Balances::deposit_creating(&1, 42); Balances::set_reserved_balance(&1, 69); Balances::unreserve(&1, 69); assert_eq!(Balances::free_balance(&1), 111); @@ -214,33 +332,31 @@ fn refunding_balance_should_work() { #[test] fn slashing_balance_should_work() { with_externalities(&mut ExtBuilder::default().build(), || { - Balances::set_free_balance(&1, 111); - Balances::increase_total_stake_by(111); + let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 69)); - assert!(Balances::slash(&1, 69).is_none()); + assert!(Balances::slash(&1, 69).1.is_zero()); assert_eq!(Balances::free_balance(&1), 0); assert_eq!(Balances::reserved_balance(&1), 42); - assert_eq!(>::get(), 44); + assert_eq!(>::get(), 42); }); } #[test] fn slashing_incomplete_balance_should_work() { with_externalities(&mut ExtBuilder::default().build(), || { - Balances::set_free_balance(&1, 42); - Balances::increase_total_stake_by(42); + let _ = Balances::deposit_creating(&1, 42); assert_ok!(Balances::reserve(&1, 21)); - assert!(Balances::slash(&1, 69).is_some()); + assert_eq!(Balances::slash(&1, 69).1, 27); assert_eq!(Balances::free_balance(&1), 0); assert_eq!(Balances::reserved_balance(&1), 0); - assert_eq!(>::get(), 2); + assert_eq!(>::get(), 0); }); } #[test] fn unreserving_balance_should_work() { with_externalities(&mut ExtBuilder::default().build(), || { - Balances::set_free_balance(&1, 111); + let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 111)); Balances::unreserve(&1, 42); assert_eq!(Balances::reserved_balance(&1), 69); @@ -251,36 +367,34 @@ fn unreserving_balance_should_work() { #[test] fn slashing_reserved_balance_should_work() { with_externalities(&mut ExtBuilder::default().build(), || { - Balances::set_free_balance(&1, 111); - Balances::increase_total_stake_by(111); + let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 111)); - assert!(Balances::slash_reserved(&1, 42).is_none()); + assert_eq!(Balances::slash_reserved(&1, 42).1, 0); assert_eq!(Balances::reserved_balance(&1), 69); assert_eq!(Balances::free_balance(&1), 0); - assert_eq!(>::get(), 71); + assert_eq!(>::get(), 69); }); } #[test] fn slashing_incomplete_reserved_balance_should_work() { with_externalities(&mut ExtBuilder::default().build(), || { - Balances::set_free_balance(&1, 111); - Balances::increase_total_stake_by(111); + let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 42)); - assert!(Balances::slash_reserved(&1, 69).is_some()); + assert_eq!(Balances::slash_reserved(&1, 69).1, 27); assert_eq!(Balances::free_balance(&1), 69); assert_eq!(Balances::reserved_balance(&1), 0); - assert_eq!(>::get(), 71); + assert_eq!(>::get(), 69); }); } #[test] fn transferring_reserved_balance_should_work() { with_externalities(&mut ExtBuilder::default().build(), || { - Balances::set_free_balance(&1, 110); - Balances::set_free_balance(&2, 1); + let _ = Balances::deposit_creating(&1, 110); + let _ = Balances::deposit_creating(&2, 1); assert_ok!(Balances::reserve(&1, 110)); - assert_ok!(Balances::repatriate_reserved(&1, &2, 41), None); + assert_ok!(Balances::repatriate_reserved(&1, &2, 41), 0); assert_eq!(Balances::reserved_balance(&1), 69); assert_eq!(Balances::free_balance(&1), 0); assert_eq!(Balances::reserved_balance(&2), 0); @@ -291,7 +405,7 @@ fn transferring_reserved_balance_should_work() { #[test] fn transferring_reserved_balance_to_nonexistent_should_fail() { with_externalities(&mut ExtBuilder::default().build(), || { - Balances::set_free_balance(&1, 111); + let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 111)); assert_noop!(Balances::repatriate_reserved(&1, &2, 42), "beneficiary account must pre-exist"); }); @@ -300,10 +414,10 @@ fn transferring_reserved_balance_to_nonexistent_should_fail() { #[test] fn transferring_incomplete_reserved_balance_should_work() { with_externalities(&mut ExtBuilder::default().build(), || { - Balances::set_free_balance(&1, 110); - Balances::set_free_balance(&2, 1); + let _ = Balances::deposit_creating(&1, 110); + let _ = Balances::deposit_creating(&2, 1); assert_ok!(Balances::reserve(&1, 41)); - assert!(Balances::repatriate_reserved(&1, &2, 69).unwrap().is_some()); + assert_ok!(Balances::repatriate_reserved(&1, &2, 69), 28); assert_eq!(Balances::reserved_balance(&1), 0); assert_eq!(Balances::free_balance(&1), 69); assert_eq!(Balances::reserved_balance(&2), 0); @@ -327,32 +441,62 @@ fn transferring_too_high_value_should_not_panic() { }); } +#[test] +fn account_create_on_free_too_low_with_other() { + with_externalities( + &mut ExtBuilder::default().existential_deposit(100).build(), + || { + let _ = Balances::deposit_creating(&1, 100); + assert_eq!(>::get(), 100); + + // No-op. + let _ = Balances::deposit_creating(&2, 50); + assert_eq!(Balances::free_balance(&2), 0); + assert_eq!(>::get(), 100); + } + ) +} + + +#[test] +fn account_create_on_free_too_low() { + with_externalities( + &mut ExtBuilder::default().existential_deposit(100).build(), + || { + // No-op. + let _ = Balances::deposit_creating(&2, 50); + assert_eq!(Balances::free_balance(&2), 0); + assert_eq!(>::get(), 0); + } + ) +} + #[test] fn account_removal_on_free_too_low() { with_externalities( &mut ExtBuilder::default().existential_deposit(100).build(), || { - // Setup two accounts with free balance above the exsistential threshold. - { - Balances::set_free_balance(&1, 110); - Balances::increase_total_stake_by(110); + assert_eq!(>::get(), 0); - Balances::set_free_balance(&2, 110); - Balances::increase_total_stake_by(110); + // Setup two accounts with free balance above the existential threshold. + let _ = Balances::deposit_creating(&1, 110); + let _ = Balances::deposit_creating(&2, 110); - assert_eq!(>::get(), 732); - } + assert_eq!(Balances::free_balance(&1), 110); + assert_eq!(Balances::free_balance(&2), 110); + assert_eq!(>::get(), 220); // Transfer funds from account 1 of such amount that after this transfer - // the balance of account 1 will be below the exsistential threshold. + // the balance of account 1 will be below the existential threshold. // This should lead to the removal of all balance of this account. assert_ok!(Balances::transfer(Some(1).into(), 2, 20)); // Verify free balance removal of account 1. assert_eq!(Balances::free_balance(&1), 0); + assert_eq!(Balances::free_balance(&2), 130); // Verify that TotalIssuance tracks balance removal when free balance is too low. - assert_eq!(>::get(), 642); + assert_eq!(>::get(), 130); }, ); } @@ -377,7 +521,7 @@ fn transfer_overflow_isnt_exploitable() { fn check_vesting_status() { with_externalities( &mut ExtBuilder::default() - .existential_deposit(10) + .existential_deposit(256) .monied(true) .vesting(true) .build(), @@ -427,10 +571,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, 256 * 10); // Account 1 has free balance - assert_eq!(Balances::vesting_balance(&1), user1_free_balance - 256); // Account 1 has only 256 units vested at block 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_noop!( - Balances::transfer(Some(1).into(), 2, 256 * 2), + Balances::transfer(Some(1).into(), 2, 11), "vesting balance too high to send value" ); // Account 1 cannot send more than vested amount } @@ -446,13 +590,11 @@ fn vested_balance_should_transfer() { .vesting(true) .build(), || { - System::set_block_number(5); - assert_eq!(System::block_number(), 5); + assert_eq!(System::block_number(), 1); let user1_free_balance = Balances::free_balance(&1); - assert_eq!(user1_free_balance, 256 * 10); // Account 1 has free balance - - assert_eq!(Balances::vesting_balance(&1), user1_free_balance - 256 * 5); // Account 1 has 256 * 5 units vested at block 5 - assert_ok!(Balances::transfer(Some(1).into(), 2, 256 * 2)); // Account 1 can now send vested value + 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)); } ); } @@ -467,12 +609,12 @@ fn extra_balance_should_transfer() { .build(), || { assert_eq!(System::block_number(), 1); - assert_ok!(Balances::transfer(Some(3).into(), 1, 256 * 10)); + assert_ok!(Balances::transfer(Some(3).into(), 1, 100)); let user1_free_balance = Balances::free_balance(&1); - assert_eq!(user1_free_balance, 256 * 20); // Account 1 has 2560 more free balance than normal + assert_eq!(user1_free_balance, 200); // Account 1 has 100 more free balance than normal - assert_eq!(Balances::vesting_balance(&1), 256 * 10 - 256); // Account 1 has 256 units vested at block 1 - assert_ok!(Balances::transfer(Some(1).into(), 2, 256 * 5)); // Account 1 can send extra units gained + 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 } ); -} \ No newline at end of file +} diff --git a/srml/consensus/Cargo.toml b/srml/consensus/Cargo.toml index c9b2e391af417e66fdfefa4f51862b55db6155d9..6adeb90d0248cd34f5701e46509a8e4e8dc38ea2 100644 --- a/srml/consensus/Cargo.toml +++ b/srml/consensus/Cargo.toml @@ -6,10 +6,9 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", default-features = false, features = ["derive"] } substrate-primitives = { path = "../../core/primitives", default-features = false } inherents = { package = "substrate-inherents", path = "../../core/inherents", default-features = false } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } @@ -23,7 +22,7 @@ runtime_io = { package = "sr-io", path = "../../core/sr-io" } [features] default = ["std"] std = [ - "serde/std", + "serde", "serde_derive", "parity-codec/std", "substrate-primitives/std", diff --git a/srml/consensus/src/lib.rs b/srml/consensus/src/lib.rs index aacda649975dd337371586c826abd8dc0f2f748e..985a32bd6c3b6bb7b25c0bc96815121da87427a5 100644 --- a/srml/consensus/src/lib.rs +++ b/srml/consensus/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -22,8 +22,7 @@ use serde_derive::Serialize; use rstd::prelude::*; use parity_codec as codec; -use codec::Encode; -use parity_codec_derive::{Encode, Decode}; +use codec::{Encode, Decode}; use srml_support::{storage, Parameter, decl_storage, decl_module}; use srml_support::storage::StorageValue; use srml_support::storage::unhashed::StorageVec; @@ -35,7 +34,7 @@ use inherents::{ }; #[cfg(any(feature = "std", test))] -use substrate_primitives::Ed25519AuthorityId; +use substrate_primitives::ed25519::Public as AuthorityId; mod mock; mod tests; @@ -52,6 +51,7 @@ impl StorageVec for AuthorityStorageVec { const PREFIX: &'static [u8] = well_known_keys::AUTHORITY_PREFIX; } +pub type Key = Vec; pub type KeyValue = (Vec, Vec); /// Handling offline validator reports in a generic way. @@ -136,7 +136,7 @@ impl RawLog { // Implementation for tests outside of this crate. #[cfg(any(feature = "std", test))] -impl From> for primitives::testing::DigestItem where N: Into { +impl From> for primitives::testing::DigestItem where N: Into { fn from(log: RawLog) -> primitives::testing::DigestItem { match log { RawLog::AuthoritiesChange(authorities) => @@ -217,6 +217,13 @@ decl_module! { } } + /// Kill some items from storage. + fn kill_storage(keys: Vec) { + for key in &keys { + storage::unhashed::kill(&key); + } + } + fn on_finalise() { if let Some(original_authorities) = >::take() { let current_authorities = AuthorityStorageVec::::items(); @@ -245,6 +252,12 @@ impl Module { } } + /// Set a single authority by index. + pub fn set_authority_count(count: u32) { + Self::save_original_authorities(None); + AuthorityStorageVec::::set_count(count); + } + /// Set a single authority by index. pub fn set_authority(index: u32, key: &T::SessionKey) { let current_authority = AuthorityStorageVec::::item(index); diff --git a/srml/consensus/src/mock.rs b/srml/consensus/src/mock.rs index 0cdf4ef2c615aa519714de92a03f0581e7fa3437..85e6dc365411608c348732950756d77626d165d3 100644 --- a/srml/consensus/src/mock.rs +++ b/srml/consensus/src/mock.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -44,7 +44,7 @@ impl system::Trait for Test { type Hashing = ::primitives::traits::BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; diff --git a/srml/consensus/src/tests.rs b/srml/consensus/src/tests.rs index d883a897f113b8d2692a5c5b76a40f71d90bb867..0145094a7674d90c131bfa749cfb49b8ae894a18 100644 --- a/srml/consensus/src/tests.rs +++ b/srml/consensus/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -83,3 +83,28 @@ fn offline_report_can_be_excluded() { assert!(Consensus::create_inherent(&data).is_some()); }); } + +#[test] +fn set_and_kill_storage_work() { + use srml_support::storage; + + with_externalities(&mut new_test_ext(vec![1, 2, 3]), || { + System::initialise(&1, &Default::default(), &Default::default()); + + let item = (vec![42u8], vec![42u8]); + + Consensus::set_storage(vec![item.clone()]).unwrap(); + + assert_eq!( + storage::unhashed::get_raw(&item.0), + Some(item.1), + ); + + Consensus::kill_storage(vec![item.0.clone()]).unwrap(); + + assert_eq!( + storage::unhashed::get_raw(&item.0), + None, + ); + }); +} diff --git a/srml/contract/Cargo.toml b/srml/contract/Cargo.toml index 380662768113926b83facf8b7f02746464a19295..ae91f6632d69b0be8ca269efcebc2515bab0cbd4 100644 --- a/srml/contract/Cargo.toml +++ b/srml/contract/Cargo.toml @@ -5,11 +5,10 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } pwasm-utils = { version = "0.6.1", default-features = false } -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", default-features = false, features = ["derive"] } parity-wasm = { version = "0.31", default-features = false } substrate-primitives = { path = "../../core/primitives", default-features = false } runtime-primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } @@ -18,33 +17,29 @@ rstd = { package = "sr-std", path = "../../core/sr-std", default-features = fals sandbox = { package = "sr-sandbox", path = "../../core/sr-sandbox", 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 } timestamp = { package = "srml-timestamp", path = "../timestamp", default-features = false } -fees = { package = "srml-fees", path = "../fees", default-features = false } [dev-dependencies] wabt = "~0.7.4" assert_matches = "1.1" hex-literal = "0.1.0" consensus = { package = "srml-consensus", path = "../consensus" } +balances = { package = "srml-balances", path = "../balances" } [features] default = ["std"] std = [ - "serde/std", + "serde", "serde_derive", "parity-codec/std", - "parity-codec-derive/std", "substrate-primitives/std", "runtime-primitives/std", "runtime-io/std", "rstd/std", - "balances/std", "sandbox/std", "srml-support/std", "system/std", "timestamp/std", "parity-wasm/std", "pwasm-utils/std", - "fees/std", ] diff --git a/srml/contract/src/account_db.rs b/srml/contract/src/account_db.rs index 17249f7db39a7d53fd4668951c86e4235d92d592..6b5142b6c82ed658aedb97d5812bc1a85a17ce26 100644 --- a/srml/contract/src/account_db.rs +++ b/srml/contract/src/account_db.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -16,15 +16,18 @@ //! Auxilliaries to help with managing partial changes to accounts state. -use super::{CodeHash, CodeHashOf, StorageOf, Trait}; -use {balances, system}; +use super::{CodeHash, CodeHashOf, Trait, AccountInfo, TrieId, AccountInfoOf, BalanceOf}; +use system; use rstd::cell::RefCell; +use rstd::rc::Rc; use rstd::collections::btree_map::{BTreeMap, Entry}; use rstd::prelude::*; -use srml_support::{StorageMap, StorageDoubleMap, traits::UpdateBalanceOutcome}; +use runtime_primitives::traits::Zero; +use srml_support::{StorageMap, traits::{UpdateBalanceOutcome, + SignedImbalance, Currency, Imbalance}, storage::child}; pub struct ChangeEntry { - balance: Option, + balance: Option>, /// In the case the outer option is None, the code_hash remains untouched, while providing `Some(None)` signifies a removing of the code in question code: Option>>, storage: BTreeMap, Option>>, @@ -43,33 +46,87 @@ impl Default for ChangeEntry { pub type ChangeSet = BTreeMap<::AccountId, ChangeEntry>; +#[derive(Clone, Default)] +pub struct AccountTrieIdMapping { + to_account: BTreeMap, + to_key: BTreeMap, + // this lock is related to the way overlaydb stack + // if set it must be unset at the lower level + lock: bool, +} + +impl AccountTrieIdMapping { + + pub fn new() -> Self { + AccountTrieIdMapping { + to_account: BTreeMap::new(), + to_key: BTreeMap::new(), + lock: false, + } + } + + pub fn lock(&mut self) { + self.lock = true; + } + pub fn unlock(&mut self) { + self.lock = false; + } + pub fn insert(&mut self, account: A, ks: TrieId) { + self.to_account.insert(ks.clone(), account.clone()); + self.to_key.insert(account, ks); + } + pub fn get_trieid(&self, account: &A) -> Option<&TrieId> { + if self.lock { return None } + self.to_key.get(account) + } + pub fn get_account(&self, ks: &TrieId) -> Option<&A> { + if self.lock { return None } + self.to_account.get(ks) + } + +} + pub trait AccountDb { - fn get_storage(&self, account: &T::AccountId, location: &[u8]) -> Option>; + fn get_account_info(&self, account: &T::AccountId) -> Option; + fn get_or_create_trieid(&self, account: &T::AccountId) -> TrieId; + fn get_storage(&self, trie_id: &TrieId, location: &[u8]) -> Option>; fn get_code(&self, account: &T::AccountId) -> Option>; - fn get_balance(&self, account: &T::AccountId) -> T::Balance; + fn get_balance(&self, account: &T::AccountId) -> BalanceOf; fn commit(&mut self, change_set: ChangeSet); } pub struct DirectAccountDb; impl AccountDb for DirectAccountDb { - fn get_storage(&self, account: &T::AccountId, location: &[u8]) -> Option> { - >::get(account, &location.to_vec()) + fn get_account_info(&self, account: &T::AccountId) -> Option { + let res: Option = AccountInfoOf::::get(account); + res + } + fn get_or_create_trieid(&self, account: &T::AccountId) -> TrieId { + use super::TrieIdGenerator; + >::get_account_info(self, account) + .map(|s|s.trie_id) + .unwrap_or_else(||::TrieIdGenerator::trie_id(account)) + } + fn get_storage(&self, trie_id: &TrieId, location: &[u8]) -> Option> { + child::get_raw(trie_id, location) } fn get_code(&self, account: &T::AccountId) -> Option> { >::get(account) } - fn get_balance(&self, account: &T::AccountId) -> T::Balance { - balances::Module::::free_balance(account) + fn get_balance(&self, account: &T::AccountId) -> BalanceOf { + T::Currency::free_balance(account) } fn commit(&mut self, s: ChangeSet) { + let mut total_imbalance = SignedImbalance::zero(); for (address, changed) in s.into_iter() { + let trieid = >::get_or_create_trieid(&self, &address); if let Some(balance) = changed.balance { - if let UpdateBalanceOutcome::AccountKilled = - balances::Module::::set_free_balance_creating(&address, balance) - { + let (imbalance, outcome) = T::Currency::make_free_balance_be(&address, balance); + total_imbalance = total_imbalance.merge(imbalance); + if let UpdateBalanceOutcome::AccountKilled = outcome { // Account killed. This will ultimately lead to calling `OnFreeBalanceZero` callback - // which will make removal of CodeHashOf and StorageOf for this account. + // which will make removal of CodeHashOf and AccountStorage for this account. // In order to avoid writing over the deleted properties we `continue` here. continue; } @@ -83,27 +140,48 @@ impl AccountDb for DirectAccountDb { } for (k, v) in changed.storage.into_iter() { if let Some(value) = v { - >::insert(&address, &k, value); + child::put_raw(&trieid[..], &k, &value[..]); } else { - >::remove(&address, &k); + child::kill(&trieid[..], &k); } } } + + match total_imbalance { + // If we've detected a positive imbalance as a result of our contract-level machinations + // then it's indicative of a buggy contracts system. + // Panicking is far from ideal as it opens up a DoS attack on block validators, however + // it's a less bad option than allowing arbitrary value to be created. + SignedImbalance::Positive(ref p) if !p.peek().is_zero() => + panic!("contract subsystem resulting in positive imbalance!"), + _ => {} + } } } - pub struct OverlayAccountDb<'a, T: Trait + 'a> { local: RefCell>, + trie_account: Rc::AccountId>>>, + trie_account_cache: bool, underlying: &'a AccountDb, } impl<'a, T: Trait> OverlayAccountDb<'a, T> { - pub fn new(underlying: &'a AccountDb) -> OverlayAccountDb<'a, T> { + pub fn new( + underlying: &'a AccountDb, + trie_account: Rc::AccountId>>>, + trie_account_cache: bool, + ) -> OverlayAccountDb<'a, T> { OverlayAccountDb { local: RefCell::new(ChangeSet::new()), + trie_account, + trie_account_cache, underlying, } } + pub fn reg_cache_new_rc(&self) -> Rc::AccountId>>> { + self.trie_account.clone() + } + pub fn into_change_set(self) -> ChangeSet { self.local.into_inner() } @@ -114,13 +192,13 @@ impl<'a, T: Trait> OverlayAccountDb<'a, T> { location: Vec, value: Option>, ) { - self.local - .borrow_mut() + self.local.borrow_mut() .entry(account.clone()) .or_insert(Default::default()) .storage .insert(location, value); } + pub fn set_code(&mut self, account: &T::AccountId, code: Option>) { self.local .borrow_mut() @@ -128,7 +206,7 @@ impl<'a, T: Trait> OverlayAccountDb<'a, T> { .or_insert(Default::default()) .code = Some(code); } - pub fn set_balance(&mut self, account: &T::AccountId, balance: T::Balance) { + pub fn set_balance(&mut self, account: &T::AccountId, balance: BalanceOf) { self.local .borrow_mut() .entry(account.clone()) @@ -138,13 +216,39 @@ impl<'a, T: Trait> OverlayAccountDb<'a, T> { } impl<'a, T: Trait> AccountDb for OverlayAccountDb<'a, T> { - fn get_storage(&self, account: &T::AccountId, location: &[u8]) -> Option> { - self.local + fn get_account_info(&self, account: &T::AccountId) -> Option { + let v = self.underlying.get_account_info(account); + if self.trie_account_cache { + v.as_ref().map(|v|self.trie_account.as_ref().borrow_mut().insert(account.clone(), v.trie_id.clone())); + } + v + } + fn get_or_create_trieid(&self, account: &T::AccountId) -> TrieId { + if self.trie_account_cache { + let mut ka_mut = self.trie_account.as_ref().borrow_mut(); + if let Some(v) = ka_mut.get_trieid(account) { + v.clone() + } else { + ka_mut.unlock(); + let v = self.underlying.get_or_create_trieid(account); + ka_mut.insert(account.clone(), v.clone()); + v + } + } else { + let res = self.trie_account.as_ref().borrow().get_trieid(account).map(|v|v.clone()); + res.unwrap_or_else(|| { + self.trie_account.as_ref().borrow_mut().lock(); + self.underlying.get_or_create_trieid(account) + }) + } + } + fn get_storage(&self, ks: &TrieId, location: &[u8]) -> Option> { + self.trie_account.as_ref().borrow().get_account(ks).and_then(|account| self.local .borrow() - .get(account) + .get(&account) .and_then(|a| a.storage.get(location)) .cloned() - .unwrap_or_else(|| self.underlying.get_storage(account, location)) + .unwrap_or_else(|| self.underlying.get_storage(ks, location))) } fn get_code(&self, account: &T::AccountId) -> Option> { self.local @@ -153,7 +257,7 @@ impl<'a, T: Trait> AccountDb for OverlayAccountDb<'a, T> { .and_then(|a| a.code.clone()) .unwrap_or_else(|| self.underlying.get_code(account)) } - fn get_balance(&self, account: &T::AccountId) -> T::Balance { + fn get_balance(&self, account: &T::AccountId) -> BalanceOf { self.local .borrow() .get(account) diff --git a/srml/contract/src/exec.rs b/srml/contract/src/exec.rs index 046d1075337aa48bc6905b85bccd648e7511687b..6c04a2e1d0a1f992b172f7096481c96fcdda93b1 100644 --- a/srml/contract/src/exec.rs +++ b/srml/contract/src/exec.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -14,16 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use super::{CodeHash, Config, ContractAddressFor, Event, RawEvent, Trait}; -use crate::account_db::{AccountDb, DirectAccountDb, OverlayAccountDb}; +use super::{CodeHash, Config, ContractAddressFor, Event, RawEvent, Trait, TrieId, BalanceOf}; +use crate::account_db::{AccountDb, DirectAccountDb, OverlayAccountDb, AccountTrieIdMapping}; use crate::gas::{GasMeter, Token, approx_gas_for_balance}; use rstd::prelude::*; +use rstd::cell::RefCell; +use rstd::rc::Rc; use runtime_primitives::traits::{CheckedAdd, CheckedSub, Zero}; +use srml_support::traits::{WithdrawReason, Currency}; use timestamp; -use srml_support::traits::EnsureAccountLiquid; -pub type BalanceOf = ::Balance; pub type AccountIdOf = ::AccountId; pub type CallOf = ::Call; pub type MomentOf = ::Moment; @@ -225,6 +226,7 @@ impl Token for ExecFeeToken { pub struct ExecutionContext<'a, T: Trait + 'a, V, L> { pub self_account: T::AccountId, + pub self_trieid: TrieId, pub overlay: OverlayAccountDb<'a, T>, pub depth: usize, pub events: Vec>, @@ -244,9 +246,11 @@ where /// /// The specified `origin` address will be used as `sender` for pub fn top_level(origin: T::AccountId, cfg: &'a Config, vm: &'a V, loader: &'a L) -> Self { - let overlay = OverlayAccountDb::::new(&DirectAccountDb); + let overlay = OverlayAccountDb::::new(&DirectAccountDb, Rc::new(RefCell::new(AccountTrieIdMapping::new())), true); + let self_trieid = overlay.get_or_create_trieid(&origin); ExecutionContext { self_account: origin, + self_trieid, depth: 0, overlay, events: Vec::new(), @@ -258,9 +262,11 @@ where } fn nested(&self, overlay: OverlayAccountDb<'a, T>, dest: T::AccountId) -> Self { + let self_trieid = overlay.get_or_create_trieid(&dest); ExecutionContext { - overlay: overlay, + overlay, self_account: dest, + self_trieid, depth: self.depth + 1, events: Vec::new(), calls: Vec::new(), @@ -274,7 +280,7 @@ where pub fn call( &mut self, dest: T::AccountId, - value: T::Balance, + value: BalanceOf, gas_meter: &mut GasMeter, input_data: &[u8], empty_output_buf: EmptyOutputBuf, @@ -295,11 +301,11 @@ where let (change_set, events, calls) = { let mut nested = self.nested( - OverlayAccountDb::new(&self.overlay), + OverlayAccountDb::new(&self.overlay, self.overlay.reg_cache_new_rc(), false), dest.clone() ); - if value > T::Balance::zero() { + if value > BalanceOf::::zero() { transfer( gas_meter, TransferCause::Call, @@ -342,7 +348,7 @@ where pub fn instantiate( &mut self, - endowment: T::Balance, + endowment: BalanceOf, gas_meter: &mut GasMeter, code_hash: &CodeHash, input_data: &[u8], @@ -370,7 +376,8 @@ where } let (change_set, events, calls) = { - let mut overlay = OverlayAccountDb::new(&self.overlay); + let mut overlay = OverlayAccountDb::new(&self.overlay, self.overlay.reg_cache_new_rc(), false); + overlay.set_code(&dest, Some(code_hash.clone())); let mut nested = self.nested(overlay, dest.clone()); @@ -431,7 +438,7 @@ pub struct TransferFeeToken { gas_price: Balance, } -impl Token for TransferFeeToken { +impl Token for TransferFeeToken> { type Metadata = Config; #[inline] @@ -460,7 +467,7 @@ enum TransferCause { /// (transfering endowment) or because of a transfer via `call`. This /// is specified using the `cause` parameter. /// -/// NOTE: that the fee is denominated in `T::Balance` units, but +/// NOTE: that the fee is denominated in `BalanceOf` units, but /// charged in `T::Gas` from the provided `gas_meter`. This means /// that the actual amount charged might differ. /// @@ -472,7 +479,7 @@ fn transfer<'a, T: Trait, V: Vm, L: Loader>( cause: TransferCause, transactor: &T::AccountId, dest: &T::AccountId, - value: T::Balance, + value: BalanceOf, ctx: &mut ExecutionContext<'a, T, V, L>, ) -> Result<(), &'static str> { use self::TransferCause::*; @@ -520,7 +527,7 @@ fn transfer<'a, T: Trait, V: Vm, L: Loader>( if would_create && value < ctx.config.existential_deposit { return Err("value too low to create account"); } - ::EnsureAccountLiquid::ensure_account_liquid(transactor)?; + T::Currency::ensure_can_withdraw(transactor, value, WithdrawReason::Transfer, new_from_balance)?; let new_to_balance = match to_balance.checked_add(&value) { Some(b) => b, @@ -540,7 +547,7 @@ fn transfer<'a, T: Trait, V: Vm, L: Loader>( struct CallContext<'a, 'b: 'a, T: Trait + 'b, V: Vm + 'b, L: Loader> { ctx: &'a mut ExecutionContext<'b, T, V, L>, caller: T::AccountId, - value_transferred: T::Balance, + value_transferred: BalanceOf, timestamp: T::Moment, random_seed: T::Hash, } @@ -554,7 +561,7 @@ where type T = T; fn get_storage(&self, key: &[u8]) -> Option> { - self.ctx.overlay.get_storage(&self.ctx.self_account, key) + self.ctx.overlay.get_storage(&self.ctx.self_trieid, key) } fn set_storage(&mut self, key: &[u8], value: Option>) { @@ -566,7 +573,7 @@ where fn instantiate( &mut self, code_hash: &CodeHash, - endowment: T::Balance, + endowment: BalanceOf, gas_meter: &mut GasMeter, input_data: &[u8], ) -> Result>, &'static str> { @@ -576,7 +583,7 @@ where fn call( &mut self, to: &T::AccountId, - value: T::Balance, + value: BalanceOf, gas_meter: &mut GasMeter, input_data: &[u8], empty_output_buf: EmptyOutputBuf, @@ -600,11 +607,11 @@ where &self.caller } - fn balance(&self) -> T::Balance { + fn balance(&self) -> BalanceOf { self.ctx.overlay.get_balance(&self.ctx.self_account) } - fn value_transferred(&self) -> T::Balance { + fn value_transferred(&self) -> BalanceOf { self.value_transferred } @@ -639,9 +646,9 @@ mod tests { use crate::{CodeHash, Config}; use runtime_io::with_externalities; use std::cell::RefCell; + use std::rc::Rc; use std::collections::HashMap; use std::marker::PhantomData; - use std::rc::Rc; use assert_matches::assert_matches; const ALICE: u64 = 1; diff --git a/srml/contract/src/gas.rs b/srml/contract/src/gas.rs index 0c9b422a67ba2a9205797e631cb80c55494ca92d..54199042bccb8ff9507d73b065c595c5c406c89f 100644 --- a/srml/contract/src/gas.rs +++ b/srml/contract/src/gas.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -14,11 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use crate::{GasSpent, Module, Trait}; -use balances; +use crate::{GasSpent, Module, Trait, BalanceOf, NegativeImbalanceOf}; use runtime_primitives::BLOCK_FULL; use runtime_primitives::traits::{As, CheckedMul, CheckedSub, Zero}; -use srml_support::StorageValue; +use srml_support::{StorageValue, traits::{OnUnbalanced, ExistenceRequirement, WithdrawReason, Currency, Imbalance}}; #[cfg(test)] use std::{any::Any, fmt::Debug}; @@ -83,14 +82,14 @@ pub struct GasMeter { limit: T::Gas, /// Amount of gas left from initial gas limit. Can reach zero. gas_left: T::Gas, - gas_price: T::Balance, + gas_price: BalanceOf, #[cfg(test)] tokens: Vec, } impl GasMeter { #[cfg(test)] - pub fn with_limit(gas_limit: T::Gas, gas_price: T::Balance) -> GasMeter { + pub fn with_limit(gas_limit: T::Gas, gas_price: BalanceOf) -> GasMeter { GasMeter { limit: gas_limit, gas_left: gas_limit, @@ -175,7 +174,7 @@ impl GasMeter { } } - pub fn gas_price(&self) -> T::Balance { + pub fn gas_price(&self) -> BalanceOf { self.gas_price } @@ -202,7 +201,7 @@ impl GasMeter { pub fn buy_gas( transactor: &T::AccountId, gas_limit: T::Gas, -) -> Result, &'static str> { +) -> 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(); @@ -213,47 +212,54 @@ pub fn buy_gas( // Buy the specified amount of gas. let gas_price = >::gas_price(); - let b = >::free_balance(transactor); - let cost = >::as_(gas_limit.clone()) + let cost = >>::as_(gas_limit.clone()) .checked_mul(&gas_price) .ok_or("overflow multiplying gas limit by price")?; - let new_balance = b.checked_sub(&cost); - if new_balance < Some(>::existential_deposit()) { - return Err("not enough funds for transaction fee"); - } + let imbalance = T::Currency::withdraw( + transactor, + cost, + WithdrawReason::Fee, + ExistenceRequirement::KeepAlive + )?; - >::set_free_balance(transactor, b - cost); - >::decrease_total_stake_by(cost); - Ok(GasMeter { + Ok((GasMeter { limit: gas_limit, gas_left: gas_limit, gas_price, + #[cfg(test)] tokens: Vec::new(), - }) + }, imbalance)) } /// Refund the unused gas. -pub fn refund_unused_gas(transactor: &T::AccountId, gas_meter: GasMeter) { +pub fn refund_unused_gas( + transactor: &T::AccountId, + gas_meter: GasMeter, + imbalance: NegativeImbalanceOf, +) { + let gas_spent = gas_meter.spent(); + let gas_left = gas_meter.gas_left(); + // Increase total spent gas. // This cannot overflow, since `gas_spent` is never greater than `block_gas_limit`, which // also has T::Gas type. - let gas_spent = >::gas_spent() + gas_meter.spent(); - >::put(gas_spent); + >::mutate(|block_gas_spent| *block_gas_spent += gas_spent); // Refund gas left by the price it was bought. - let b = >::free_balance(transactor); - let refund = >::as_(gas_meter.gas_left) * gas_meter.gas_price; - >::set_free_balance(transactor, b + refund); - >::increase_total_stake_by(refund); + let refund = >>::as_(gas_left) * gas_meter.gas_price; + let refund_imbalance = T::Currency::deposit_creating(transactor, refund); + if let Ok(imbalance) = imbalance.offset(refund_imbalance) { + T::GasPayment::on_unbalanced(imbalance); + } } /// A little handy utility for converting a value in balance units into approximitate value in gas units /// at the given gas price. -pub fn approx_gas_for_balance(gas_price: T::Balance, balance: T::Balance) -> T::Gas { - let amount_in_gas: T::Balance = balance / gas_price; - >::sa(amount_in_gas) +pub fn approx_gas_for_balance(gas_price: BalanceOf, balance: BalanceOf) -> T::Gas { + let amount_in_gas: BalanceOf = balance / gas_price; + >>::sa(amount_in_gas) } /// A simple utility macro that helps to match against a diff --git a/srml/contract/src/lib.rs b/srml/contract/src/lib.rs index 90cccfce79868ac7bf2a502861790aa8391692d1..63b425eba453ced74fa827fe48b09ea2bffe706d 100644 --- a/srml/contract/src/lib.rs +++ b/srml/contract/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -63,27 +63,26 @@ mod wasm; mod tests; use crate::exec::ExecutionContext; -use crate::account_db::AccountDb; +use crate::account_db::{AccountDb, DirectAccountDb}; #[cfg(feature = "std")] use serde_derive::{Serialize, Deserialize}; +use substrate_primitives::crypto::UncheckedFrom; use rstd::prelude::*; use rstd::marker::PhantomData; -use parity_codec::{Codec, Encode}; -use parity_codec_derive::{Encode, Decode}; +use parity_codec::{Codec, Encode, Decode}; use runtime_primitives::traits::{Hash, As, SimpleArithmetic,Bounded, StaticLookup}; use srml_support::dispatch::{Result, Dispatchable}; -use srml_support::{Parameter, StorageMap, StorageValue, StorageDoubleMap, decl_module, decl_event, decl_storage}; -use srml_support::traits::OnFreeBalanceZero; +use srml_support::{Parameter, StorageMap, StorageValue, decl_module, decl_event, decl_storage, storage::child}; +use srml_support::traits::{OnFreeBalanceZero, OnUnbalanced, Currency}; use system::{ensure_signed, RawOrigin}; -use runtime_io::{blake2_256, twox_128}; use timestamp; -use fees; pub type CodeHash = ::Hash; +pub type TrieId = Vec; /// A function that generates an `AccountId` for a contract upon instantiation. -pub trait ContractAddressFor { +pub trait ContractAddressFor { fn contract_address_for(code_hash: &CodeHash, data: &[u8], origin: &AccountId) -> AccountId; } @@ -92,7 +91,54 @@ pub trait ComputeDispatchFee { fn compute_dispatch_fee(call: &Call) -> Balance; } -pub trait Trait: fees::Trait + balances::Trait + timestamp::Trait { +#[derive(Encode,Decode,Clone,Debug)] +/// Information for managing an acocunt and its sub trie abstraction. +/// This is the required info to cache for an account +pub struct AccountInfo { + /// unique ID for the subtree encoded as a byte + pub trie_id: TrieId, + /// the size of stored value in octet + pub current_mem_stored: u64, +} + +/// Get a trie id (trie id must be unique and collision resistant depending upon its context) +/// Note that it is different than encode because trie id should have collision resistance +/// property (being a proper uniqueid). +pub trait TrieIdGenerator { + /// get a trie id for an account, using reference to parent account trie id to ensure + /// uniqueness of trie id + /// The implementation must ensure every new trie id is unique: two consecutive call with the + /// same parameter needs to return different trie id values. + fn trie_id(account_id: &AccountId) -> TrieId; +} + +/// Get trie id from `account_id` +pub struct TrieIdFromParentCounter(PhantomData); + +/// This generator use inner counter for account id and apply hash over `AccountId + +/// accountid_counter` +impl TrieIdGenerator for TrieIdFromParentCounter +where + T::AccountId: AsRef<[u8]> +{ + 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| v.wrapping_add(1)); + + let mut buf = Vec::new(); + buf.extend_from_slice(account_id.as_ref()); + buf.extend_from_slice(&new_seed.to_le_bytes()[..]); + T::Hashing::hash(&buf[..]).as_ref().into() + } +} + +pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +pub type NegativeImbalanceOf = <::Currency as Currency<::AccountId>>::NegativeImbalance; + +pub trait Trait: timestamp::Trait { + type Currency: Currency; + /// The outer call dispatch type. type Call: Parameter + Dispatchable::Origin>; @@ -100,7 +146,7 @@ pub trait Trait: fees::Trait + balances::Trait + timestamp::Trait { type Event: From> + Into<::Event>; // As is needed for wasm-utils - type Gas: Parameter + Default + Codec + SimpleArithmetic + Bounded + Copy + As + As + As; + type Gas: Parameter + Default + Codec + SimpleArithmetic + Bounded + Copy + As> + As + As; /// A function type to get the contract address given the creator. type DetermineContractAddress: ContractAddressFor, Self::AccountId>; @@ -109,7 +155,13 @@ pub trait Trait: fees::Trait + balances::Trait + timestamp::Trait { /// /// It is recommended (though not required) for this function to return a fee that would be taken /// by executive module for regular dispatch. - type ComputeDispatchFee: ComputeDispatchFee::Balance>; + type ComputeDispatchFee: ComputeDispatchFee>; + + /// trieid id generator + type TrieIdGenerator: TrieIdGenerator; + + /// Handler for the unbalanced reduction when making a gas payment. + type GasPayment: OnUnbalanced>; } /// Simple contract address determintator. @@ -121,7 +173,7 @@ pub trait Trait: fees::Trait + balances::Trait + timestamp::Trait { pub struct SimpleAddressDeterminator(PhantomData); impl ContractAddressFor, T::AccountId> for SimpleAddressDeterminator where - T::AccountId: From + AsRef<[u8]> + T::AccountId: UncheckedFrom + AsRef<[u8]> { fn contract_address_for(code_hash: &CodeHash, data: &[u8], origin: &T::AccountId) -> T::AccountId { let data_hash = T::Hashing::hash(data); @@ -131,19 +183,19 @@ where buf.extend_from_slice(data_hash.as_ref()); buf.extend_from_slice(origin.as_ref()); - T::Hashing::hash(&buf[..]).into() + UncheckedFrom::unchecked_from(T::Hashing::hash(&buf[..])) } } /// The default dispatch fee computor computes the fee in the same way that -/// implementation of `ChargeBytesFee` for fees module does. +/// implementation of `MakePayment` for balances module does. pub struct DefaultDispatchFeeComputor(PhantomData); -impl ComputeDispatchFee for DefaultDispatchFeeComputor { - fn compute_dispatch_fee(call: &T::Call) -> T::Balance { +impl ComputeDispatchFee> for DefaultDispatchFeeComputor { + fn compute_dispatch_fee(call: &T::Call) -> BalanceOf { let encoded_len = call.using_encoded(|encoded| encoded.len()); - let base_fee = >::transaction_base_fee(); - let byte_fee = >::transaction_byte_fee(); - >::sa(base_fee.as_() + byte_fee.as_() * encoded_len as u64) + let base_fee = >::transaction_base_fee(); + let byte_fee = >::transaction_byte_fee(); + base_fee + byte_fee * as As>::sa(encoded_len as u64) } } @@ -175,14 +227,14 @@ decl_module! { let origin = ensure_signed(origin)?; let schedule = >::current_schedule(); - let mut gas_meter = gas::buy_gas::(&origin, gas_limit)?; + let (mut gas_meter, imbalance) = gas::buy_gas::(&origin, gas_limit)?; let result = wasm::save_code::(code, &mut gas_meter, &schedule); if let Ok(code_hash) = result { Self::deposit_event(RawEvent::CodeStored(code_hash)); } - gas::refund_unused_gas::(&origin, gas_meter); + gas::refund_unused_gas::(&origin, gas_meter, imbalance); result.map(|_| ()) } @@ -191,7 +243,7 @@ decl_module! { fn call( origin, dest: ::Source, - #[compact] value: T::Balance, + #[compact] value: BalanceOf, #[compact] gas_limit: T::Gas, data: Vec ) -> Result { @@ -202,7 +254,7 @@ decl_module! { // // NOTE: it is very important to avoid any state changes before // paying for the gas. - let mut gas_meter = gas::buy_gas::(&origin, gas_limit)?; + let (mut gas_meter, imbalance) = gas::buy_gas::(&origin, gas_limit)?; let cfg = Config::preload(); let vm = crate::wasm::WasmVm::new(&cfg.schedule); @@ -213,7 +265,7 @@ decl_module! { if let Ok(_) = result { // Commit all changes that made it thus far into the persistant storage. - account_db::DirectAccountDb.commit(ctx.overlay.into_change_set()); + DirectAccountDb.commit(ctx.overlay.into_change_set()); // Then deposit all events produced. ctx.events.into_iter().for_each(Self::deposit_event); @@ -223,7 +275,7 @@ decl_module! { // // NOTE: this should go after the commit to the storage, since the storage changes // can alter the balance of the caller. - gas::refund_unused_gas::(&origin, gas_meter); + gas::refund_unused_gas::(&origin, gas_meter, imbalance); // Dispatch every recorded call with an appropriate origin. ctx.calls.into_iter().for_each(|(who, call)| { @@ -234,7 +286,7 @@ decl_module! { result.map(|_| ()) } - /// Create a new contract, optionally transfering some balance to the created account. + /// Create a new contract, optionally transferring some balance to the created account. /// /// Creation is executed as follows: /// @@ -245,7 +297,7 @@ decl_module! { /// upon any message received by this account. fn create( origin, - #[compact] endowment: T::Balance, + #[compact] endowment: BalanceOf, #[compact] gas_limit: T::Gas, code_hash: CodeHash, data: Vec @@ -256,7 +308,7 @@ decl_module! { // // NOTE: it is very important to avoid any state changes before // paying for the gas. - let mut gas_meter = gas::buy_gas::(&origin, gas_limit)?; + let (mut gas_meter, imbalance) = gas::buy_gas::(&origin, gas_limit)?; let cfg = Config::preload(); let vm = crate::wasm::WasmVm::new(&cfg.schedule); @@ -266,7 +318,7 @@ decl_module! { if let Ok(_) = result { // Commit all changes that made it thus far into the persistant storage. - account_db::DirectAccountDb.commit(ctx.overlay.into_change_set()); + DirectAccountDb.commit(ctx.overlay.into_change_set()); // Then deposit all events produced. ctx.events.into_iter().for_each(Self::deposit_event); @@ -276,7 +328,7 @@ decl_module! { // // NOTE: this should go after the commit to the storage, since the storage changes // can alter the balance of the caller. - gas::refund_unused_gas::(&origin, gas_meter); + gas::refund_unused_gas::(&origin, gas_meter, imbalance); // Dispatch every recorded call with an appropriate origin. ctx.calls.into_iter().for_each(|(who, call)| { @@ -296,7 +348,7 @@ decl_module! { decl_event! { pub enum Event where - ::Balance, + Balance = BalanceOf, ::AccountId, ::Hash { @@ -320,14 +372,22 @@ decl_event! { decl_storage! { trait Store for Module as Contract { - /// The fee required to create a contract. At least as big as staking's ReclaimRebate. - ContractFee get(contract_fee) config(): T::Balance = T::Balance::sa(21); + /// 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. + ContractFee get(contract_fee) config(): BalanceOf = BalanceOf::::sa(21); /// The fee charged for a call into a contract. CallBaseFee get(call_base_fee) config(): T::Gas = T::Gas::sa(135); /// The fee charged for a create of a contract. CreateBaseFee get(create_base_fee) config(): T::Gas = T::Gas::sa(175); /// The price of one unit of gas. - GasPrice get(gas_price) config(): T::Balance = T::Balance::sa(1); + GasPrice get(gas_price) config(): BalanceOf = BalanceOf::::sa(1); /// 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. @@ -342,34 +402,19 @@ decl_storage! { pub PristineCode: map CodeHash => Option>; /// A mapping between an original code hash and instrumented wasm code, ready for the execution. pub CodeStorage: map CodeHash => Option; - } -} - -/// The storage items associated with an account/key. -/// -pub(crate) struct StorageOf(rstd::marker::PhantomData); -impl StorageDoubleMap for StorageOf { - const PREFIX: &'static [u8] = b"con:sto:"; - type Key1 = T::AccountId; - type Key2 = Vec; - type Value = Vec; - - /// Hashed by XX - fn derive_key1(key1_data: Vec) -> Vec { - twox_128(&key1_data).to_vec() - } - - /// Blake2 is used for `Key2` is because it will be used as a key for contract's storage and - /// thus will be susceptible for a untrusted input. - fn derive_key2(key2_data: Vec) -> Vec { - blake2_256(&key2_data).to_vec() + /// The subtrie counter + pub AccountCounter: u64 = 0; + /// The code associated with a given account. + pub AccountInfoOf: map T::AccountId => Option; } } impl OnFreeBalanceZero for Module { fn on_free_balance_zero(who: &T::AccountId) { >::remove(who); - >::remove_prefix(who); + >::get_account_info(&DirectAccountDb, who).map(|subtrie| { + child::kill_storage(&subtrie.trie_id); + }); } } @@ -379,11 +424,11 @@ impl OnFreeBalanceZero for Module { /// course of transaction execution. pub struct Config { pub schedule: Schedule, - pub existential_deposit: T::Balance, + pub existential_deposit: BalanceOf, pub max_depth: u32, - pub contract_account_instantiate_fee: T::Balance, - pub account_create_fee: T::Balance, - pub transfer_fee: T::Balance, + 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, } @@ -392,11 +437,11 @@ impl Config { fn preload() -> Config { Config { schedule: >::current_schedule(), - existential_deposit: >::existential_deposit(), + 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(), + account_create_fee: >::creation_fee(), + transfer_fee: >::transfer_fee(), call_base_fee: >::call_base_fee(), instantiate_base_fee: >::create_base_fee(), } diff --git a/srml/contract/src/tests.rs b/srml/contract/src/tests.rs index 1d1141c2f4acf8b93d005cf2414c2b07f4b17472..36b98098b0e207eb717e5c4b1f4ac708ee19c2f8 100644 --- a/srml/contract/src/tests.rs +++ b/srml/contract/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -24,17 +24,21 @@ use runtime_primitives::testing::{Digest, DigestItem, H256, Header, UintAuthorit use runtime_primitives::traits::{BlakeTwo256, IdentityLookup}; use runtime_primitives::BuildStorage; use runtime_io; -use srml_support::{StorageMap, StorageDoubleMap, assert_ok, impl_outer_event, impl_outer_dispatch, impl_outer_origin}; -use substrate_primitives::{Blake2Hasher}; +use srml_support::{storage::child, StorageMap, assert_ok, impl_outer_event, impl_outer_dispatch, + impl_outer_origin, traits::Currency}; +use substrate_primitives::Blake2Hasher; use system::{self, Phase, EventRecord}; -use fees; use {wabt, balances, consensus}; use hex_literal::*; use assert_matches::assert_matches; use crate::{ - ContractAddressFor, GenesisConfig, Module, RawEvent, StorageOf, - Trait, ComputeDispatchFee + ContractAddressFor, GenesisConfig, Module, RawEvent, + Trait, ComputeDispatchFee, TrieIdGenerator, TrieId, + AccountInfo, AccountInfoOf, }; +use substrate_primitives::storage::well_known_keys; +use parity_codec::{Encode, Decode, KeyedVec}; +use std::sync::atomic::{AtomicUsize, Ordering}; mod contract { // Re-export contents of the root. This basically @@ -45,7 +49,7 @@ mod contract { } impl_outer_event! { pub enum MetaEvent for Test { - balances, contract, fees, + balances, contract, } } impl_outer_origin! { @@ -68,7 +72,7 @@ impl system::Trait for Test { type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = MetaEvent; type Log = DigestItem; @@ -77,8 +81,10 @@ impl balances::Trait for Test { type Balance = u64; type OnFreeBalanceZero = Contract; type OnNewAccount = (); - type EnsureAccountLiquid = (); type Event = MetaEvent; + type TransactionPayment = (); + type DustRemoval = (); + type TransferPayment = (); } impl timestamp::Trait for Test { type Moment = u64; @@ -89,16 +95,15 @@ impl consensus::Trait for Test { type SessionKey = UintAuthorityId; type InherentOfflineReport = (); } -impl fees::Trait for Test { - type Event = MetaEvent; - type TransferAsset = Balances; -} 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 Balances = balances::Module; @@ -112,6 +117,17 @@ impl ContractAddressFor for DummyContractAddressFor { } } +static KEY_COUNTER: AtomicUsize = AtomicUsize::new(0); + +pub struct DummyTrieIdGenerator; +impl TrieIdGenerator for DummyTrieIdGenerator { + fn trie_id(account_id: &u64) -> TrieId { + let mut res = KEY_COUNTER.fetch_add(1, Ordering::Relaxed).to_le_bytes().to_vec(); + res.extend_from_slice(&account_id.to_le_bytes()); + res + } +} + pub struct DummyComputeDispatchFee; impl ComputeDispatchFee for DummyComputeDispatchFee { fn compute_dispatch_fee(call: &Call) -> u64 { @@ -169,6 +185,8 @@ impl ExtBuilder { .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, @@ -181,6 +199,10 @@ impl ExtBuilder { ); t.extend( GenesisConfig:: { + transaction_base_fee: 0, + transaction_byte_fee: 0, + transfer_fee: self.transfer_fee, + creation_fee: self.creation_fee, contract_fee: 21, call_base_fee: 135, create_base_fee: 175, @@ -200,8 +222,7 @@ impl ExtBuilder { #[test] fn refunds_unused_gas() { with_externalities(&mut ExtBuilder::default().build(), || { - Balances::set_free_balance(&0, 100_000_000); - Balances::increase_total_stake_by(100_000_000); + Balances::deposit_creating(&0, 100_000_000); assert_ok!(Contract::call( Origin::signed(0), @@ -217,20 +238,29 @@ fn refunds_unused_gas() { #[test] fn account_removal_removes_storage() { + let unique_id1 = b"unique_id1"; + let unique_id2 = b"unique_id2"; with_externalities( &mut ExtBuilder::default().existential_deposit(100).build(), || { // Setup two accounts with free balance above than exsistential threshold. { - Balances::set_free_balance(&1, 110); - Balances::increase_total_stake_by(110); - >::insert(&1, &b"foo".to_vec(), b"1".to_vec()); - >::insert(&1, &b"bar".to_vec(), b"2".to_vec()); - - Balances::set_free_balance(&2, 110); - Balances::increase_total_stake_by(110); - >::insert(&2, &b"hello".to_vec(), b"3".to_vec()); - >::insert(&2, &b"world".to_vec(), b"4".to_vec()); + Balances::deposit_creating(&1, 110); + AccountInfoOf::::insert(1, &AccountInfo { + trie_id: unique_id1.to_vec(), + current_mem_stored: 0, + }); + child::put(&unique_id1[..], &b"foo".to_vec(), &b"1".to_vec()); + assert_eq!(child::get(&unique_id1[..], &b"foo".to_vec()), Some(b"1".to_vec())); + child::put(&unique_id1[..], &b"bar".to_vec(), &b"2".to_vec()); + + Balances::deposit_creating(&2, 110); + AccountInfoOf::::insert(2, &AccountInfo { + trie_id: unique_id2.to_vec(), + current_mem_stored: 0, + }); + child::put(&unique_id2[..], &b"hello".to_vec(), &b"3".to_vec()); + child::put(&unique_id2[..], &b"world".to_vec(), &b"4".to_vec()); } // Transfer funds from account 1 of such amount that after this transfer @@ -242,15 +272,15 @@ fn account_removal_removes_storage() { // Verify that all entries from account 1 is removed, while // entries from account 2 is in place. { - assert_eq!(>::get(&1, &b"foo".to_vec()), None); - assert_eq!(>::get(&1, &b"bar".to_vec()), None); + assert_eq!(child::get_raw(&unique_id1[..], &b"foo".to_vec()), None); + assert_eq!(child::get_raw(&unique_id1[..], &b"bar".to_vec()), None); assert_eq!( - >::get(&2, &b"hello".to_vec()), + child::get(&unique_id2[..], &b"hello".to_vec()), Some(b"3".to_vec()) ); assert_eq!( - >::get(&2, &b"world".to_vec()), + child::get(&unique_id2[..], &b"world".to_vec()), Some(b"4".to_vec()) ); } @@ -289,8 +319,7 @@ fn instantiate_and_call() { with_externalities( &mut ExtBuilder::default().existential_deposit(100).build(), || { - Balances::set_free_balance(&ALICE, 1_000_000); - Balances::increase_total_stake_by(1_000_000); + Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contract::put_code( Origin::signed(ALICE), @@ -307,6 +336,10 @@ fn instantiate_and_call() { )); assert_eq!(System::events(), vec![ + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::balances(balances::RawEvent::NewAccount(1, 1_000_000)), + }, EventRecord { phase: Phase::ApplyExtrinsic(0), event: MetaEvent::contract(RawEvent::CodeStored(HASH_RETURN_FROM_START_FN.into())), @@ -360,8 +393,7 @@ fn dispatch_call() { with_externalities( &mut ExtBuilder::default().existential_deposit(50).build(), || { - Balances::set_free_balance(&ALICE, 1_000_000); - Balances::increase_total_stake_by(1_000_000); + Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contract::put_code( Origin::signed(ALICE), @@ -372,6 +404,10 @@ fn dispatch_call() { // 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)), + }, EventRecord { phase: Phase::ApplyExtrinsic(0), event: MetaEvent::contract(RawEvent::CodeStored(HASH_DISPATCH_CALL.into())), @@ -395,6 +431,10 @@ fn dispatch_call() { )); assert_eq!(System::events(), vec![ + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::balances(balances::RawEvent::NewAccount(1, 1_000_000)), + }, EventRecord { phase: Phase::ApplyExtrinsic(0), event: MetaEvent::contract(RawEvent::CodeStored(HASH_DISPATCH_CALL.into())), diff --git a/srml/contract/src/wasm/code_cache.rs b/srml/contract/src/wasm/code_cache.rs index 195da157451528237abd6cae111e1d21b4cc41ea..dab8c4bfa4b04a7ab931688affb74ff807e24af2 100644 --- a/srml/contract/src/wasm/code_cache.rs +++ b/srml/contract/src/wasm/code_cache.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/srml/contract/src/wasm/env_def/macros.rs b/srml/contract/src/wasm/env_def/macros.rs index 27485d55ce9c7c9f099473cccad572f7cd3b3a39..0b112a825858d06b45760ec6c60c67821486fdc5 100644 --- a/srml/contract/src/wasm/env_def/macros.rs +++ b/srml/contract/src/wasm/env_def/macros.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/srml/contract/src/wasm/env_def/mod.rs b/srml/contract/src/wasm/env_def/mod.rs index 65e9e14e6796209e4aff9615b5df0b7e8c95fc01..d51a157910d5c2c46470913ada843d0dd19f881c 100644 --- a/srml/contract/src/wasm/env_def/mod.rs +++ b/srml/contract/src/wasm/env_def/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/srml/contract/src/wasm/mod.rs b/srml/contract/src/wasm/mod.rs index 5348df1ad38430283a3e1a0301e8f39e497c6485..04428280d05bb3f3f4af9068b79d52190f5aa396 100644 --- a/srml/contract/src/wasm/mod.rs +++ b/srml/contract/src/wasm/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -23,7 +23,7 @@ use crate::exec::{Ext, EmptyOutputBuf, VmExecResult}; use crate::gas::GasMeter; use rstd::prelude::*; -use parity_codec_derive::{Encode, Decode}; +use parity_codec::{Encode, Decode}; use sandbox; #[macro_use] @@ -580,7 +580,7 @@ mod tests { /// calls `ext_caller`, loads the address from the scratch buffer and /// compares it with the constant 42. - const CODE_CALLER: &'static str = r#" + const CODE_CALLER: &str = r#" (module (import "env" "ext_caller" (func $ext_caller)) (import "env" "ext_scratch_size" (func $ext_scratch_size (result i32))) @@ -645,7 +645,7 @@ mod tests { /// calls `ext_address`, loads the address from the scratch buffer and /// compares it with the constant 69. - const CODE_ADDRESS: &'static str = r#" + const CODE_ADDRESS: &str = r#" (module (import "env" "ext_address" (func $ext_address)) (import "env" "ext_scratch_size" (func $ext_scratch_size (result i32))) diff --git a/srml/contract/src/wasm/prepare.rs b/srml/contract/src/wasm/prepare.rs index 12f4c7d2838cc971e80ea2b07f5495b91e3a779c..52f1580aa9fecb4c71c13a37d017f20e71e46f05 100644 --- a/srml/contract/src/wasm/prepare.rs +++ b/srml/contract/src/wasm/prepare.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/srml/contract/src/wasm/runtime.rs b/srml/contract/src/wasm/runtime.rs index 9f515ee84e4a6910a005eb74833d2fe183ebd6c6..b4a963f93192e891f16577f8f063aa2ac03787c9 100644 --- a/srml/contract/src/wasm/runtime.rs +++ b/srml/contract/src/wasm/runtime.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -16,8 +16,8 @@ //! Environment definition of the wasm smart-contract runtime. -use crate::{Schedule, Trait, CodeHash, ComputeDispatchFee}; -use crate::exec::{Ext, BalanceOf, VmExecResult, OutputBuf, EmptyOutputBuf, CallReceipt, InstantiateReceipt}; +use crate::{Schedule, Trait, CodeHash, ComputeDispatchFee, BalanceOf}; +use crate::exec::{Ext, VmExecResult, OutputBuf, EmptyOutputBuf, CallReceipt, InstantiateReceipt}; use crate::gas::{GasMeter, Token, GasMeterResult, approx_gas_for_balance}; use sandbox; use system; diff --git a/srml/council/Cargo.toml b/srml/council/Cargo.toml index 5d21d9eecd46ff1314b07e47382d647ea0ee3479..e26003a73e4f13c62e9c9ab85891cb1d22a2fd79 100644 --- a/srml/council/Cargo.toml +++ b/srml/council/Cargo.toml @@ -5,10 +5,10 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false} -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", default-features = false } +parity-codec-derive = { version = "3.1", default-features = false } 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 } @@ -29,6 +29,7 @@ std = [ "parity-codec-derive/std", "substrate-primitives/std", "rstd/std", + "serde", "runtime_io/std", "srml-support/std", "primitives/std", diff --git a/srml/council/src/lib.rs b/srml/council/src/lib.rs index 20c95b2bd9ff4d196211be83ba06ce437ac7cc37..a13eb7e28067ac66a8ac95ee5c8d2a63f5d85ff1 100644 --- a/srml/council/src/lib.rs +++ b/srml/council/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -67,7 +67,7 @@ mod tests { type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = Event; type Log = DigestItem; @@ -76,8 +76,10 @@ mod tests { type Balance = u64; type OnFreeBalanceZero = (); type OnNewAccount = (); - type EnsureAccountLiquid = (); type Event = Event; + type TransactionPayment = (); + type TransferPayment = (); + type DustRemoval = (); } impl democracy::Trait for Test { type Currency = balances::Module; @@ -86,6 +88,8 @@ mod tests { } impl seats::Trait for Test { type Event = Event; + type BadPresentation = (); + type BadReaper = (); } impl motions::Trait for Test { type Origin = Origin; @@ -99,6 +103,8 @@ mod tests { pub fn new_test_ext(with_council: bool) -> 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![(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)], existential_deposit: 0, transfer_fee: 0, diff --git a/srml/council/src/motions.rs b/srml/council/src/motions.rs index a2636c728a3f517deec27c5279d2f4813b5ec317..3bbe463780c46f910947209e0b45e66f23391e74 100644 --- a/srml/council/src/motions.rs +++ b/srml/council/src/motions.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -47,7 +47,6 @@ pub enum Origin { Members(u32), } -/// Event for this module. decl_event!( pub enum Event where ::Hash, ::AccountId { /// A motion (given hash) has been proposed (by given account) with a threshold (given u32). diff --git a/srml/council/src/seats.rs b/srml/council/src/seats.rs index 27a22bbf471339a3a59ebfe198fae992e7c19f7f..867efe4ca186eea450211b1fc054d3f20d46f1a7 100644 --- a/srml/council/src/seats.rs +++ b/srml/council/src/seats.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -19,7 +19,10 @@ use rstd::prelude::*; use primitives::traits::{Zero, One, As, StaticLookup}; use runtime_io::print; -use srml_support::{StorageValue, StorageMap, dispatch::Result, traits::Currency, decl_storage, decl_event, ensure}; +use srml_support::{ + StorageValue, StorageMap, dispatch::Result, decl_storage, decl_event, ensure, + traits::{Currency, ReservableCurrency, OnUnbalanced} +}; use democracy; use system::{self, ensure_signed}; @@ -77,14 +80,21 @@ use system::{self, ensure_signed}; // after each vote as all but K entries are cleared. newly registering candidates must use cleared // entries before they increase the capacity. -use srml_support::{decl_module, traits::ArithmeticType}; +use srml_support::decl_module; pub type VoteIndex = u32; -type BalanceOf = <::Currency as ArithmeticType>::Type; +type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +type NegativeImbalanceOf = <::Currency as Currency<::AccountId>>::NegativeImbalance; 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>; } decl_module! { @@ -101,7 +111,7 @@ decl_module! { ensure!(index == Self::vote_index(), "incorrect vote index"); ensure!(!candidates.len().is_zero(), "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 otherise an attacker may be able to submit a very long list of `votes` that far exceeds + // 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 approval votes cannot exceed amount of candidates"); @@ -167,7 +177,8 @@ decl_module! { T::Currency::repatriate_reserved(&who, &reporter, Self::voting_bond())?; Self::deposit_event(RawEvent::VoterReaped(who, reporter)); } else { - T::Currency::slash_reserved(&reporter, Self::voting_bond()); + let imbalance = T::Currency::slash_reserved(&reporter, Self::voting_bond()).0; + T::BadReaper::on_unbalanced(imbalance); Self::deposit_event(RawEvent::BadReaperSlashed(reporter)); } } @@ -266,7 +277,8 @@ decl_module! { } else { // we can rest assured it will be Ok since we checked `can_slash` earlier; still // better safe than sorry. - let _ = T::Currency::slash(&who, bad_presentation_punishment); + let imbalance = T::Currency::slash(&who, bad_presentation_punishment).0; + T::BadPresentation::on_unbalanced(imbalance); Err(if dupe { "duplicate presentation" } else { "incorrect total" }) } } @@ -370,7 +382,6 @@ decl_storage! { } decl_event!( - /// An event in this module. pub enum Event where ::AccountId { /// reaped voter, reaper VoterReaped(AccountId, AccountId), diff --git a/srml/council/src/voting.rs b/srml/council/src/voting.rs index 17ab4adc7fdfbb2d6933f73d98d95caeb75c093d..4c5c62dc838b5dc015c93e8c5f8bc548b013f885 100644 --- a/srml/council/src/voting.rs +++ b/srml/council/src/voting.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -117,7 +117,7 @@ decl_storage! { pub VotingPeriod get(voting_period) config(): T::BlockNumber = T::BlockNumber::sa(3); /// Number of blocks by which to delay enactment of successful, non-unanimous-council-instigated referendum proposals. pub EnactDelayPeriod get(enact_delay_period) config(): T::BlockNumber = T::BlockNumber::sa(0); - pub Proposals get(proposals) build(|_| vec![0u8; 0]): Vec<(T::BlockNumber, T::Hash)>; // ordered by expiry. + pub Proposals get(proposals) build(|_| vec![]): Vec<(T::BlockNumber, T::Hash)>; // ordered by expiry. pub ProposalOf get(proposal_of): map T::Hash => Option; pub ProposalVoters get(proposal_voters): map T::Hash => Vec; pub CouncilVoteOf get(vote_of): map (T::Hash, T::AccountId) => Option; @@ -125,7 +125,6 @@ decl_storage! { } } -/// An event in this module. decl_event!( pub enum Event where ::Hash { /// A voting tally has happened for a referendum cancellation vote. diff --git a/srml/democracy/Cargo.toml b/srml/democracy/Cargo.toml index 74d0f764b45c6e984a9462ae62c57c2fdab1316e..890882c485a1022ac0bb76920a3c85c45fd0b8c0 100644 --- a/srml/democracy/Cargo.toml +++ b/srml/democracy/Cargo.toml @@ -6,11 +6,10 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false} -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", 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 } @@ -24,7 +23,7 @@ balances = { package = "srml-balances", path = "../balances" } [features] default = ["std"] std = [ - "serde/std", + "serde", "serde_derive", "safe-mix/std", "parity-codec/std", diff --git a/srml/democracy/src/lib.rs b/srml/democracy/src/lib.rs index 539aa4227b0014ba27e94cb325051792dcb7540a..c6e87e29c427699f31b29cdd401c6824736c5a36 100644 --- a/srml/democracy/src/lib.rs +++ b/srml/democracy/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -20,17 +20,19 @@ use rstd::prelude::*; use rstd::result; -use primitives::traits::{Zero, As}; -use parity_codec_derive::{Encode, Decode}; -use srml_support::{StorageValue, StorageMap, Parameter, Dispatchable, IsSubType}; +use primitives::traits::{Zero, As, Bounded}; +use parity_codec::{Encode, Decode}; +use srml_support::{StorageValue, StorageMap, Parameter, Dispatchable, IsSubType, EnumerableStorageMap}; use srml_support::{decl_module, decl_storage, decl_event, ensure}; -use srml_support::traits::{Currency, OnFreeBalanceZero, EnsureAccountLiquid, ArithmeticType}; +use srml_support::traits::{Currency, ReservableCurrency, LockableCurrency, WithdrawReason, LockIdentifier}; use srml_support::dispatch::Result; use system::ensure_signed; mod vote_threshold; pub use vote_threshold::{Approved, VoteThreshold}; +const DEMOCRACY_ID: LockIdentifier = *b"democrac"; + /// A proposal index. pub type PropIndex = u32; /// A referendum index. @@ -38,6 +40,8 @@ pub type ReferendumIndex = u32; /// A number of lock periods. pub type LockPeriods = i8; +const MAX_RECURSION_LIMIT: u32 = 16; + /// A number of lock periods, plus a vote, one way or the other. #[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Default)] #[cfg_attr(feature = "std", derive(Debug))] @@ -65,10 +69,10 @@ impl Vote { } } -type BalanceOf = <::Currency as ArithmeticType>::Type; +type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; pub trait Trait: system::Trait + Sized { - type Currency: ArithmeticType + Currency<::AccountId, Balance=BalanceOf>; + type Currency: ReservableCurrency + LockableCurrency; type Proposal: Parameter + Dispatchable + IsSubType>; @@ -154,6 +158,22 @@ decl_module! { runtime_io::print(e); } } + + /// Delegate vote. + pub fn delegate(origin, to: T::AccountId, lock_periods: LockPeriods) -> Result { + let who = ensure_signed(origin)?; + >::insert(who.clone(), (to.clone(), lock_periods.clone())); + Self::deposit_event(RawEvent::Delegated(who, to)); + Ok(()) + } + + /// Undelegate vote. + fn undelegate(origin) -> Result { + let who = ensure_signed(origin)?; + >::remove(who.clone()); + Self::deposit_event(RawEvent::Undelegated(who)); + Ok(()) + } } } @@ -208,9 +228,6 @@ decl_storage! { /// Queue of successful referenda to be dispatched. pub DispatchQueue get(dispatch_queue): map T::BlockNumber => Vec>; - /// The block at which the `who`'s funds become liquid. - pub Bondage get(bondage): map T::AccountId => T::BlockNumber; - /// Get the voters for the current proposal. pub VotersFor get(voters_for): map ReferendumIndex => Vec; @@ -218,11 +235,13 @@ decl_storage! { /// voter when called with the referendum (you'll get the default `Vote` value otherwise). If you don't want to check /// `voters_for`, then you can also check for simple existence with `VoteOf::exists` first. pub VoteOf get(vote_of): map (ReferendumIndex, T::AccountId) => Vote; + + /// Get the account (and lock periods) to which another account is delegating vote. + pub Delegations get(delegations): linked_map T::AccountId => (T::AccountId, LockPeriods); } } decl_event!( - /// An event in this module. pub enum Event where Balance = BalanceOf, ::AccountId { Proposed(PropIndex, Balance), Tabled(PropIndex, Balance, Vec), @@ -231,6 +250,8 @@ decl_event!( NotPassed(ReferendumIndex), Cancelled(ReferendumIndex), Executed(ReferendumIndex, bool), + Delegated(AccountId, AccountId), + Undelegated(AccountId), } ); @@ -269,10 +290,9 @@ impl Module { /// Get the voters for the current proposal. pub fn tally(ref_index: ReferendumIndex) -> (BalanceOf, BalanceOf, BalanceOf) { - Self::voters_for(ref_index).iter() + let (approve, against, capital): (BalanceOf, BalanceOf, BalanceOf) = Self::voters_for(ref_index).iter() .map(|voter| ( - T::Currency::total_balance(voter), - Self::vote_of((ref_index, voter.clone())), + T::Currency::total_balance(voter), Self::vote_of((ref_index, voter.clone())) )) .map(|(bal, vote)| if vote.is_aye() { @@ -280,7 +300,42 @@ impl Module { } else { (Zero::zero(), bal * BalanceOf::::sa(vote.multiplier() as u64), bal) } - ).fold((Zero::zero(), Zero::zero(), Zero::zero()), |(a, b, c), (d, e, f)| (a + d, b + e, c + f)) + ).fold((Zero::zero(), Zero::zero(), Zero::zero()), |(a, b, c), (d, e, f)| (a + d, b + e, c + f)); + let (del_approve, del_against, del_capital) = Self::tally_delegation(ref_index); + (approve + del_approve, against + del_against, capital + del_capital) + } + + /// Get the delegated voters for the current proposal. + /// I think this goes into a worker once https://github.com/paritytech/substrate/issues/1458 is done. + fn tally_delegation(ref_index: ReferendumIndex) -> (BalanceOf, BalanceOf, BalanceOf) { + Self::voters_for(ref_index).iter() + .fold((Zero::zero(), Zero::zero(), Zero::zero()), |(approve_acc, against_acc, capital_acc), voter| { + let vote = Self::vote_of((ref_index, voter.clone())); + let (votes, balance) = Self::delegated_votes(ref_index, voter.clone(), vote.multiplier(), MAX_RECURSION_LIMIT); + if vote.is_aye() { + (approve_acc + votes, against_acc, capital_acc + balance) + } else { + (approve_acc, against_acc + votes, capital_acc + balance) + } + }) + } + + fn delegated_votes( + ref_index: ReferendumIndex, + to: T::AccountId, + min_lock_periods: LockPeriods, + recursion_limit: u32, + ) -> (BalanceOf, BalanceOf) { + if recursion_limit == 0 { return (Zero::zero(), Zero::zero()); } + >::enumerate() + .filter(|(delegator, (delegate, _))| *delegate == to && !>::exists(&(ref_index, delegator.clone()))) + .fold((Zero::zero(), Zero::zero()), |(votes_acc, balance_acc), (delegator, (_delegate, periods))| { + let lock_periods = if min_lock_periods <= periods { min_lock_periods } else { periods }; + let balance = T::Currency::total_balance(&delegator); + let votes = T::Currency::total_balance(&delegator) * BalanceOf::::sa(lock_periods as u64); + let (del_votes, del_balance) = Self::delegated_votes(ref_index, delegator, lock_periods, recursion_limit - 1); + (votes_acc + votes + del_votes, balance_acc + balance + del_balance) + }) } // Exposed mutables. @@ -371,7 +426,7 @@ impl Module { // lock should they win... let locked_until = now + lock_period * T::BlockNumber::sa((vote.multiplier()) as u64); // ...extend their bondage until at least then. - >::mutate(a, |b| if *b < locked_until { *b = locked_until }); + T::Currency::extend_lock(DEMOCRACY_ID, &a, Bounded::max_value(), locked_until, WithdrawReason::Transfer.into()); } Self::clear_referendum(index); @@ -409,22 +464,6 @@ impl Module { } } -impl OnFreeBalanceZero for Module { - fn on_free_balance_zero(who: &T::AccountId) { - >::remove(who); - } -} - -impl EnsureAccountLiquid for Module { - fn ensure_account_liquid(who: &T::AccountId) -> Result { - if Self::bondage(who) <= >::block_number() { - Ok(()) - } else { - Err("cannot transfer illiquid funds") - } - } -} - #[cfg(test)] mod tests { use super::*; @@ -434,6 +473,7 @@ mod tests { use primitives::BuildStorage; use primitives::traits::{BlakeTwo256, IdentityLookup}; use primitives::testing::{Digest, DigestItem, Header}; + use balances::BalanceLock; const AYE: Vote = Vote(-1); const NAY: Vote = Vote(0); @@ -460,7 +500,7 @@ mod tests { type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; @@ -469,8 +509,10 @@ mod tests { type Balance = u64; type OnFreeBalanceZero = (); type OnNewAccount = (); - type EnsureAccountLiquid = (); type Event = (); + type TransactionPayment = (); + type TransferPayment = (); + type DustRemoval = (); } impl Trait for Test { type Currency = balances::Module; @@ -485,6 +527,8 @@ mod tests { fn new_test_ext_with_public_delay(public_delay: u64) -> 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![(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)], existential_deposit: 0, transfer_fee: 0, @@ -581,6 +625,158 @@ mod tests { assert_eq!(Democracy::voters_for(r), vec![1]); assert_eq!(Democracy::vote_of((r, 1)), AYE); assert_eq!(Democracy::tally(r), (10, 0, 10)); + + assert_eq!(Democracy::end_block(System::block_number()), Ok(())); + assert_eq!(Balances::free_balance(&42), 2); + }); + } + + #[test] + fn single_proposal_should_work_with_delegation() { + with_externalities(&mut new_test_ext(), || { + System::set_block_number(1); + + assert_ok!(propose_set_balance(1, 2, 1)); + + assert_eq!(Democracy::end_block(System::block_number()), Ok(())); + System::set_block_number(2); + let r = 0; + + // Delegate vote. + assert_ok!(Democracy::delegate(Origin::signed(2), 1, 100)); + + assert_ok!(Democracy::vote(Origin::signed(1), r, AYE)); + + assert_eq!(Democracy::referendum_count(), 1); + assert_eq!(Democracy::voters_for(r), vec![1]); + assert_eq!(Democracy::vote_of((r, 1)), AYE); + + // Delegated vote is counted. + assert_eq!(Democracy::tally(r), (30, 0, 30)); + + assert_eq!(Democracy::end_block(System::block_number()), Ok(())); + + assert_eq!(Balances::free_balance(&42), 2); + }); + } + + #[test] + fn single_proposal_should_work_with_cyclic_delegation() { + with_externalities(&mut new_test_ext(), || { + System::set_block_number(1); + + assert_ok!(propose_set_balance(1, 2, 1)); + + assert_eq!(Democracy::end_block(System::block_number()), Ok(())); + System::set_block_number(2); + let r = 0; + + // Check behaviour with cycle. + assert_ok!(Democracy::delegate(Origin::signed(2), 1, 100)); + assert_ok!(Democracy::delegate(Origin::signed(3), 2, 100)); + assert_ok!(Democracy::delegate(Origin::signed(1), 3, 100)); + + assert_ok!(Democracy::vote(Origin::signed(1), r, AYE)); + + assert_eq!(Democracy::referendum_count(), 1); + assert_eq!(Democracy::voters_for(r), vec![1]); + + // Delegated vote is counted. + assert_eq!(Democracy::tally(r), (60, 0, 60)); + assert_eq!(Democracy::end_block(System::block_number()), Ok(())); + + assert_eq!(Balances::free_balance(&42), 2); + }); + } + + #[test] + /// If transactor already voted, delegated vote is overwriten. + fn single_proposal_should_work_with_vote_and_delegation() { + with_externalities(&mut new_test_ext(), || { + System::set_block_number(1); + + assert_ok!(propose_set_balance(1, 2, 1)); + + assert_eq!(Democracy::end_block(System::block_number()), Ok(())); + System::set_block_number(2); + let r = 0; + + assert_ok!(Democracy::vote(Origin::signed(1), r, AYE)); + + // Vote. + assert_ok!(Democracy::vote(Origin::signed(2), r, AYE)); + + // Delegate vote. + assert_ok!(Democracy::delegate(Origin::signed(2), 1, 100)); + + assert_eq!(Democracy::referendum_count(), 1); + assert_eq!(Democracy::voters_for(r), vec![1, 2]); + assert_eq!(Democracy::vote_of((r, 1)), AYE); + + // Delegated vote is not counted. + assert_eq!(Democracy::tally(r), (30, 0, 30)); + + assert_eq!(Democracy::end_block(System::block_number()), Ok(())); + + assert_eq!(Balances::free_balance(&42), 2); + }); + } + + #[test] + fn single_proposal_should_work_with_undelegation() { + with_externalities(&mut new_test_ext(), || { + System::set_block_number(1); + + assert_ok!(propose_set_balance(1, 2, 1)); + + // Delegate and undelegate vote. + assert_ok!(Democracy::delegate(Origin::signed(2), 1, 100)); + assert_ok!(Democracy::undelegate(Origin::signed(2))); + + assert_eq!(Democracy::end_block(System::block_number()), Ok(())); + System::set_block_number(2); + let r = 0; + assert_ok!(Democracy::vote(Origin::signed(1), r, AYE)); + + assert_eq!(Democracy::referendum_count(), 1); + assert_eq!(Democracy::voters_for(r), vec![1]); + assert_eq!(Democracy::vote_of((r, 1)), AYE); + + // Delegated vote is not counted. + assert_eq!(Democracy::tally(r), (10, 0, 10)); + + assert_eq!(Democracy::end_block(System::block_number()), Ok(())); + + assert_eq!(Balances::free_balance(&42), 2); + }); + } + + #[test] + /// If transactor voted, delegated vote is overwriten. + fn single_proposal_should_work_with_delegation_and_vote() { + with_externalities(&mut new_test_ext(), || { + System::set_block_number(1); + + assert_ok!(propose_set_balance(1, 2, 1)); + + assert_eq!(Democracy::end_block(System::block_number()), Ok(())); + System::set_block_number(2); + let r = 0; + + assert_ok!(Democracy::vote(Origin::signed(1), r, AYE)); + + // Delegate vote. + assert_ok!(Democracy::delegate(Origin::signed(2), 1, 100)); + + // Vote. + assert_ok!(Democracy::vote(Origin::signed(2), r, AYE)); + + assert_eq!(Democracy::referendum_count(), 1); + assert_eq!(Democracy::voters_for(r), vec![1, 2]); + assert_eq!(Democracy::vote_of((r, 1)), AYE); + + // Delegated vote is not counted. + assert_eq!(Democracy::tally(r), (30, 0, 30)); assert_eq!(Democracy::end_block(System::block_number()), Ok(())); @@ -777,12 +973,35 @@ mod tests { assert_eq!(Democracy::end_block(System::block_number()), Ok(())); - assert_eq!(Democracy::bondage(1), 0); - assert_eq!(Democracy::bondage(2), 6); - assert_eq!(Democracy::bondage(3), 5); - assert_eq!(Democracy::bondage(4), 4); - assert_eq!(Democracy::bondage(5), 3); - assert_eq!(Democracy::bondage(6), 0); + assert_eq!(Balances::locks(1), vec![]); + assert_eq!(Balances::locks(2), vec![BalanceLock { id: DEMOCRACY_ID, amount: u64::max_value(), until: 6, reasons: WithdrawReason::Transfer.into() }]); + assert_eq!(Balances::locks(3), vec![BalanceLock { id: DEMOCRACY_ID, amount: u64::max_value(), until: 5, reasons: WithdrawReason::Transfer.into() }]); + assert_eq!(Balances::locks(4), vec![BalanceLock { id: DEMOCRACY_ID, amount: u64::max_value(), until: 4, reasons: WithdrawReason::Transfer.into() }]); + assert_eq!(Balances::locks(5), vec![BalanceLock { id: DEMOCRACY_ID, amount: u64::max_value(), until: 3, reasons: WithdrawReason::Transfer.into() }]); + assert_eq!(Balances::locks(6), vec![]); + + System::set_block_number(2); + assert_eq!(Democracy::end_block(System::block_number()), Ok(())); + + assert_eq!(Balances::free_balance(&42), 2); + }); + } + + #[test] + fn lock_voting_should_work_with_delegation() { + with_externalities(&mut new_test_ext_with_public_delay(1), || { + System::set_block_number(1); + let r = Democracy::inject_referendum(1, set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0).unwrap(); + assert_ok!(Democracy::vote(Origin::signed(1), r, Vote::new(false, 6))); + assert_ok!(Democracy::vote(Origin::signed(2), r, Vote::new(true, 5))); + assert_ok!(Democracy::vote(Origin::signed(3), r, Vote::new(true, 4))); + assert_ok!(Democracy::vote(Origin::signed(4), r, Vote::new(true, 3))); + assert_ok!(Democracy::delegate(Origin::signed(5), 2, 2)); + assert_ok!(Democracy::vote(Origin::signed(6), r, Vote::new(false, 1))); + + assert_eq!(Democracy::tally(r), (440, 120, 210)); + + assert_eq!(Democracy::end_block(System::block_number()), Ok(())); System::set_block_number(2); assert_eq!(Democracy::end_block(System::block_number()), Ok(())); diff --git a/srml/democracy/src/vote_threshold.rs b/srml/democracy/src/vote_threshold.rs index 9a730fc52aab4fb41763759e543daa5572dc1f5c..d436757539d47e8dad3294964a80a7aa214440c0 100644 --- a/srml/democracy/src/vote_threshold.rs +++ b/srml/democracy/src/vote_threshold.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -18,7 +18,7 @@ #[cfg(feature = "std")] use serde_derive::{Serialize, Deserialize}; -use parity_codec_derive::{Encode, Decode}; +use parity_codec::{Encode, Decode}; use primitives::traits::{Zero, IntegerSquareRoot}; use rstd::ops::{Add, Mul, Div, Rem}; diff --git a/srml/example/Cargo.toml b/srml/example/Cargo.toml index 72faa86f4cfc1e1af6e2447fe1e1dc9053701ba9..57abe374c9b131887c6dc420a562a5d8481d4d5b 100644 --- a/srml/example/Cargo.toml +++ b/srml/example/Cargo.toml @@ -6,8 +6,8 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } -parity-codec = { version = "3.0", default-features = false } +serde = { version = "1.0", optional = true } +parity-codec = { version = "3.2", 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 } @@ -20,7 +20,7 @@ sr-primitives = { path = "../../core/sr-primitives" } [features] default = ["std"] std = [ - "serde/std", + "serde", "parity-codec/std", "sr-primitives/std", "srml-support/std", diff --git a/srml/example/src/lib.rs b/srml/example/src/lib.rs index 4f4e0b96a0b6249da09b02c56d5fe5d8408fd971..6ceb6da236d632afd571824b24bff0bd0d0e0a26 100644 --- a/srml/example/src/lib.rs +++ b/srml/example/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -66,16 +66,15 @@ decl_storage! { // A map that has enumerable entries. Bar get(bar) config(): linked_map T::AccountId => T::Balance; - // this one uses the default, we'll demonstrate the usage of 'mutate' API. Foo get(foo) config(): T::Balance; } } -/// An event in this module. Events are simple means of reporting specific conditions and -/// circumstances that have happened that users, Dapps and/or chain explorers would find -/// interesting and otherwise difficult to detect. decl_event!( + /// Events are a simple means of reporting specific conditions and + /// circumstances that have happened that users, Dapps and/or chain explorers would find + /// interesting and otherwise difficult to detect. pub enum Event where B = ::Balance { // Just a normal `enum`, here's a dummy event to ensure it compiles. /// Dummy event, just here so there's a generic type that's used. @@ -214,6 +213,15 @@ decl_module! { // We just kill our dummy storage item. >::kill(); } + + // A runtime code run after every block and have access to extended set of APIs. + // + // For instance you can generate extrinsics for the upcoming produced block. + fn offchain_worker(_n: T::BlockNumber) { + // We don't do anything here. + // but we could dispatch extrinsic (transaction/inherent) using + // runtime_io::submit_extrinsic + } } } @@ -271,7 +279,7 @@ mod tests { type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; @@ -280,8 +288,10 @@ mod tests { type Balance = u64; type OnFreeBalanceZero = (); type OnNewAccount = (); - type EnsureAccountLiquid = (); type Event = (); + type TransactionPayment = (); + type TransferPayment = (); + type DustRemoval = (); } impl Trait for Test { type Event = (); diff --git a/srml/executive/Cargo.toml b/srml/executive/Cargo.toml index 4b4d859136843945ea84f898232ebb6c2e193535..31ca69fa55b3a2ffc7de57f10f9161ad5f0313dd 100644 --- a/srml/executive/Cargo.toml +++ b/srml/executive/Cargo.toml @@ -5,8 +5,8 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -serde = { version = "1.0", default-features = false } -parity-codec = { version = "3.0", default-features = false } +serde = { version = "1.0", optional = true } +parity-codec = { version = "3.2", 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 } @@ -18,15 +18,14 @@ hex-literal = "0.1.0" substrate-primitives = { path = "../../core/primitives" } srml-indices = { path = "../indices" } balances = { package = "srml-balances", path = "../balances" } -fees = { package = "srml-fees", path = "../fees" } -parity-codec-derive = { version = "3.0" } +parity-codec-derive = { version = "3.1" } [features] default = ["std"] std = [ "rstd/std", "srml-support/std", - "serde/std", + "serde", "parity-codec/std", "primitives/std", "runtime_io/std", diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index 1638bc6e62528c6db27efce3c3840360a070f2f0..0fe4b9e33d772a297a219ec0c7a14992ec637717 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -18,13 +18,14 @@ #![cfg_attr(not(feature = "std"), no_std)] - use rstd::prelude::*; use rstd::marker::PhantomData; use rstd::result; -use primitives::traits::{self, Header, Zero, One, Checkable, Applyable, CheckEqual, OnFinalise, - OnInitialise, ChargeBytesFee, Hash, As, Digest}; -use srml_support::Dispatchable; +use primitives::traits::{ + self, Header, Zero, One, Checkable, Applyable, CheckEqual, OnFinalise, + OnInitialise, Hash, As, Digest, NumberFor, Block as BlockT, OffchainWorker +}; +use srml_support::{Dispatchable, traits::MakePayment}; use parity_codec::{Codec, Encode}; use system::extrinsics_root; use primitives::{ApplyOutcome, ApplyError}; @@ -47,20 +48,45 @@ mod internal { } } -pub struct Executive< - System, - Block, - Context, - Payment, - AllModules, ->(PhantomData<(System, Block, Context, Payment, AllModules)>); +/// Something that can be used to execute a block. +pub trait ExecuteBlock { + /// Actually execute all transitioning for `block`. + fn execute_block(block: Block); + /// Execute all extrinsics like when executing a `block`, but with dropping intial and final checks. + fn execute_extrinsics_without_checks(block_number: NumberFor, extrinsics: Vec); +} + +pub struct Executive( + PhantomData<(System, Block, Context, Payment, AllModules)> +); impl< + System: system::Trait, + Block: traits::Block, Context: Default, + Payment: MakePayment, + AllModules: OnInitialise + OnFinalise + OffchainWorker, +> ExecuteBlock for Executive where + Block::Extrinsic: Checkable + Codec, + >::Checked: Applyable, + <>::Checked as Applyable>::Call: Dispatchable, + <<>::Checked as Applyable>::Call as Dispatchable>::Origin: From> +{ + fn execute_block(block: Block) { + Executive::::execute_block(block); + } + + fn execute_extrinsics_without_checks(block_number: NumberFor, extrinsics: Vec) { + Executive::::execute_extrinsics_without_checks(block_number, extrinsics); + } +} + +impl< System: system::Trait, Block: traits::Block, - Payment: ChargeBytesFee, - AllModules: OnInitialise + OnFinalise, + Context: Default, + Payment: MakePayment, + AllModules: OnInitialise + OnFinalise + OffchainWorker, > Executive where Block::Extrinsic: Checkable + Codec, >::Checked: Applyable, @@ -69,8 +95,12 @@ impl< { /// Start the execution of a particular block. pub fn initialise_block(header: &System::Header) { - >::initialise(header.number(), header.parent_hash(), header.extrinsics_root()); - >::on_initialise(*header.number()); + Self::initialise_block_impl(header.number(), header.parent_hash(), header.extrinsics_root()); + } + + fn initialise_block_impl(block_number: &System::BlockNumber, parent_hash: &System::Hash, extrinsics_root: &System::Hash) { + >::initialise(block_number, parent_hash, extrinsics_root); + >::on_initialise(*block_number); } fn initial_checks(block: &Block) { @@ -96,18 +126,35 @@ impl< // any initial checks Self::initial_checks(&block); - // execute transactions + // execute extrinsics let (header, extrinsics) = block.deconstruct(); - extrinsics.into_iter().for_each(Self::apply_extrinsic_no_note); - - // post-transactional book-keeping. - >::note_finished_extrinsics(); - >::on_finalise(*header.number()); + Self::execute_extrinsics_with_book_keeping(extrinsics, *header.number()); // any final checks Self::final_checks(&header); } + /// Execute all extrinsics like when executing a `block`, but with dropping intial and final checks. + pub fn execute_extrinsics_without_checks(block_number: NumberFor, extrinsics: Vec) { + // Make the api happy, but maybe we should not set them at all. + let parent_hash = ::Hashing::hash(b"parent_hash"); + let extrinsics_root = ::Hashing::hash(b"extrinsics_root"); + + Self::initialise_block_impl(&block_number, &parent_hash, &extrinsics_root); + + // execute extrinsics + Self::execute_extrinsics_with_book_keeping(extrinsics, block_number); + } + + /// Execute given extrinsics and take care of post-extrinsics book-keeping + fn execute_extrinsics_with_book_keeping(extrinsics: Vec, block_number: NumberFor) { + extrinsics.into_iter().for_each(Self::apply_extrinsic_no_note); + + // post-extrinsics book-keeping. + >::note_finished_extrinsics(); + >::on_finalise(block_number); + } + /// Finalise the block - it is up the caller to ensure that all header fields are valid /// except state-root. pub fn finalise_block() -> System::Header { @@ -167,7 +214,7 @@ impl< ) } // pay any fees. - Payment::charge_base_bytes_fee(sender, encoded_len).map_err(|_| internal::ApplyError::CantPay)?; + Payment::make_payment(sender, encoded_len).map_err(|_| internal::ApplyError::CantPay)?; // AUDIT: Under no circumstances may this function panic from here onwards. @@ -239,7 +286,7 @@ impl< if let (Some(sender), Some(index)) = (xt.sender(), xt.index()) { // pay any fees. - if Payment::charge_base_bytes_fee(sender, encoded_len).is_err() { + if Payment::make_payment(sender, encoded_len).is_err() { return TransactionValidity::Invalid(ApplyError::CantPay as i8) } @@ -272,6 +319,11 @@ impl< }) } } + + /// Start an offchain worker and generate extrinsics. + pub fn offchain_worker(n: System::BlockNumber) { + >::generate_extrinsics(n) + } } #[cfg(test)] @@ -285,7 +337,6 @@ mod tests { use primitives::testing::{Digest, DigestItem, Header, Block}; use srml_support::{traits::Currency, impl_outer_origin, impl_outer_event}; use system; - use fees; use hex_literal::{hex, hex_impl}; impl_outer_origin! { @@ -295,7 +346,7 @@ mod tests { impl_outer_event!{ pub enum MetaEvent for Runtime { - balances, fees, + balances, } } @@ -319,31 +370,27 @@ mod tests { type Balance = u64; type OnFreeBalanceZero = (); type OnNewAccount = (); - type EnsureAccountLiquid = (); - type Event = MetaEvent; - } - impl fees::Trait for Runtime { type Event = MetaEvent; - type TransferAsset = balances::Module; + type TransactionPayment = (); + type DustRemoval = (); + type TransferPayment = (); } type TestXt = primitives::testing::TestXt>; - type Executive = super::Executive, system::ChainContext, fees::Module, ()>; + type Executive = super::Executive, system::ChainContext, balances::Module, ()>; #[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, balances: vec![(1, 111)], existential_deposit: 0, transfer_fee: 0, creation_fee: 0, vesting: vec![], }.build_storage().unwrap().0); - t.extend(fees::GenesisConfig:: { - transaction_base_fee: 10, - transaction_byte_fee: 0, - }.build_storage().unwrap().0); let xt = primitives::testing::TestXt(Some(1), 0, Call::transfer(2, 69)); let mut t = runtime_io::TestExternalities::::new(t); with_externalities(&mut t, || { @@ -368,7 +415,7 @@ mod tests { header: Header { parent_hash: [69u8; 32].into(), number: 1, - state_root: hex!("6651861f40a8f42c033b3e937cb3513e6dbaf4be6bafb1561a19f884be3f58dd").into(), + state_root: hex!("49cd58a254ccf6abc4a023d9a22dcfc421e385527a250faec69f8ad0d8ed3e48").into(), extrinsics_root: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").into(), digest: Digest { logs: vec![], }, }, @@ -402,7 +449,7 @@ mod tests { header: Header { parent_hash: [69u8; 32].into(), number: 1, - state_root: hex!("6651861f40a8f42c033b3e937cb3513e6dbaf4be6bafb1561a19f884be3f58dd").into(), + state_root: hex!("49cd58a254ccf6abc4a023d9a22dcfc421e385527a250faec69f8ad0d8ed3e48").into(), extrinsics_root: [0u8; 32].into(), digest: Digest { logs: vec![], }, }, diff --git a/srml/fees/Cargo.toml b/srml/fees/Cargo.toml deleted file mode 100644 index d3883e09b0bec2a3b92b9e5a9b2f7185c95035eb..0000000000000000000000000000000000000000 --- a/srml/fees/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "srml-fees" -version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2018" - -[dependencies] -hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } -primitives = { package = "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 } -runtime_primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } -srml-support = { package = "srml-support", path = "../support", default-features = false } -system = { package = "srml-system", path = "../system", default-features = false } - -[features] -default = ["std"] -std = [ - "serde/std", - "parity-codec/std", - "parity-codec-derive/std", - "primitives/std", - "rstd/std", - "runtime_io/std", - "runtime_primitives/std", - "srml-support/std", - "system/std", -] diff --git a/srml/fees/src/lib.rs b/srml/fees/src/lib.rs deleted file mode 100644 index d6809bac30de4b36ec9618ed465a44afb6360bec..0000000000000000000000000000000000000000 --- a/srml/fees/src/lib.rs +++ /dev/null @@ -1,115 +0,0 @@ -// 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 . - -//! Handles all transaction fee related operations - -// Ensure we're `no_std` when compiling for Wasm. -#![cfg_attr(not(feature = "std"), no_std)] - -use srml_support::{dispatch::Result, traits::ArithmeticType, StorageMap, decl_event, decl_storage, decl_module}; -use runtime_primitives::traits::{ - As, ChargeBytesFee, ChargeFee, - TransferAsset, CheckedAdd, CheckedSub, CheckedMul, Zero -}; -use system; - -mod mock; -mod tests; - -type AssetOf = <::TransferAsset as ArithmeticType>::Type; - -pub trait Trait: system::Trait { - /// The overarching event type. - type Event: From> + Into<::Event>; - - /// A function does the asset transfer between accounts - type TransferAsset: ArithmeticType + TransferAsset>; -} - -decl_module! { - pub struct Module for enum Call where origin: T::Origin { - fn deposit_event() = default; - - fn on_finalise() { - let extrinsic_count = >::extrinsic_count(); - (0..extrinsic_count).for_each(|index| { - // Deposit `Charged` event if some amount of fee charged. - let fee = >::take(index); - if !fee.is_zero() { - Self::deposit_event(RawEvent::Charged(index, fee)); - } - }); - } - } -} - -decl_event!( - pub enum Event where Amount = AssetOf { - /// Fee charged (extrinsic_index, fee_amount) - Charged(u32, Amount), - } -); - -decl_storage! { - trait Store for Module as Fees { - /// The fee to be paid for making a transaction; the base. - pub TransactionBaseFee get(transaction_base_fee) config(): AssetOf; - /// The fee to be paid for making a transaction; the per-byte portion. - pub TransactionByteFee get(transaction_byte_fee) config(): AssetOf; - - /// The `extrinsic_index => accumulated_fees` map, containing records to - /// track the overall charged fees for each transaction. - /// - /// All records should be removed at finalise stage. - CurrentTransactionFee get(current_transaction_fee): map u32 => AssetOf; - } -} - -impl ChargeBytesFee for Module { - fn charge_base_bytes_fee(transactor: &T::AccountId, encoded_len: usize) -> Result { - let bytes_fee = Self::transaction_byte_fee().checked_mul( - & as As>::sa(encoded_len as u64) - ).ok_or_else(|| "bytes fee overflow")?; - let overall = Self::transaction_base_fee().checked_add(&bytes_fee).ok_or_else(|| "bytes fee overflow")?; - Self::charge_fee(transactor, overall) - } -} - -impl ChargeFee for Module { - type Amount = AssetOf; - - fn charge_fee(transactor: &T::AccountId, amount: AssetOf) -> Result { - let extrinsic_index = >::extrinsic_index().ok_or_else(|| "no extrinsic index found")?; - let current_fee = Self::current_transaction_fee(extrinsic_index); - let new_fee = current_fee.checked_add(&amount).ok_or_else(|| "fee got overflow after charge")?; - - T::TransferAsset::remove_from(transactor, amount)?; - - >::insert(extrinsic_index, new_fee); - Ok(()) - } - - fn refund_fee(transactor: &T::AccountId, amount: AssetOf) -> Result { - let extrinsic_index = >::extrinsic_index().ok_or_else(|| "no extrinsic index found")?; - let current_fee = Self::current_transaction_fee(extrinsic_index); - let new_fee = current_fee.checked_sub(&amount).ok_or_else(|| "fee got underflow after refund")?; - - T::TransferAsset::add_to(transactor, amount)?; - - >::insert(extrinsic_index, new_fee); - Ok(()) - } -} diff --git a/srml/fees/src/mock.rs b/srml/fees/src/mock.rs deleted file mode 100644 index dd93335eef064878e65874a3532dce06fa10006d..0000000000000000000000000000000000000000 --- a/srml/fees/src/mock.rs +++ /dev/null @@ -1,112 +0,0 @@ -// 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 . - -//! Test utilities - -#![cfg(test)] - -use runtime_primitives::BuildStorage; -use runtime_primitives::{ - traits::{IdentityLookup, BlakeTwo256, TransferAsset}, - testing::{Digest, DigestItem, Header}, -}; -use primitives::{H256, Blake2Hasher}; -use runtime_io; -use srml_support::{impl_outer_origin, impl_outer_event, traits::ArithmeticType}; -use crate::{GenesisConfig, Module, Trait, system}; - -impl_outer_origin!{ - pub enum Origin for Test {} -} - -mod fees { - pub use crate::Event; -} - -impl_outer_event!{ - pub enum TestEvent for Test { - fees, - } -} - -pub struct TransferAssetMock; - -impl TransferAsset for TransferAssetMock { - type Amount = u64; - - fn transfer(_: &AccountId, _: &AccountId, _: Self::Amount) -> Result<(), &'static str> { Ok(()) } - fn remove_from(_: &AccountId, _: Self::Amount) -> Result<(), &'static str> { Ok(()) } - fn add_to(_: &AccountId, _: Self::Amount) -> Result<(), &'static str> { Ok(()) } -} - -impl ArithmeticType for TransferAssetMock { - type Type = u64; -} - -// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct Test; -impl system::Trait for Test { - type Origin = Origin; - type Index = u64; - type BlockNumber = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type Digest = Digest; - type AccountId = u64; - type Lookup = IdentityLookup; - type Header = Header; - type Event = TestEvent; - type Log = DigestItem; -} -impl Trait for Test { - type Event = TestEvent; - type TransferAsset = TransferAssetMock; -} - -pub type System = system::Module; -pub type Fees = Module; - -pub struct ExtBuilder { - transaction_base_fee: u64, - transaction_byte_fee: u64, -} -impl Default for ExtBuilder { - fn default() -> Self { - Self { - transaction_base_fee: 0, - transaction_byte_fee: 0, - } - } -} -impl ExtBuilder { - pub fn transaction_base_fee(mut self, transaction_base_fee: u64) -> Self { - self.transaction_base_fee = transaction_base_fee; - self - } - pub fn transaction_byte_fee(mut self, transaction_byte_fee: u64) -> Self { - self.transaction_byte_fee = transaction_byte_fee; - self - } - pub fn build(self) -> runtime_io::TestExternalities { - 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, - }.build_storage().unwrap().0); - t.into() - } -} diff --git a/srml/fees/src/tests.rs b/srml/fees/src/tests.rs deleted file mode 100644 index a1c96570629e85d2b5c8df5a8bed4fc314792803..0000000000000000000000000000000000000000 --- a/srml/fees/src/tests.rs +++ /dev/null @@ -1,174 +0,0 @@ -// 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 . - -//! Tests for the module. - -#![cfg(test)] - -use super::*; -use runtime_io::with_externalities; -use runtime_primitives::traits::{OnFinalise}; -use system::{EventRecord, Phase}; - -use mock::{Fees, System, ExtBuilder}; -use srml_support::{assert_ok, assert_err}; - -#[test] -fn charge_base_bytes_fee_should_work() { - with_externalities( - &mut ExtBuilder::default() - .transaction_base_fee(3) - .transaction_byte_fee(5) - .build(), - || { - System::set_extrinsic_index(0); - assert_ok!(Fees::charge_base_bytes_fee(&0, 7)); - assert_eq!(Fees::current_transaction_fee(0), 3 + 5 * 7); - - System::set_extrinsic_index(1); - assert_ok!(Fees::charge_base_bytes_fee(&0, 11)); - assert_eq!(Fees::current_transaction_fee(1), 3 + 5 * 11); - - System::set_extrinsic_index(3); - assert_ok!(Fees::charge_base_bytes_fee(&0, 13)); - assert_eq!(Fees::current_transaction_fee(3), 3 + 5 * 13); - } - ); -} - -#[test] -fn charge_base_bytes_fee_should_not_work_if_bytes_fee_overflow() { - // bytes fee overflows. - with_externalities( - &mut ExtBuilder::default() - .transaction_base_fee(0) - .transaction_byte_fee(u64::max_value()) - .build(), - || { - System::set_extrinsic_index(0); - assert_err!( - Fees::charge_base_bytes_fee(&0, 2), - "bytes fee overflow" - ); - } - ); -} - -#[test] -fn charge_base_bytes_fee_should_not_work_if_overall_fee_overflow() { - // bytes fee doesn't overflow, but overall fee (bytes_fee + base_fee) does - with_externalities( - &mut ExtBuilder::default() - .transaction_base_fee(u64::max_value()) - .transaction_byte_fee(1) - .build(), - || { - System::set_extrinsic_index(0); - assert_err!( - Fees::charge_base_bytes_fee(&0, 1), - "bytes fee overflow" - ); - } - ); -} - -#[test] -fn charge_fee_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_extrinsic_index(0); - assert_ok!(Fees::charge_fee(&0, 2)); - assert_ok!(Fees::charge_fee(&0, 3)); - assert_eq!(Fees::current_transaction_fee(0), 2 + 3); - - System::set_extrinsic_index(2); - assert_ok!(Fees::charge_fee(&0, 5)); - assert_ok!(Fees::charge_fee(&0, 7)); - assert_eq!(Fees::current_transaction_fee(2), 5 + 7); - }); -} - -#[test] -fn charge_fee_when_overflow_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_extrinsic_index(0); - assert_ok!(Fees::charge_fee(&0, u64::max_value())); - assert_err!(Fees::charge_fee(&0, 1), "fee got overflow after charge"); - }); -} - -#[test] -fn refund_fee_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_extrinsic_index(0); - assert_ok!(Fees::charge_fee(&0, 5)); - assert_ok!(Fees::refund_fee(&0, 3)); - assert_eq!(Fees::current_transaction_fee(0), 5 - 3); - }); -} - -#[test] -fn refund_fee_when_underflow_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - System::set_extrinsic_index(0); - assert_err!(Fees::refund_fee(&0, 1), "fee got underflow after refund"); - }); -} - -#[test] -fn on_finalise_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { - // charge fees in extrinsic index 3 - System::set_extrinsic_index(3); - assert_ok!(Fees::charge_fee(&0, 1)); - System::note_applied_extrinsic(&Ok(()), 1); - // charge fees in extrinsic index 5 - System::set_extrinsic_index(5); - assert_ok!(Fees::charge_fee(&0, 1)); - System::note_applied_extrinsic(&Ok(()), 1); - System::note_finished_extrinsics(); - - // `current_transaction_fee`, `extrinsic_count` should be as expected. - assert_eq!(Fees::current_transaction_fee(3), 1); - assert_eq!(Fees::current_transaction_fee(5), 1); - assert_eq!(System::extrinsic_count(), 5 + 1); - - >::on_finalise(1); - - // When finalised, `CurrentTransactionFee` records should be cleared. - assert_eq!(Fees::current_transaction_fee(3), 0); - assert_eq!(Fees::current_transaction_fee(5), 0); - - // When finalised, if any fee charged in a extrinsic, a `Charged` event should be deposited - // for it. - let fee_charged_events: Vec> = System::events() - .into_iter() - .filter(|e| match e.event { - mock::TestEvent::fees(RawEvent::Charged(_, _)) => return true, - _ => return false, - }) - .collect(); - assert_eq!(fee_charged_events, vec![ - EventRecord { - phase: Phase::Finalization, - event: RawEvent::Charged(3, 1).into(), - }, - EventRecord { - phase: Phase::Finalization, - event: RawEvent::Charged(5, 1).into(), - }, - ]); - }); -} diff --git a/srml/finality-tracker/Cargo.toml b/srml/finality-tracker/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..22691e1aa7b14f5538f749edb6261c6fd3d13bc7 --- /dev/null +++ b/srml/finality-tracker/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "srml-finality-tracker" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +hex-literal = "0.1.0" +serde = { version = "1.0", default-features = false } +serde_derive = { version = "1.0", optional = true } +parity-codec = { version = "3.2", 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 } +srml-support = { path = "../support", default-features = false } +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.7" + +[features] +default = ["std"] +std = [ + "serde/std", + "serde_derive", + "parity-codec/std", + "rstd/std", + "srml-support/std", + "primitives/std", + "srml-system/std", + "inherents/std", +] diff --git a/srml/finality-tracker/src/lib.rs b/srml/finality-tracker/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..5f417881f7482d337f66f5e9a931a70216c547ec --- /dev/null +++ b/srml/finality-tracker/src/lib.rs @@ -0,0 +1,385 @@ +// 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 . + +//! SRML module that tracks the last finalized block, as perceived by block authors. + +#![cfg_attr(not(feature = "std"), no_std)] + +#[macro_use] +extern crate srml_support; + +use inherents::{ + RuntimeString, InherentIdentifier, ProvideInherent, + InherentData, MakeFatalError, +}; +use srml_support::StorageValue; +use primitives::traits::{As, One, Zero}; +use rstd::{prelude::*, result, cmp, vec}; +use parity_codec::Decode; +use srml_system::{ensure_inherent, Trait as SystemTrait}; + +#[cfg(feature = "std")] +use parity_codec::Encode; + +const DEFAULT_WINDOW_SIZE: u64 = 101; +const DEFAULT_DELAY: u64 = 1000; + +/// The identifier for the `finalnum` inherent. +pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"finalnum"; + +/// Auxiliary trait to extract finalized inherent data. +pub trait FinalizedInherentData { + /// Get finalized inherent data. + fn finalized_number(&self) -> Result; +} + +impl FinalizedInherentData for InherentData { + fn finalized_number(&self) -> Result { + self.get_data(&INHERENT_IDENTIFIER) + .and_then(|r| r.ok_or_else(|| "Finalized number inherent data not found".into())) + } +} + +/// Provider for inherent data. +#[cfg(feature = "std")] +pub struct InherentDataProvider { + inner: F, + _marker: std::marker::PhantomData, +} + +#[cfg(feature = "std")] +impl InherentDataProvider { + pub fn new(final_oracle: F) -> Self { + InherentDataProvider { inner: final_oracle, _marker: Default::default() } + } +} + +#[cfg(feature = "std")] +impl inherents::ProvideInherentData for InherentDataProvider + where F: Fn() -> Result +{ + fn inherent_identifier(&self) -> &'static InherentIdentifier { + &INHERENT_IDENTIFIER + } + + fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), RuntimeString> { + (self.inner)() + .and_then(|n| inherent_data.put_data(INHERENT_IDENTIFIER, &n)) + } + + fn error_to_string(&self, _error: &[u8]) -> Option { + Some(format!("no further information")) + } +} + + +pub trait Trait: SystemTrait { + /// Something which can be notified when the timestamp is set. Set this to `()` if not needed. + type OnFinalizationStalled: OnFinalizationStalled; +} + +decl_storage! { + trait Store for Module as Timestamp { + /// Recent hints. + RecentHints get(recent_hints) build(|_| vec![T::BlockNumber::zero()]): Vec; + /// Ordered recent hints. + 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 = T::BlockNumber::sa(DEFAULT_WINDOW_SIZE); + /// The delay after which point things become suspicious. + pub ReportLatency get(report_latency) config(report_latency): T::BlockNumber = T::BlockNumber::sa(DEFAULT_DELAY); + + /// Final hint to apply in the block. `None` means "same as parent". + Update: Option; + + // when initialized through config this is set in the beginning. + Initialized get(initialized) build(|_| false): bool; + } +} + +decl_module! { + pub struct Module for enum Call where origin: T::Origin { + /// Hint that the author of this block thinks the best finalized + /// block is the given number. + fn final_hint(origin, #[compact] hint: T::BlockNumber) { + ensure_inherent(origin)?; + assert!(!::Update::exists(), "Final hint must be updated only once in the block"); + assert!( + srml_system::Module::::block_number() >= hint, + "Finalized height above block number", + ); + ::Update::put(hint); + } + + fn on_finalise() { + Self::update_hint(::Update::take()) + } + } +} + +impl Module { + fn update_hint(hint: Option) { + if !Self::initialized() { + ::RecentHints::put(vec![T::BlockNumber::zero()]); + ::OrderedHints::put(vec![T::BlockNumber::zero()]); + ::Median::put(T::BlockNumber::zero()); + + ::Initialized::put(true); + } + + let mut recent = Self::recent_hints(); + let mut ordered = Self::ordered_hints(); + let window_size = cmp::max(T::BlockNumber::one(), Self::window_size()); + + let hint = hint.unwrap_or_else(|| recent.last() + .expect("always at least one recent sample; qed").clone() + ); + + // prune off the front of the list -- typically 1 except for when + // the sample size has just been shrunk. + { + // take into account the item we haven't pushed yet. + let to_prune = (recent.len() + 1).saturating_sub(window_size.as_() as usize); + + for drained in recent.drain(..to_prune) { + let idx = ordered.binary_search(&drained) + .expect("recent and ordered contain the same items; qed"); + + ordered.remove(idx); + } + } + + // find the position in the ordered list where the new item goes. + let ordered_idx = ordered.binary_search(&hint) + .unwrap_or_else(|idx| idx); + + ordered.insert(ordered_idx, hint); + recent.push(hint); + + let two = T::BlockNumber::one() + T::BlockNumber::one(); + + let median = { + let len = ordered.len(); + assert!(len > 0, "pruning dictated by window_size which is always saturated at 1; qed"); + + if len % 2 == 0 { + let a = ordered[len / 2]; + let b = ordered[(len / 2) - 1]; + + // compute average. + (a + b) / two + } else { + ordered[len / 2] + } + }; + + let our_window_size = recent.len(); + + ::RecentHints::put(recent); + ::OrderedHints::put(ordered); + ::Median::put(median); + + if T::BlockNumber::sa(our_window_size as u64) == window_size { + let now = srml_system::Module::::block_number(); + let latency = Self::report_latency(); + + // the delay is the latency plus half the window size. + let delay = latency + (window_size / two); + // median may be at most n - delay + if median + delay <= now { + T::OnFinalizationStalled::on_stalled(window_size - T::BlockNumber::one()); + } + } + } +} + +/// Called when finalization stalled at a given number. +pub trait OnFinalizationStalled { + /// The parameter here is how many more blocks to wait before applying + /// changes triggered by finality stalling. + fn on_stalled(further_wait: N); +} + +macro_rules! impl_on_stalled { + () => ( + impl OnFinalizationStalled for () { + fn on_stalled(_: N) {} + } + ); + + ( $($t:ident)* ) => { + impl),*> OnFinalizationStalled for ($($t,)*) { + fn on_stalled(further_wait: NUM) { + $($t::on_stalled(further_wait.clone());)* + } + } + } +} + +for_each_tuple!(impl_on_stalled); + +impl ProvideInherent for Module { + type Call = Call; + type Error = MakeFatalError<()>; + const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; + + fn create_inherent(data: &InherentData) -> Option { + let final_num = + data.finalized_number().expect("Gets and decodes final number inherent data"); + + // make hint only when not same as last to avoid bloat. + Self::recent_hints().last().and_then(|last| if last == &final_num { + None + } else { + Some(Call::final_hint(final_num)) + }) + } + + fn check_inherent(_call: &Self::Call, _data: &InherentData) -> result::Result<(), Self::Error> { + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use sr_io::{with_externalities, TestExternalities}; + use substrate_primitives::H256; + use primitives::BuildStorage; + use primitives::traits::{BlakeTwo256, IdentityLookup, OnFinalise, Header as HeaderT}; + use primitives::testing::{Digest, DigestItem, Header}; + use srml_support::impl_outer_origin; + use srml_system as system; + use lazy_static::lazy_static; + use parking_lot::Mutex; + + #[derive(Clone, PartialEq, Debug)] + pub struct StallEvent { + at: u64, + 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 Digest = Digest; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = (); + type Log = DigestItem; + } + + type System = system::Module; + + lazy_static! { + static ref NOTIFICATIONS: Mutex> = Mutex::new(Vec::new()); + } + + pub struct StallTracker; + impl OnFinalizationStalled for StallTracker { + fn on_stalled(further_wait: u64) { + let now = System::block_number(); + NOTIFICATIONS.lock().push(StallEvent { at: now, further_wait }); + } + } + + impl Trait for Test { + type OnFinalizationStalled = StallTracker; + } + + 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), || { + FinalityTracker::update_hint(Some(500)); + assert_eq!(FinalityTracker::median(), 250); + assert!(NOTIFICATIONS.lock().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 mut parent_hash = System::parent_hash(); + for i in 2..106 { + System::initialise(&i, &parent_hash, &Default::default()); + FinalityTracker::on_finalise(i); + let hdr = System::finalise(); + parent_hash = hdr.hash(); + } + + assert_eq!( + NOTIFICATIONS.lock().to_vec(), + vec![StallEvent { at: 105, further_wait: 10 }] + ) + }); + } + + #[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 mut parent_hash = System::parent_hash(); + for i in 2..106 { + System::initialise(&i, &parent_hash, &Default::default()); + assert_ok!(FinalityTracker::dispatch( + Call::final_hint(i-1), + Origin::INHERENT, + )); + FinalityTracker::on_finalise(i); + let hdr = System::finalise(); + parent_hash = hdr.hash(); + } + + assert!(NOTIFICATIONS.lock().is_empty()); + }); + } +} diff --git a/srml/grandpa/Cargo.toml b/srml/grandpa/Cargo.toml index 17b569cfe805e531ab726c8a0e8f25178dfff0c8..b7cc5dc231f3d7f3075db9710644574d73b7b43c 100644 --- a/srml/grandpa/Cargo.toml +++ b/srml/grandpa/Cargo.toml @@ -6,10 +6,9 @@ edition = "2018" [dependencies] #hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", 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 } @@ -17,6 +16,8 @@ primitives = { package = "sr-primitives", path = "../../core/sr-primitives", def 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 } +consensus = { package = "srml-consensus", path = "../consensus", default-features = false } +finality-tracker = { package = "srml-finality-tracker", path = "../finality-tracker", default-features = false } [dev-dependencies] runtime_io = { package = "sr-io", path = "../../core/sr-io" } @@ -24,7 +25,7 @@ runtime_io = { package = "sr-io", path = "../../core/sr-io" } [features] default = ["std"] std = [ - "serde/std", + "serde", "serde_derive", "parity-codec/std", "substrate-primitives/std", @@ -33,5 +34,7 @@ std = [ "srml-support/std", "primitives/std", "system/std", + "consensus/std", "session/std", + "finality-tracker/std", ] diff --git a/srml/grandpa/src/lib.rs b/srml/grandpa/src/lib.rs index 9b586fe10d2f7a4e1523154450075740be409061..3c85756e96ba6fcfbca04e984b1cbfb3ecbf996d 100644 --- a/srml/grandpa/src/lib.rs +++ b/srml/grandpa/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -34,16 +34,17 @@ pub use substrate_finality_grandpa_primitives as fg_primitives; use serde_derive::Serialize; use rstd::prelude::*; use parity_codec as codec; -use parity_codec_derive::{Encode, Decode}; +use codec::{Encode, Decode}; use fg_primitives::ScheduledChange; use srml_support::{Parameter, decl_event, decl_storage, decl_module}; use srml_support::dispatch::Result; use srml_support::storage::StorageValue; use srml_support::storage::unhashed::StorageVec; -use primitives::traits::{CurrentHeight, Convert}; -use substrate_primitives::Ed25519AuthorityId; +use primitives::traits::CurrentHeight; +use substrate_primitives::ed25519; use system::ensure_signed; use primitives::traits::MaybeSerializeDebug; +use ed25519::Public as AuthorityId; mod mock; mod tests; @@ -64,6 +65,8 @@ pub type Log = RawLog< pub trait GrandpaChangeSignal { /// Try to cast the log entry as a contained signal. fn as_signal(&self) -> Option>; + /// Try to cast the log entry as a contained forced signal. + fn as_forced_signal(&self) -> Option<(N, ScheduledChange)>; } /// A logs in this module. @@ -71,21 +74,34 @@ pub trait GrandpaChangeSignal { #[derive(Encode, Decode, PartialEq, Eq, Clone)] pub enum RawLog { /// Authorities set change has been signalled. Contains the new set of authorities - /// and the delay in blocks before applying. + /// and the delay in blocks _to finalize_ before applying. AuthoritiesChangeSignal(N, Vec<(SessionKey, u64)>), + /// 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. + ForcedAuthoritiesChangeSignal(N, N, Vec<(SessionKey, u64)>), } impl RawLog { /// Try to cast the log entry as a contained signal. pub fn as_signal(&self) -> Option<(N, &[(SessionKey, u64)])> { match *self { - RawLog::AuthoritiesChangeSignal(ref n, ref signal) => Some((n.clone(), signal)), + RawLog::AuthoritiesChangeSignal(ref delay, ref signal) => Some((delay.clone(), signal)), + RawLog::ForcedAuthoritiesChangeSignal(_, _, _) => None, + } + } + + /// Try to cast the log entry as a contained forced signal. + pub fn as_forced_signal(&self) -> Option<(N, N, &[(SessionKey, u64)])> { + match *self { + RawLog::ForcedAuthoritiesChangeSignal(ref median, ref delay, ref signal) => Some((median.clone(), delay.clone(), signal)), + RawLog::AuthoritiesChangeSignal(_, _) => None, } } } impl GrandpaChangeSignal for RawLog - where N: Clone, SessionKey: Clone + Into, + where N: Clone, SessionKey: Clone + Into, { fn as_signal(&self) -> Option> { RawLog::as_signal(self).map(|(delay, next_authorities)| ScheduledChange { @@ -96,6 +112,16 @@ impl GrandpaChangeSignal for RawLog .collect(), }) } + + fn as_forced_signal(&self) -> Option<(N, ScheduledChange)> { + RawLog::as_forced_signal(self).map(|(median, delay, next_authorities)| (median, ScheduledChange { + delay, + next_authorities: next_authorities.iter() + .cloned() + .map(|(k, w)| (k.into(), w)) + .collect(), + })) + } } pub trait Trait: system::Trait { @@ -109,8 +135,21 @@ pub trait Trait: system::Trait { type Event: From> + Into<::Event>; } -/// A stored pending change. +/// A stored pending change, old format. +// TODO: remove shim +// https://github.com/paritytech/substrate/issues/1614 #[derive(Encode, Decode)] +pub struct OldStoredPendingChange { + /// The block number this was scheduled at. + pub scheduled_at: N, + /// The delay in blocks until it will be applied. + pub delay: N, + /// The next authority set. + pub next_authorities: Vec<(SessionKey, u64)>, +} + +/// A stored pending change. +#[derive(Encode)] pub struct StoredPendingChange { /// The block number this was scheduled at. pub scheduled_at: N, @@ -118,9 +157,25 @@ pub struct StoredPendingChange { pub delay: N, /// The next authority set. pub next_authorities: Vec<(SessionKey, u64)>, + /// If defined it means the change was forced and the given block number + /// indicates the median last finalized block when the change was signaled. + pub forced: Option, +} + +impl Decode for StoredPendingChange { + fn decode(value: &mut I) -> Option { + let old = OldStoredPendingChange::decode(value)?; + let forced = >::decode(value).unwrap_or(None); + + Some(StoredPendingChange { + scheduled_at: old.scheduled_at, + delay: old.delay, + next_authorities: old.next_authorities, + forced, + }) + } } -/// GRANDPA events. decl_event!( pub enum Event where ::SessionKey { /// New authority set has been applied. @@ -132,6 +187,8 @@ decl_storage! { trait Store for Module as GrandpaFinality { // Pending change: (signalled at, scheduled change). PendingChange get(pending_change): Option>; + // next block number where we can force a change. + NextForced get(next_forced): Option; } add_extra_genesis { config(authorities): Vec<(T::SessionKey, u64)>; @@ -167,10 +224,18 @@ decl_module! { fn on_finalise(block_number: T::BlockNumber) { if let Some(pending_change) = >::get() { if block_number == pending_change.scheduled_at { - Self::deposit_log(RawLog::AuthoritiesChangeSignal( - pending_change.delay, - pending_change.next_authorities.clone(), - )); + if let Some(median) = pending_change.forced { + Self::deposit_log(RawLog::ForcedAuthoritiesChangeSignal( + median, + pending_change.delay, + pending_change.next_authorities.clone(), + )); + } else { + Self::deposit_log(RawLog::AuthoritiesChangeSignal( + pending_change.delay, + pending_change.next_authorities.clone(), + )); + } } if block_number == pending_change.scheduled_at + pending_change.delay { @@ -197,18 +262,39 @@ impl Module { /// `in_blocks` after the current block. This value may be 0, in which /// case the change is applied at the end of the current block. /// + /// If the `forced` parameter is defined, this indicates that the current + /// set has been synchronously determined to be offline and that after + /// `in_blocks` the given change should be applied. The given block number + /// indicates the median last finalized block number and it should be used + /// as the canon block when starting the new grandpa voter. + /// /// No change should be signalled while any change is pending. Returns /// an error if a change is already pending. pub fn schedule_change( next_authorities: Vec<(T::SessionKey, u64)>, in_blocks: T::BlockNumber, + forced: Option, ) -> Result { + use primitives::traits::As; + if Self::pending_change().is_none() { let scheduled_at = system::ChainContext::::default().current_height(); + + if let Some(_) = forced { + if Self::next_forced().map_or(false, |next| next > scheduled_at) { + return Err("Cannot signal forced change so soon after last."); + } + + // only allow the next forced change when twice the window has passed since + // this one. + >::put(scheduled_at + in_blocks * T::BlockNumber::sa(2)); + } + >::put(StoredPendingChange { delay: in_blocks, scheduled_at, next_authorities, + forced, }); Ok(()) @@ -223,13 +309,20 @@ impl Module { } } -impl Module where Ed25519AuthorityId: core::convert::From<::SessionKey> { - /// See if the digest contains any scheduled change. +impl Module where AuthorityId: core::convert::From<::SessionKey> { + /// See if the digest contains any standard scheduled change. pub fn scrape_digest_change(log: &Log) -> Option> { as GrandpaChangeSignal>::as_signal(log) } + + /// See if the digest contains any forced scheduled change. + pub fn scrape_digest_forced_change(log: &Log) + -> Option<(T::BlockNumber, ScheduledChange)> + { + as GrandpaChangeSignal>::as_forced_signal(log) + } } /// Helper for authorities being synchronized with the general session authorities. @@ -247,26 +340,43 @@ impl Default for SyncedAuthorities { } impl session::OnSessionChange for SyncedAuthorities where - T: Trait, - T: session::Trait, - ::ConvertAccountIdToSessionKey: Convert< - ::AccountId, - ::SessionKey, - >, + T: Trait + consensus::Trait::SessionKey>, + ::Log: From::SessionKey>> { fn on_session_change(_: X, _: bool) { use primitives::traits::Zero; - let next_authorities = >::validators() + let next_authorities = >::authorities() .into_iter() - .map(T::ConvertAccountIdToSessionKey::convert) .map(|key| (key, 1)) // evenly-weighted. .collect::::SessionKey, u64)>>(); // instant changes let last_authorities = >::grandpa_authorities(); if next_authorities != last_authorities { - let _ = >::schedule_change(next_authorities, Zero::zero()); + let _ = >::schedule_change(next_authorities, Zero::zero(), None); } } } + +impl finality_tracker::OnFinalizationStalled for SyncedAuthorities where + T: Trait + consensus::Trait::SessionKey>, + ::Log: From::SessionKey>>, + T: finality_tracker::Trait, +{ + fn on_stalled(further_wait: T::BlockNumber) { + // when we record old authority sets, we can use `finality_tracker::median` + // to figure out _who_ failed. until then, we can't meaningfully guard + // against `next == last` the way that normal session changes do. + + let next_authorities = >::authorities() + .into_iter() + .map(|key| (key, 1)) // evenly-weighted. + .collect::::SessionKey, u64)>>(); + + let median = >::median(); + + // schedule a change for `further_wait` blocks. + let _ = >::schedule_change(next_authorities, further_wait, Some(median)); + } +} diff --git a/srml/grandpa/src/mock.rs b/srml/grandpa/src/mock.rs index 7123e784ccf300d9a7da514bac52ee401a87ddc6..4405604ab19c07a9e074439ebc778ae3b10ac20c 100644 --- a/srml/grandpa/src/mock.rs +++ b/srml/grandpa/src/mock.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -23,8 +23,7 @@ use primitives::generic::DigestItem as GenDigestItem; use runtime_io; use srml_support::{impl_outer_origin, impl_outer_event}; use substrate_primitives::{H256, Blake2Hasher}; -use parity_codec::Encode; -use parity_codec_derive::{Encode, Decode}; +use parity_codec::{Encode, Decode}; use crate::{GenesisConfig, Trait, Module, RawLog}; impl_outer_origin!{ @@ -53,7 +52,7 @@ impl system::Trait for Test { type Hashing = ::primitives::traits::BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = TestEvent; type Log = DigestItem; diff --git a/srml/grandpa/src/tests.rs b/srml/grandpa/src/tests.rs index 74c998d873db0375cfb36f6d018da7544be23c24..37902cfb17d8ce20b2d7b4ea36eac2c6e93094a9 100644 --- a/srml/grandpa/src/tests.rs +++ b/srml/grandpa/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -24,12 +24,14 @@ use runtime_io::with_externalities; use crate::mock::{Grandpa, System, new_test_ext}; use system::{EventRecord, Phase}; use crate::{RawLog, RawEvent}; +use codec::{Decode, Encode}; +use super::*; #[test] fn authorities_change_logged() { with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { System::initialise(&1, &Default::default(), &Default::default()); - Grandpa::schedule_change(vec![(4, 1), (5, 1), (6, 1)], 0).unwrap(); + Grandpa::schedule_change(vec![(4, 1), (5, 1), (6, 1)], 0, None).unwrap(); System::note_finished_extrinsics(); Grandpa::on_finalise(1); @@ -54,7 +56,7 @@ fn authorities_change_logged() { fn authorities_change_logged_after_delay() { with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { System::initialise(&1, &Default::default(), &Default::default()); - Grandpa::schedule_change(vec![(4, 1), (5, 1), (6, 1)], 1).unwrap(); + Grandpa::schedule_change(vec![(4, 1), (5, 1), (6, 1)], 1, None).unwrap(); Grandpa::on_finalise(1); let header = System::finalise(); assert_eq!(header.digest, testing::Digest { @@ -84,25 +86,113 @@ fn authorities_change_logged_after_delay() { fn cannot_schedule_change_when_one_pending() { with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { System::initialise(&1, &Default::default(), &Default::default()); - Grandpa::schedule_change(vec![(4, 1), (5, 1), (6, 1)], 1).unwrap(); + Grandpa::schedule_change(vec![(4, 1), (5, 1), (6, 1)], 1, None).unwrap(); assert!(Grandpa::pending_change().is_some()); - assert!(Grandpa::schedule_change(vec![(5, 1)], 1).is_err()); + assert!(Grandpa::schedule_change(vec![(5, 1)], 1, None).is_err()); Grandpa::on_finalise(1); let header = System::finalise(); System::initialise(&2, &header.hash(), &Default::default()); assert!(Grandpa::pending_change().is_some()); - assert!(Grandpa::schedule_change(vec![(5, 1)], 1).is_err()); + assert!(Grandpa::schedule_change(vec![(5, 1)], 1, None).is_err()); Grandpa::on_finalise(2); let header = System::finalise(); System::initialise(&3, &header.hash(), &Default::default()); assert!(Grandpa::pending_change().is_none()); - assert!(Grandpa::schedule_change(vec![(5, 1)], 1).is_ok()); + assert!(Grandpa::schedule_change(vec![(5, 1)], 1, None).is_ok()); Grandpa::on_finalise(3); let _header = System::finalise(); }); } + +#[test] +fn new_decodes_from_old() { + let old = OldStoredPendingChange { + scheduled_at: 5u32, + delay: 100u32, + next_authorities: vec![(1u64, 5), (2u64, 10), (3u64, 2)], + }; + + let encoded = old.encode(); + let new = StoredPendingChange::::decode(&mut &encoded[..]).unwrap(); + assert!(new.forced.is_none()); + assert_eq!(new.scheduled_at, old.scheduled_at); + assert_eq!(new.delay, old.delay); + assert_eq!(new.next_authorities, old.next_authorities); +} + +#[test] +fn dispatch_forced_change() { + with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { + System::initialise(&1, &Default::default(), &Default::default()); + Grandpa::schedule_change( + vec![(4, 1), (5, 1), (6, 1)], + 5, + Some(0), + ).unwrap(); + + assert!(Grandpa::pending_change().is_some()); + assert!(Grandpa::schedule_change(vec![(5, 1)], 1, Some(0)).is_err()); + + Grandpa::on_finalise(1); + let mut header = System::finalise(); + + for i in 2..7 { + System::initialise(&i, &header.hash(), &Default::default()); + assert!(Grandpa::pending_change().unwrap().forced.is_some()); + assert_eq!(Grandpa::next_forced(), Some(11)); + assert!(Grandpa::schedule_change(vec![(5, 1)], 1, None).is_err()); + assert!(Grandpa::schedule_change(vec![(5, 1)], 1, Some(0)).is_err()); + + Grandpa::on_finalise(i); + header = System::finalise(); + } + + // change has been applied at the end of block 6. + // add a normal change. + { + System::initialise(&7, &header.hash(), &Default::default()); + assert!(Grandpa::pending_change().is_none()); + assert_eq!(Grandpa::grandpa_authorities(), vec![(4, 1), (5, 1), (6, 1)]); + assert!(Grandpa::schedule_change(vec![(5, 1)], 1, None).is_ok()); + Grandpa::on_finalise(7); + header = System::finalise(); + } + + // run the normal change. + { + System::initialise(&8, &header.hash(), &Default::default()); + assert!(Grandpa::pending_change().is_some()); + assert_eq!(Grandpa::grandpa_authorities(), vec![(4, 1), (5, 1), (6, 1)]); + assert!(Grandpa::schedule_change(vec![(5, 1)], 1, None).is_err()); + Grandpa::on_finalise(8); + header = System::finalise(); + } + + // normal change applied. but we can't apply a new forced change for some + // time. + for i in 9..11 { + System::initialise(&i, &header.hash(), &Default::default()); + assert!(Grandpa::pending_change().is_none()); + assert_eq!(Grandpa::grandpa_authorities(), vec![(5, 1)]); + assert_eq!(Grandpa::next_forced(), Some(11)); + assert!(Grandpa::schedule_change(vec![(5, 1), (6, 1)], 5, Some(0)).is_err()); + Grandpa::on_finalise(i); + header = System::finalise(); + } + + { + System::initialise(&11, &header.hash(), &Default::default()); + assert!(Grandpa::pending_change().is_none()); + assert!(Grandpa::schedule_change(vec![(5, 1), (6, 1), (7, 1)], 5, Some(0)).is_ok()); + assert_eq!(Grandpa::next_forced(), Some(21)); + Grandpa::on_finalise(11); + header = System::finalise(); + } + let _ = header; + }); +} diff --git a/srml/indices/Cargo.toml b/srml/indices/Cargo.toml index 2e7e2b5e33ce539c92d77685647b77a1673c5e8e..2331f325d1dd1aaf8fd42559bf143fc65bde7129 100644 --- a/srml/indices/Cargo.toml +++ b/srml/indices/Cargo.toml @@ -6,10 +6,10 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false} -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", default-features = false } +parity-codec-derive = { version = "3.1", default-features = false } 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 } @@ -24,7 +24,7 @@ ref_thread_local = "0.0" [features] default = ["std"] std = [ - "serde/std", + "serde", "safe-mix/std", "substrate-keyring", "parity-codec/std", diff --git a/srml/indices/src/address.rs b/srml/indices/src/address.rs index 5e313883e0b5b081347ecd1d0240123e9f447597..c7709e3bec3a5722b0662d141a65c9b494474d6c 100644 --- a/srml/indices/src/address.rs +++ b/srml/indices/src/address.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -54,7 +54,7 @@ impl From for Address(a: T, b: T) -> Option { - if a < b { Some(a) } else { None } + if a < b { Some(b) } else { None } } impl Decode for Address where @@ -108,3 +108,31 @@ impl Default for Address where Address::Id(Default::default()) } } + +#[cfg(test)] +mod tests { + use crate::{Encode, Decode}; + + type Address = super::Address<[u8; 8], u32>; + fn index(i: u32) -> Address { super::Address::Index(i) } + fn id(i: [u8; 8]) -> Address { super::Address::Id(i) } + + fn compare(a: Option
, d: &[u8]) { + if let Some(ref a) = a { + assert_eq!(d, &a.encode()[..]); + } + assert_eq!(Address::decode(&mut &d[..]), a); + } + + #[test] + fn it_should_work() { + compare(Some(index(2)), &[2][..]); + compare(None, &[240][..]); + compare(None, &[252, 239, 0][..]); + compare(Some(index(240)), &[252, 240, 0][..]); + compare(Some(index(304)), &[252, 48, 1][..]); + compare(None, &[253, 255, 255, 0, 0][..]); + compare(Some(index(0x10000)), &[253, 0, 0, 1, 0][..]); + compare(Some(id([42, 69, 42, 69, 42, 69, 42, 69])), &[255, 42, 69, 42, 69, 42, 69, 42, 69][..]); + } +} diff --git a/srml/indices/src/lib.rs b/srml/indices/src/lib.rs index c63f819d35d3f56cab6d9fc3ebf5a383223a26d5..76261796c8b78b6131fb1fb00794b897b473b8c9 100644 --- a/srml/indices/src/lib.rs +++ b/srml/indices/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -198,4 +198,7 @@ impl StaticLookup for Module { fn lookup(a: Self::Source) -> result::Result { Self::lookup_address(a).ok_or("invalid account index") } + fn unlookup(a: Self::Target) -> Self::Source { + address::Address::Id(a) + } } diff --git a/srml/indices/src/mock.rs b/srml/indices/src/mock.rs index 0123bc7fc834017ef134cd15bd68101db62190af..80d3fa2c4fc9d3a4d15e33f607a6d44a03d26ac1 100644 --- a/srml/indices/src/mock.rs +++ b/srml/indices/src/mock.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/srml/indices/src/tests.rs b/srml/indices/src/tests.rs index 965f155f2926676b90286ab716c58c41956bccff..7b60e305278c58be97d156b0bbffc892afe7b750 100644 --- a/srml/indices/src/tests.rs +++ b/srml/indices/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/srml/metadata/Cargo.toml b/srml/metadata/Cargo.toml index f5f30d8b5578258f267f4cc974088cdc9fd9c2c5..eed5e6b4e3379fad722aecc007b46e92ab5d2de3 100644 --- a/srml/metadata/Cargo.toml +++ b/srml/metadata/Cargo.toml @@ -5,8 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", default-features = false, features = ["derive"] } serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } @@ -16,7 +15,6 @@ primitives = { package = "substrate-primitives", path = "../../core/primitives", default = ["std"] std = [ "parity-codec/std", - "parity-codec-derive/std", "rstd/std", "primitives/std", "serde", diff --git a/srml/metadata/src/lib.rs b/srml/metadata/src/lib.rs index 6b67b5adb5d395e6d0bde8bbb7db6c28824afff9..9b03daafa65d3e81152e0f44e991b0c924e7b85c 100644 --- a/srml/metadata/src/lib.rs +++ b/srml/metadata/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -26,10 +26,7 @@ use serde_derive::Serialize; #[cfg(feature = "std")] use parity_codec::{Decode, Input}; -#[cfg(feature = "std")] -use parity_codec_derive::Decode; use parity_codec::{Encode, Output}; -use parity_codec_derive::Encode; use rstd::vec::Vec; #[cfg(feature = "std")] @@ -216,7 +213,7 @@ pub trait DefaultByte { fn default_byte(&self) -> Vec; } -/// Wrapper over dyn pointer for accessing a cached once byet value. +/// Wrapper over dyn pointer for accessing a cached once byte value. #[derive(Clone)] pub struct DefaultByteGetter(pub &'static dyn DefaultByte); @@ -264,7 +261,14 @@ pub enum StorageFunctionType { Map { key: DecodeDifferentStr, value: DecodeDifferentStr, - } + is_linked: bool, + }, + DoubleMap { + key1: DecodeDifferentStr, + key2: DecodeDifferentStr, + value: DecodeDifferentStr, + key2_hasher: DecodeDifferentStr, + }, } /// A storage function modifier. @@ -304,8 +308,12 @@ pub struct RuntimeMetadataPrefixed(pub u32, pub RuntimeMetadata); pub enum RuntimeMetadata { /// Unused; enum filler. V0(RuntimeMetadataDeprecated), - /// Version 1 for runtime metadata. - V1(RuntimeMetadataV1), + /// Version 1 for runtime metadata. No longer used. + V1(RuntimeMetadataDeprecated), + /// Version 2 for runtime metadata. No longer used. + V2(RuntimeMetadataDeprecated), + /// Version 3 for runtime metadata. + V3(RuntimeMetadataV3), } /// Enum that should fail. @@ -325,10 +333,10 @@ impl Decode for RuntimeMetadataDeprecated { } } -/// The metadata of a runtime version 1. +/// The metadata of a runtime. #[derive(Eq, Encode, PartialEq)] #[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] -pub struct RuntimeMetadataV1 { +pub struct RuntimeMetadataV3 { pub modules: DecodeDifferentArray, } diff --git a/srml/session/Cargo.toml b/srml/session/Cargo.toml index 318bcdceb4980a91109b12780efca1a989a6dce6..4f1fe086cffdab125a8e59210c14d6858915c28c 100644 --- a/srml/session/Cargo.toml +++ b/srml/session/Cargo.toml @@ -6,10 +6,10 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false} -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", default-features = false } +parity-codec-derive = { version = "3.1", 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 } srml-support = { path = "../support", default-features = false } @@ -20,11 +20,12 @@ timestamp = { package = "srml-timestamp", path = "../timestamp", default-feature [dev-dependencies] substrate-primitives = { path = "../../core/primitives" } runtime_io = { package = "sr-io", path = "../../core/sr-io" } +lazy_static = "1.0" [features] default = ["std"] std = [ - "serde/std", + "serde", "safe-mix/std", "parity-codec/std", "parity-codec-derive/std", diff --git a/srml/session/src/lib.rs b/srml/session/src/lib.rs index 7f74811bfc24f1c15f3c72e9052864e3b86cb13b..9143931b98f9b419e85c21629a148790af5aefb4 100644 --- a/srml/session/src/lib.rs +++ b/srml/session/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -22,7 +22,7 @@ use rstd::prelude::*; use primitives::traits::{As, Zero, One, Convert}; use srml_support::{StorageValue, StorageMap, for_each_tuple, decl_module, decl_event, decl_storage}; -use srml_support::dispatch::Result; +use srml_support::{dispatch::Result, traits::OnFreeBalanceZero}; use system::ensure_signed; use rstd::ops::Mul; @@ -50,8 +50,8 @@ macro_rules! impl_session_change { for_each_tuple!(impl_session_change); -pub trait Trait: timestamp::Trait { - type ConvertAccountIdToSessionKey: Convert; +pub trait Trait: timestamp::Trait + consensus::Trait { + type ConvertAccountIdToSessionKey: Convert>; type OnSessionChange: OnSessionChange; type Event: From> + Into<::Event>; } @@ -84,7 +84,6 @@ decl_module! { } } -/// An event in this module. decl_event!( pub enum Event where ::BlockNumber { /// New session has happened. Note that the argument is the session index, not the block @@ -110,10 +109,15 @@ decl_storage! { /// Block at which the session length last changed. LastLengthChange: Option; /// The next key for a given validator. - NextKeyFor: map T::AccountId => Option; + NextKeyFor build(|config: &GenesisConfig| { + config.keys.clone() + }): map T::AccountId => Option; /// The next session length. NextSessionLength: Option; } + add_extra_genesis { + config(keys): Vec<(T::AccountId, T::SessionKey)>; + } } impl Module { @@ -136,13 +140,10 @@ impl Module { /// Set the current set of validators. /// - /// Called by `staking::new_era()` only. `next_session` should be called after this in order to + /// Called by `staking::new_era()` only. `rotate_session` must be called after this in order to /// update the session keys to the next validator set. pub fn set_validators(new: &[T::AccountId]) { >::put(&new.to_vec()); - >::set_authorities( - &new.iter().cloned().map(T::ConvertAccountIdToSessionKey::convert).collect::>() - ); } /// Hook to be called after transaction processing. @@ -185,16 +186,21 @@ impl Module { T::OnSessionChange::on_session_change(time_elapsed, apply_rewards); // Update any changes in session keys. - Self::validators().iter().enumerate().for_each(|(i, v)| { - if let Some(n) = >::take(v) { - >::set_authority(i as u32, &n); - } - }); + let v = Self::validators(); + >::set_authority_count(v.len() as u32); + for (i, v) in v.into_iter().enumerate() { + >::set_authority( + i as u32, + &>::get(&v) + .or_else(|| T::ConvertAccountIdToSessionKey::convert(v)) + .unwrap_or_default() + ); + }; } /// Get the time that should have elapsed over a session if everything was working perfectly. pub fn ideal_session_duration() -> T::Moment { - let block_period: T::Moment = >::block_period(); + let block_period: T::Moment = >::minimum_period(); let session_length: T::BlockNumber = Self::length(); Mul::::mul(block_period, session_length) } @@ -210,9 +216,16 @@ impl Module { } } +impl OnFreeBalanceZero for Module { + fn on_free_balance_zero(who: &T::AccountId) { + >::remove(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}; @@ -224,6 +237,17 @@ mod tests { pub enum Origin for Test {} } + thread_local!{ + static NEXT_VALIDATORS: RefCell> = RefCell::new(vec![1, 2, 3]); + } + + pub struct TestOnSessionChange; + impl OnSessionChange for TestOnSessionChange { + fn on_session_change(_elapsed: u64, _should_reward: bool) { + NEXT_VALIDATORS.with(|v| Session::set_validators(&*v.borrow())); + } + } + #[derive(Clone, Eq, PartialEq)] pub struct Test; impl consensus::Trait for Test { @@ -239,7 +263,7 @@ mod tests { type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; @@ -250,7 +274,7 @@ mod tests { } impl Trait for Test { type ConvertAccountIdToSessionKey = ConvertUintAuthorityId; - type OnSessionChange = (); + type OnSessionChange = TestOnSessionChange; type Event = (); } @@ -262,14 +286,15 @@ mod tests { let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; t.extend(consensus::GenesisConfig::{ code: vec![], - authorities: vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)], + authorities: NEXT_VALIDATORS.with(|l| l.borrow().iter().cloned().map(UintAuthorityId).collect()), }.build_storage().unwrap().0); t.extend(timestamp::GenesisConfig::{ - period: 5, + minimum_period: 5, }.build_storage().unwrap().0); t.extend(GenesisConfig::{ session_length: 2, - validators: vec![1, 2, 3], + validators: NEXT_VALIDATORS.with(|l| l.borrow().clone()), + keys: vec![], }.build_storage().unwrap().0); runtime_io::TestExternalities::new(t) } @@ -277,12 +302,35 @@ mod tests { #[test] fn simple_setup_should_work() { with_externalities(&mut new_test_ext(), || { - assert_eq!(Consensus::authorities(), vec![UintAuthorityId(1).into(), UintAuthorityId(2).into(), UintAuthorityId(3).into()]); + assert_eq!(Consensus::authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); assert_eq!(Session::length(), 2); assert_eq!(Session::validators(), vec![1, 2, 3]); }); } + #[test] + fn authorities_should_track_validators() { + with_externalities(&mut new_test_ext(), || { + NEXT_VALIDATORS.with(|v| *v.borrow_mut() = vec![1, 2]); + assert_ok!(Session::force_new_session(false)); + Session::check_rotate_session(1); + assert_eq!(Session::validators(), vec![1, 2]); + assert_eq!(Consensus::authorities(), vec![UintAuthorityId(1), UintAuthorityId(2)]); + + NEXT_VALIDATORS.with(|v| *v.borrow_mut() = vec![1, 2, 4]); + assert_ok!(Session::force_new_session(false)); + Session::check_rotate_session(2); + assert_eq!(Session::validators(), vec![1, 2, 4]); + assert_eq!(Consensus::authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(4)]); + + NEXT_VALIDATORS.with(|v| *v.borrow_mut() = vec![1, 2, 3]); + assert_ok!(Session::force_new_session(false)); + Session::check_rotate_session(3); + assert_eq!(Session::validators(), vec![1, 2, 3]); + assert_eq!(Consensus::authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); + }); + } + #[test] fn should_work_with_early_exit() { with_externalities(&mut new_test_ext(), || { diff --git a/srml/staking/Cargo.toml b/srml/staking/Cargo.toml index a5cbeb06c4a9f33c3f127dc13feafa5a961bee98..967cee3391f08fe8b323fb1d65ef917e5bb75495 100644 --- a/srml/staking/Cargo.toml +++ b/srml/staking/Cargo.toml @@ -6,12 +6,12 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false} -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", 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 } consensus = { package = "srml-consensus", path = "../consensus", default-features = false } @@ -20,19 +20,18 @@ session = { package = "srml-session", path = "../session", default-features = fa [dev-dependencies] substrate-primitives = { path = "../../core/primitives" } -runtime_io = { package = "sr-io", path = "../../core/sr-io" } timestamp = { package = "srml-timestamp", path = "../timestamp" } balances = { package = "srml-balances", path = "../balances" } [features] default = ["std"] std = [ - "serde/std", + "serde", "safe-mix/std", "substrate-keyring", "parity-codec/std", - "parity-codec-derive/std", "rstd/std", + "runtime_io/std", "srml-support/std", "primitives/std", "session/std", diff --git a/srml/staking/src/lib.rs b/srml/staking/src/lib.rs index 34fa4f036c83808ee0ae1bfc81fb41b7629d6d54..21cc6cbf9dc50f77b42cb344cde51c485737a912 100644 --- a/srml/staking/src/lib.rs +++ b/srml/staking/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -6,8 +6,6 @@ // 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 @@ -16,34 +14,263 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! Staking manager: Periodically determines the best set of validators. +//! # Staking Module +//! +//! +//! The staking module is the means by which a set of network maintainers (known as "authorities" in some contexts and "validators" in others) +//! are chosen based upon those who voluntarily place funds under deposit. Under deposit, those funds are rewarded under +//! normal operation but are held at pain of "slash" (expropriation) should the staked maintainer be found not to be +//! discharging their duties properly. +//! You can start using the Staking module by implementing the staking [`Trait`]. +//! +//! ## Overview +//! +//! ### Terminology +//! +//! +//! - Staking: The process of locking up funds for some time, placing them at risk of slashing (loss) in order to become a rewarded maintainer of the network. +//! - Validating: The process of running a node to actively maintain the network, either by producing blocks or guaranteeing finality of the chain. +//! - Nominating: The process of placing staked funds behind one or more validators in order to share in any reward, and punishment, they take. +//! - Stash account: The account holding an owner's funds used for staking. +//! - Controller account: The account which controls an owner's funds for staking. +//! - Era: A (whole) number of sessions, which is the period that the validator set (and each validator's active nominator set) is recalculated and where rewards are paid out. +//! - Slash: The punishment of a staker by reducing their funds ([reference](#references)). +//! +//! ### Goals +//! +//! +//! The staking system in Substrate NPoS is designed to achieve three goals: +//! - It should be possible to stake funds that are controlled by a cold wallet. +//! - It should be possible to withdraw some, or deposit more, funds without interrupting the role of an entity. +//! - It should be possible to switch between roles (nominator, validator, idle) with minimal overhead. +//! +//! ### Scenarios +//! +//! #### Staking +//! +//! Almost any interaction with the staking module requires at least one account to become **bonded**, also known as +//! being a **staker**. For this, all that it is needed is a secondary _**stash account**_ which will hold the staked funds. +//! Henceforth, the former account that initiated the interest is called the **controller** and the latter, holding the +//! funds, is named the **stash**. Also, note that this implies that entering the staking process requires an _account +//! pair_, one to take the role of the controller and one to be the frozen stash account (any value locked in +//! stash cannot be used, hence called _frozen_). This process in the public API is mostly referred to as _bonding_ via +//! the `bond()` function. +//! +//! Any account pair successfully placed at stake can accept three possible roles, namely: `validate`, `nominate` or +//! simply `chill`. Note that during the process of accepting these roles, the _controller_ account is always responsible +//! for declaring interest and the _stash_ account stays untouched, without directly interacting in any operation. +//! +//! #### Validating +//! +//! A **validator** takes the role of either validating blocks or ensuring their finality, maintaining the veracity of +//! the network. A validator should avoid both any sort of malicious misbehavior and going offline. +//! Bonded accounts that state interest in being a validator do NOT get immediately chosen as a validator. Instead, they +//! are declared as a _candidate_ and they _might_ get elected at the _next **era**_ as a validator. The result of the +//! election is determined by nominators and their votes. An account can become a validator via the `validate()` call. +//! +//! #### Nomination +//! +//! A **nominator** does not take any _direct_ role in maintaining the network, instead, it votes on a set of validators +//! to be elected. Once interest in nomination is stated by an account, it takes effect _immediately_, meaning that its +//! votes will be taken into account at the next election round. As mentioned above, a nominator must also place some +//! funds in a stash account, essentially indicating the _weight_ of its vote. In some sense, the nominator bets on the +//! honesty of a set of validators by voting for them, with the goal of having a share of the reward granted to them. +//! Any rewards given to a validator is shared among that validator and all of the nominators that voted for it. The +//! same logic applies to the slash of a validator; if a validator misbehaves all of its nominators also get slashed. +//! This rule incentivizes the nominators to NOT vote for the misbehaving/offline validators as much as possible, simply +//! because the nominators will also lose funds if they vote poorly. An account can become a nominator via the +//! `nominate()` call. +//! +//! #### Rewards and Slash +//! +//! The **reward and slashing** procedure are the core of the staking module, attempting to _embrace valid behavior_ +//! while _punishing any misbehavior or lack of availability_. Slashing can occur at any point in time, once +//! misbehavior is reported. One such misbehavior is a validator being detected as offline more than a certain number of +//! times. Once slashing is determined, a value is deducted from the balance of the validator and all the nominators who +//! voted for this validator. Same rules apply to the rewards in the sense of being shared among a validator and its +//! associated nominators. +//! +//! Finally, any of the roles above can choose to step back temporarily and just chill for a while. This means that if +//! they are a nominator, they will not be considered as voters anymore and if they are validators, they will no longer +//! be a candidate for the next election (again, both effects apply at the beginning of the next era). An account can +//! step back via the `chill()` call. +//! +//! ## Interface +//! +//! ### Types +//! +//! - `Currency`: Used as the measurement means of staking and funds management. +//! +//! ### Dispatchable +//! +//! The Dispatchable functions of the staking module enable the steps needed for entities to accept and change their +//! role, alongside some helper functions to get/set the metadata of the module. +//! +//! Please refer to the [`Call`] enum and its associated variants for a detailed list of dispatchable functions. +//! +//! ### Public +//! The staking module contains many public storage items and (im)mutable functions. Please refer to the [struct list](#structs) +//! below and the [`Module`](https://crates.parity.io/srml_staking/struct.Module.html) struct definition for more details. +//! +//! ## Usage +//! +//! +//! ### Snippet: Bonding and Accepting Roles +//! +//! An arbitrary account pair, given that the associated stash has the required funds, can become stakers via the following call: +//! +//! ```rust,ignore +//! // bond account 3 as stash +//! // account 4 as controller +//! // with stash value 1500 units +//! // while the rewards get transferred to the controller account. +//! Staking::bond(Origin::signed(3), 4, 1500, RewardDestination::Controller); +//! ``` +//! +//! To state desire to become a validator: +//! +//! ```rust,ignore +//! // controller account 4 states desire for validation with the given preferences. +//! Staking::validate(Origin::signed(4), ValidatorPrefs::default()); +//! ``` +//! +//! Note that, as mentioned, the stash account is transparent in such calls and only the controller initiates the function calls. +//! +//! Similarly, to state desire in nominating: +//! +//! ```rust,ignore +//! // controller account 4 nominates for account 10 and 20. +//! Staking::nominate(Origin::signed(4), vec![20, 10]); +//! ``` +//! +//! Finally, account 4 can withdraw from any of the above roles via +//! +//! ```rust,ignore +//! Staking::chill(Origin::signed(4)); +//! ``` +//! +//! ## Implementation Details +//! +//! ### Slot Stake +//! +//! The term `slot_stake` will be used throughout this section. It refers to a value calculated at the end of each era, +//! containing the _minimum value at stake among all validators._ +//! +//! ### Reward Calculation +//! +//! - Rewards are recorded **per-session** and paid **per-era**. The value of the reward for each session is calculated at +//! the end of the session based on the timeliness of the session, then accumulated to be paid later. The value of +//! the new _per-session-reward_ is calculated at the end of each era by multiplying `slot_stake` and a configuration +//! storage item named `SessionReward`. +//! - Once a new era is triggered, rewards are paid to the validators and the associated nominators. +//! - The validator can declare an amount, named `validator_payment`, that does not get shared with the nominators at +//! each reward payout through their `ValidatorPrefs`. This value gets deducted from the total reward that can be paid. +//! The remaining portion is split among the validator and all of the nominators who had a vote for this validator, +//! proportional to their staked value. +//! - All entities who receive a reward have the option to choose their reward destination, through the `Payee` storage item (see `set_payee()`), to be one of the following: +//! - Controller account. +//! - Stash account, not increasing the staked value. +//! - Stash account, also increasing the staked value. +//! +//! ### Slashing details +//! +//! - A validator can be _reported_ to be offline at any point via `on_offline_validator` public function. +//! - Each validator declares how many times it can be _reported_ before it actually gets slashed via the +//! `unstake_threshold` in `ValidatorPrefs`. On top of this, the module also introduces an `OfflineSlashGrace`, +//! which applies to all validators and prevents them from getting immediately slashed. +//! - Similar to the reward value, the slash value is updated at the end of each era by multiplying `slot_stake` and a +//! configuration storage item, `OfflineSlash`. +//! - Once a validator has been reported a sufficient number of times, the actual value that gets deducted from that +//! validator, and every single nominator that voted for it is calculated by multiplying the result of the above point +//! by `2.pow(unstake_threshold)`. +//! - If the previous overflows, then `slot_stake` is used. +//! - If the previous is more than what the validator/nominator has in stake, all of its stake is slashed (`.max(total_stake)`). +//! +//! ### Additional Fund Management Operations +//! +//! Any funds already placed into stash can be the target of the following operations: +//! +//! - The controller account can free a portion (or all) of the funds using the `unbond()` call. Note that the funds +//! are not immediately accessible, instead, a duration denoted by `BondingDuration` (in number of eras) must pass until the funds can actually be removed. +//! - To actually remove the funds, once the bonding duration is over, `withdraw_unbonded()` can be used. +//! - As opposed to the above, additional funds can be added to the stash account via the `bond_extra()` transaction call. +//! +//! ### Election algorithm details. +//! +//! The current election algorithm is implemented based on Phragmén. The reference implementation can be found [here](https://github.com/w3f/consensus/tree/master/NPoS). +//! +//! ## GenesisConfig +//! +//! See the [`GensisConfig`] for a list of attributes that can be provided. +//! +//! ## Related Modules +//! +//! - [**Balances**](https://crates.parity.io/srml_balances/index.html): Used to manage values at stake. +//! - [**Sessions**](https://crates.parity.io/srml_session/index.html): Used to manage sessions. Also, a list of new validators is also stored in the sessions module's `Validators` at the end of each era. +//! - [**System**](https://crates.parity.io/srml_system/index.html): Used to obtain block number and time, among other details. +//! +//! # References +//! +//! 1. This document is written as a more verbose version of the original [Staking.md](../Staking.md) file. Some sections, are taken directly from the aforementioned document. + #![cfg_attr(not(feature = "std"), no_std)] -use rstd::{prelude::*, cmp}; -use parity_codec::HasCompact; -use parity_codec_derive::{Encode, Decode}; -use srml_support::{Parameter, StorageValue, StorageMap, dispatch::Result}; +#[cfg(feature = "std")] +use runtime_io::with_storage; +use rstd::{prelude::*, result}; +use parity_codec::{HasCompact, Encode, Decode}; +use srml_support::{StorageValue, StorageMap, EnumerableStorageMap, dispatch::Result}; use srml_support::{decl_module, decl_event, decl_storage, ensure}; -use srml_support::traits::{Currency, OnDilution, EnsureAccountLiquid, OnFreeBalanceZero, ArithmeticType}; +use srml_support::traits::{ + Currency, OnFreeBalanceZero, OnDilution, LockIdentifier, LockableCurrency, WithdrawReasons, + OnUnbalanced, Imbalance +}; use session::OnSessionChange; use primitives::Perbill; -use primitives::traits::{Zero, One, Bounded, As, StaticLookup}; +use primitives::traits::{Zero, One, As, StaticLookup, CheckedSub, Saturating, Bounded}; +#[cfg(feature = "std")] +use primitives::{Serialize, Deserialize}; use system::ensure_signed; mod mock; - mod tests; +mod phragmen; + +use phragmen::{elect, ElectionConfig}; const RECENT_OFFLINE_COUNT: usize = 32; const DEFAULT_MINIMUM_VALIDATOR_COUNT: u32 = 4; +const MAX_NOMINATIONS: usize = 16; +const MAX_UNSTAKE_THRESHOLD: u32 = 10; + +/// Indicates the initial status of the staker. +#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] +pub enum StakerStatus { + /// Chilling. + Idle, + /// Declared state in validating or already participating in it. + Validator, + /// Nominating for a group of other stakers. + Nominator(Vec), +} + +/// A destination account for payment. +#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Debug))] +pub enum RewardDestination { + /// Pay into the stash account, increasing the amount at stake accordingly. + Staked, + /// Pay into the stash account, not increasing the amount at stake. + Stash, + /// Pay into the controller account. + Controller, +} -#[derive(PartialEq, Clone)] -#[cfg_attr(test, derive(Debug))] -pub enum LockStatus { - Liquid, - LockedUntil(BlockNumber), - Bonded, +impl Default for RewardDestination { + fn default() -> Self { + RewardDestination::Staked + } } /// Preference of what happens on a slash event. @@ -53,7 +280,7 @@ pub struct ValidatorPrefs { /// Validator should ensure this many more slashes than is necessary before being unstaked. #[codec(compact)] pub unstake_threshold: u32, - // Reward that validator takes up-front; only the rest is split between themselves and nominators. + /// Reward that validator takes up-front; only the rest is split between themselves and nominators. #[codec(compact)] pub validator_payment: Balance, } @@ -67,113 +294,398 @@ impl Default for ValidatorPrefs { } } -type BalanceOf = <::Currency as ArithmeticType>::Type; +/// Just a Balance/BlockNumber tuple to encode when a chunk of funds will be unlocked. +#[derive(PartialEq, Eq, Clone, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Debug))] +pub struct UnlockChunk { + /// Amount of funds to be unlocked. + #[codec(compact)] + value: Balance, + /// Era number at which point it'll be unlocked. + #[codec(compact)] + era: BlockNumber, +} + +/// The ledger of a (bonded) stash. +#[derive(PartialEq, Eq, Clone, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Debug))] +pub struct StakingLedger { + /// The stash account whose balance is actually locked and at stake. + pub stash: AccountId, + /// The total amount of the stash's balance that we are currently accounting for. + /// It's just `active` plus all the `unlocking` balances. + #[codec(compact)] + pub total: Balance, + /// The total amount of the stash's balance that will be at stake in any forthcoming + /// rounds. + #[codec(compact)] + pub active: Balance, + /// Any balance that is becoming free, which may eventually be transferred out + /// of the stash (assuming it doesn't get slashed first). + pub unlocking: Vec>, +} + +impl< + AccountId, + Balance: HasCompact + Copy + Saturating, + BlockNumber: HasCompact + PartialOrd +> StakingLedger { + /// Remove entries from `unlocking` that are sufficiently old and reduce the + /// total by the sum of their balances. + fn consolidate_unlocked(self, current_era: BlockNumber) -> Self { + let mut total = self.total; + let unlocking = self.unlocking.into_iter() + .filter(|chunk| if chunk.era > current_era { + true + } else { + total = total.saturating_sub(chunk.value); + false + }) + .collect(); + Self { total, active: self.active, stash: self.stash, unlocking } + } +} + +/// The amount of exposure (to slashing) than an individual nominator has. +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Debug))] +pub struct IndividualExposure { + /// The stash account of the nominator in question. + who: AccountId, + /// Amount of funds exposed. + #[codec(compact)] + value: Balance, +} + +/// A snapshot of the stake backing a single validator in the system. +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Default)] +#[cfg_attr(feature = "std", derive(Debug))] +pub struct Exposure { + /// The total balance backing this validator. + #[codec(compact)] + pub total: Balance, + /// The validator's own stash that is exposed. + #[codec(compact)] + pub own: Balance, + /// The portions of nominators stashes that are exposed. + pub others: Vec>, +} + +type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +type PositiveImbalanceOf = <::Currency as Currency<::AccountId>>::PositiveImbalance; +type NegativeImbalanceOf = <::Currency as Currency<::AccountId>>::NegativeImbalance; pub trait Trait: system::Trait + session::Trait { /// The staking balance. - type Currency: ArithmeticType + Currency>; + type Currency: + Currency + + LockableCurrency; /// Some tokens minted. type OnRewardMinted: OnDilution>; /// The overarching event type. type Event: From> + Into<::Event>; + + /// Handler for the unbalanced reduction when slashing a staker. + type Slash: OnUnbalanced>; + + /// Handler for the unbalanced increment when rewarding a staker. + type Reward: OnUnbalanced>; +} + +const STAKING_ID: LockIdentifier = *b"staking "; + +decl_storage! { + trait Store for Module as Staking { + + /// The ideal number of staking participants. + pub ValidatorCount get(validator_count) config(): u32; + /// Minimum number of staking participants before emergency conditions are imposed. + pub MinimumValidatorCount get(minimum_validator_count) config(): u32 = DEFAULT_MINIMUM_VALIDATOR_COUNT; + /// The length of a staking era in sessions. + pub SessionsPerEra get(sessions_per_era) config(): T::BlockNumber = T::BlockNumber::sa(1000); + /// Maximum reward, per validator, that is provided per acceptable session. + pub SessionReward get(session_reward) config(): Perbill = Perbill::from_billionths(60); + /// Slash, per validator that is taken for the first time they are found to be offline. + pub OfflineSlash get(offline_slash) config(): Perbill = Perbill::from_millionths(1000); // Perbill::from_fraction() is only for std, so use from_millionths(). + /// Number of instances of offline reports before slashing begins for validators. + pub OfflineSlashGrace get(offline_slash_grace) config(): u32; + /// The length of the bonding duration in blocks. + pub BondingDuration get(bonding_duration) config(): T::BlockNumber = T::BlockNumber::sa(1000); + + /// Any validators that may never be slashed or forcibly kicked. It's a Vec since they're easy to initialise + /// and the performance hit is minimal (we expect no more than four invulnerables) and restricted to testnets. + pub Invulnerables get(invulnerables) config(): Vec; + + /// Map from all locked "stash" accounts to the controller account. + pub Bonded get(bonded): map T::AccountId => Option; + /// Map from all (unlocked) "controller" accounts to the info regarding the staking. + pub Ledger get(ledger): map T::AccountId => Option, T::BlockNumber>>; + + /// Where the reward payment should be made. Keyed by stash. + pub Payee get(payee): map T::AccountId => RewardDestination; + + /// The map from (wannabe) validator stash key to the preferences of that validator. + pub Validators get(validators): linked_map T::AccountId => ValidatorPrefs>; + + /// The map from nominator stash key to the set of stash keys of all validators to nominate. + pub Nominators get(nominators): linked_map T::AccountId => Vec; + + /// Nominators for a particular account that is in action right now. You can't iterate through validators here, + /// but you can find them in the `sessions` module. + /// + /// 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; + + /// The current era index. + pub CurrentEra get(current_era) config(): T::BlockNumber; + + /// Maximum reward, per validator, that is provided per acceptable session. + pub CurrentSessionReward get(current_session_reward) config(): BalanceOf; + + /// The accumulated reward for the current era. Reset to zero at the beginning of the era and + /// increased for every successfully finished session. + pub CurrentEraReward get(current_era_reward): BalanceOf; + + /// The next value of sessions per era. + pub NextSessionsPerEra get(next_sessions_per_era): Option; + /// The session index at which the era length last changed. + pub LastEraLengthChange get(last_era_length_change): T::BlockNumber; + + /// The amount of balance actively at stake for each validator slot, currently. + /// + /// This is used to derive rewards and punishments. + pub SlotStake get(slot_stake) build(|config: &GenesisConfig| { + config.stakers.iter().map(|&(_, _, value, _)| value).min().unwrap_or_default() + }): BalanceOf; + + /// The number of times a given validator has been reported offline. This gets decremented by one each era that passes. + pub SlashCount get(slash_count): map T::AccountId => u32; + + /// We are forcing a new era. + pub ForcingNewEra get(forcing_new_era): Option<()>; + + /// Most recent `RECENT_OFFLINE_COUNT` instances. (who it was, when it was reported, how many instances they were offline for). + pub RecentlyOffline get(recently_offline): Vec<(T::AccountId, T::BlockNumber, u32)>; + } + add_extra_genesis { + config(stakers): Vec<(T::AccountId, T::AccountId, BalanceOf, StakerStatus)>; + build(|storage: &mut primitives::StorageOverlay, _: &mut primitives::ChildrenStorageOverlay, config: &GenesisConfig| { + with_storage(storage, || { + for &(ref stash, ref controller, balance, ref status) in &config.stakers { + assert!(T::Currency::free_balance(&stash) >= balance); + let _ = >::bond( + T::Origin::from(Some(stash.clone()).into()), + T::Lookup::unlookup(controller.clone()), + balance, + RewardDestination::Staked + ); + let _ = match status { + StakerStatus::Validator => { + >::validate( + T::Origin::from(Some(controller.clone()).into()), + Default::default() + ) + }, StakerStatus::Nominator(votes) => { + >::nominate( + T::Origin::from(Some(controller.clone()).into()), + votes.iter().map(|l| {T::Lookup::unlookup(l.clone())}).collect() + ) + }, _ => Ok(()) + }; + } + + >::select_validators(); + }); + }); + } } decl_module! { pub struct Module for enum Call where origin: T::Origin { fn deposit_event() = default; - /// Declare the desire to stake for the transactor. + /// Take the origin account as a stash and lock up `value` of its balance. `controller` will be the + /// account that controls it. /// - /// Effects will be felt at the beginning of the next era. - fn stake(origin) { - let who = ensure_signed(origin)?; - ensure!(Self::nominating(&who).is_none(), "Cannot stake if already nominating."); - let mut intentions = >::get(); - // can't be in the list twice. - ensure!(intentions.iter().find(|&t| t == &who).is_none(), "Cannot stake if already staked."); - - >::insert(&who, T::BlockNumber::max_value()); - intentions.push(who); - >::put(intentions); - } + /// The dispatch origin for this call must be _Signed_. + fn bond(origin, controller: ::Source, #[compact] value: BalanceOf, payee: RewardDestination) { + let stash = ensure_signed(origin)?; - /// Retract the desire to stake for the transactor. - /// - /// Effects will be felt at the beginning of the next era. - fn unstake(origin, #[compact] intentions_index: u32) -> Result { - let who = ensure_signed(origin)?; - // unstake fails in degenerate case of having too few existing staked parties - if Self::intentions().len() <= Self::minimum_validator_count() as usize { - return Err("cannot unstake when there are too few staked participants") + if >::exists(&stash) { + return Err("stash already bonded") + } + + let controller = T::Lookup::lookup(controller)?; + + if >::exists(&controller) { + return Err("controller already paired") } - Self::apply_unstake(&who, intentions_index as usize) - } - fn nominate(origin, target: ::Source) { - let who = ensure_signed(origin)?; - let target = T::Lookup::lookup(target)?; + // You're auto-bonded forever, here. We might improve this by only bonding when + // you actually validate/nominate. + >::insert(&stash, controller.clone()); + >::insert(&stash, payee); - ensure!(Self::nominating(&who).is_none(), "Cannot nominate if already nominating."); - ensure!(Self::intentions().iter().find(|&t| t == &who).is_none(), "Cannot nominate if already staked."); + let stash_balance = T::Currency::free_balance(&stash); + let value = value.min(stash_balance); + Self::update_ledger(&controller, &StakingLedger { stash, total: value, active: value, unlocking: vec![] }); + } + + /// Add some extra amount that have appeared in the stash `free_balance` into the balance up for + /// staking. + /// + /// Use this if there are additional funds in your stash account that you wish to bond. + /// + /// The dispatch origin for this call must be _Signed_ by the stash, not the controller. + fn bond_extra(origin, #[compact] max_additional: BalanceOf) { + let stash = ensure_signed(origin)?; - // update nominators_for - let mut t = Self::nominators_for(&target); - t.push(who.clone()); - >::insert(&target, t); + let controller = Self::bonded(&stash).ok_or("not a stash")?; + let mut ledger = Self::ledger(&controller).ok_or("not a controller")?; - // update nominating - >::insert(&who, &target); + let stash_balance = T::Currency::free_balance(&stash); - // Update bondage - >::insert(&who, T::BlockNumber::max_value()); + if let Some(extra) = stash_balance.checked_sub(&ledger.total) { + let extra = extra.min(max_additional); + ledger.total += extra; + ledger.active += extra; + Self::update_ledger(&controller, &ledger); + } } - /// Will panic if called when source isn't currently nominating target. - /// Updates Nominating, NominatorsFor and NominationBalance. - fn unnominate(origin, #[compact] target_index: u32) { - let source = ensure_signed(origin)?; - let target_index = target_index as usize; + /// Schedule a portion of the stash to be unlocked ready for transfer out after the bond + /// period ends. If this leaves an amount actively bonded less than + /// T::Currency::existential_deposit(), then it is increased to the full amount. + /// + /// Once the unlock period is done, you can call `withdraw_unbonded` to actually move + /// the funds out of management ready for transfer. + /// + /// The dispatch origin for this call must be _Signed_ by the controller, not the stash. + /// + /// See also [`Call::withdraw_unbonded`]. + fn unbond(origin, #[compact] value: BalanceOf) { + let controller = ensure_signed(origin)?; + let mut ledger = Self::ledger(&controller).ok_or("not a controller")?; + + let mut value = value.min(ledger.active); + + if !value.is_zero() { + ledger.active -= value; - let target = >::get(&source).ok_or("Account must be nominating")?; + // Avoid there being a dust balance left in the staking system. + if ledger.active < T::Currency::minimum_balance() { + value += ledger.active; + ledger.active = Zero::zero(); + } - let mut t = Self::nominators_for(&target); - if t.get(target_index) != Some(&source) { - return Err("Invalid target index") + let era = Self::current_era() + Self::bonding_duration(); + ledger.unlocking.push(UnlockChunk { value, era }); + Self::update_ledger(&controller, &ledger); } + } + + /// Remove any unlocked chunks from the `unlocking` queue from our management. + /// + /// This essentially frees up that balance to be used by the stash account to do + /// whatever it wants. + /// + /// The dispatch origin for this call must be _Signed_ by the controller, not the stash. + /// + /// See also [`Call::unbond`]. + fn withdraw_unbonded(origin) { + 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); + } - // Ok - all valid. + /// Declare the desire to validate for the origin controller. + /// + /// Effects will be felt at the beginning of the next era. + /// + /// The dispatch origin for this call must be _Signed_ by the controller, not the stash. + fn validate(origin, prefs: ValidatorPrefs>) { + let controller = ensure_signed(origin)?; + let ledger = Self::ledger(&controller).ok_or("not a controller")?; + let stash = &ledger.stash; + ensure!(prefs.unstake_threshold <= MAX_UNSTAKE_THRESHOLD, "unstake threshold too large"); + >::remove(stash); + >::insert(stash, prefs); + } - // update nominators_for - t.swap_remove(target_index); - >::insert(&target, t); + /// Declare the desire to nominate `targets` for the origin controller. + /// + /// Effects will be felt at the beginning of the next era. + /// + /// The dispatch origin for this call must be _Signed_ by the controller, not the stash. + fn nominate(origin, targets: Vec<::Source>) { + let controller = ensure_signed(origin)?; + let ledger = Self::ledger(&controller).ok_or("not a controller")?; + let stash = &ledger.stash; + ensure!(!targets.is_empty(), "targets cannot be empty"); + let targets = targets.into_iter() + .take(MAX_NOMINATIONS) + .map(T::Lookup::lookup) + .collect::, &'static str>>()?; + + >::remove(stash); + >::insert(stash, targets); + } - // update nominating - >::remove(&source); + /// Declare no desire to either validate or nominate. + /// + /// Effects will be felt at the beginning of the next era. + /// + /// The dispatch origin for this call must be _Signed_ by the controller, not the stash. + fn chill(origin) { + let controller = ensure_signed(origin)?; + let ledger = Self::ledger(&controller).ok_or("not a controller")?; + let stash = &ledger.stash; + >::remove(stash); + >::remove(stash); + } - // update bondage - >::insert( - source, - >::block_number() + Self::bonding_duration() - ); + /// (Re-)set the payment target for a controller. + /// + /// Effects will be felt at the beginning of the next era. + /// + /// The dispatch origin for this call must be _Signed_ by the controller, not the stash. + fn set_payee(origin, payee: RewardDestination) { + let controller = ensure_signed(origin)?; + let ledger = Self::ledger(&controller).ok_or("not a controller")?; + let stash = &ledger.stash; + >::insert(stash, payee); } - /// Set the given account's preference for slashing behaviour should they be a validator. + /// (Re-)set the payment target for a controller. + /// + /// Effects will be felt at the beginning of the next era. /// - /// An error (no-op) if `Self::intentions()[intentions_index] != origin`. - fn register_preferences( - origin, - #[compact] intentions_index: u32, - prefs: ValidatorPrefs> - ) { - let who = ensure_signed(origin)?; - - if Self::intentions().get(intentions_index as usize) != Some(&who) { - return Err("Invalid index") + /// The dispatch origin for this call must be _Signed_ by the stash, not the controller. + fn set_controller(origin, controller: ::Source) { + let stash = ensure_signed(origin)?; + let old_controller = Self::bonded(&stash).ok_or("not a stash")?; + let controller = T::Lookup::lookup(controller)?; + if >::exists(&controller) { + return Err("controller already paired") + } + if controller != old_controller { + >::insert(&stash, &controller); + if let Some(l) = >::take(&old_controller) { >::insert(&controller, l) }; } - - >::insert(who, prefs); } /// Set the number of sessions in an era. @@ -204,12 +716,11 @@ decl_module! { /// Set the validators who cannot be slashed (if any). fn set_invulnerables(validators: Vec) { - >::put(validators); + >::put(validators); } } } -/// An event in this module. decl_event!( pub enum Event where Balance = BalanceOf, ::AccountId { /// All validators have been rewarded by the given balance. @@ -222,69 +733,6 @@ decl_event!( } ); -pub type PairOf = (T, T); - -decl_storage! { - trait Store for Module as Staking { - - /// The ideal number of staking participants. - pub ValidatorCount get(validator_count) config(): u32; - /// Minimum number of staking participants before emergency conditions are imposed. - pub MinimumValidatorCount get(minimum_validator_count) config(): u32 = DEFAULT_MINIMUM_VALIDATOR_COUNT; - /// The length of a staking era in sessions. - pub SessionsPerEra get(sessions_per_era) config(): T::BlockNumber = T::BlockNumber::sa(1000); - /// Maximum reward, per validator, that is provided per acceptable session. - pub SessionReward get(session_reward) config(): Perbill = Perbill::from_billionths(60); - /// Slash, per validator that is taken for the first time they are found to be offline. - pub OfflineSlash get(offline_slash) config(): Perbill = Perbill::from_millionths(1000); // Perbill::from_fraction() is only for std, so use from_millionths(). - /// Number of instances of offline reports before slashing begins for validators. - pub OfflineSlashGrace get(offline_slash_grace) config(): u32; - /// The length of the bonding duration in blocks. - pub BondingDuration get(bonding_duration) config(): T::BlockNumber = T::BlockNumber::sa(1000); - - /// Any validators that may never be slashed or forcible kicked. It's a Vec since they're easy to initialise - /// and the performance hit is minimal (we expect no more than four invulnerables) and restricted to testnets. - pub Invulerables get(invulnerables) config(): Vec; - - /// The current era index. - pub CurrentEra get(current_era) config(): T::BlockNumber; - /// Preferences that a validator has. - pub ValidatorPreferences get(validator_preferences): map T::AccountId => ValidatorPrefs>; - /// All the accounts with a desire to stake. - pub Intentions get(intentions) config(): Vec; - /// All nominator -> nominee relationships. - pub Nominating get(nominating): map T::AccountId => Option; - /// Nominators for a particular account. - pub NominatorsFor get(nominators_for): map T::AccountId => Vec; - /// Nominators for a particular account that is in action right now. - pub CurrentNominatorsFor get(current_nominators_for): map T::AccountId => Vec; - - /// Maximum reward, per validator, that is provided per acceptable session. - pub CurrentSessionReward get(current_session_reward) config(): BalanceOf; - /// Slash, per validator that is taken for the first time they are found to be offline. - pub CurrentOfflineSlash get(current_offline_slash) config(): BalanceOf; - - /// The next value of sessions per era. - pub NextSessionsPerEra get(next_sessions_per_era): Option; - /// The session index at which the era length last changed. - pub LastEraLengthChange get(last_era_length_change): T::BlockNumber; - - /// The highest and lowest staked validator slashable balances. - pub StakeRange get(stake_range): PairOf>; - - /// The block at which the `who`'s funds become entirely liquid. - pub Bondage get(bondage): map T::AccountId => T::BlockNumber; - /// The number of times a given validator has been reported offline. This gets decremented by one each era that passes. - pub SlashCount get(slash_count): map T::AccountId => u32; - - /// We are forcing a new era. - pub ForcingNewEra get(forcing_new_era): Option<()>; - - /// Most recent `RECENT_OFFLINE_COUNT` instances. (who it was, when it was reported, how many instances they were offline for). - pub RecentlyOffline get(recently_offline): Vec<(T::AccountId, T::BlockNumber, u32)>; - } -} - impl Module { // Just force_new_era without origin check. fn apply_force_new_era(apply_rewards: bool) -> Result { @@ -299,92 +747,90 @@ impl Module { Self::sessions_per_era() * >::length() } - /// Balance of a (potential) validator that includes all nominators. - pub fn nomination_balance(who: &T::AccountId) -> BalanceOf { - Self::nominators_for(who).iter() - .map(T::Currency::total_balance) - .fold(Zero::zero(), |acc, x| acc + x) - } - - /// The total balance that can be slashed from an account. + /// The total balance that can be slashed from a validator controller account as of + /// right now. pub fn slashable_balance(who: &T::AccountId) -> BalanceOf { - Self::nominators_for(who).iter() - .map(T::Currency::total_balance) - .fold(T::Currency::total_balance(who), |acc, x| acc + x) + Self::stakers(who).total } - /// The block at which the `who`'s funds become entirely liquid. - pub fn unlock_block(who: &T::AccountId) -> LockStatus { - match Self::bondage(who) { - i if i == T::BlockNumber::max_value() => LockStatus::Bonded, - i if i <= >::block_number() => LockStatus::Liquid, - i => LockStatus::LockedUntil(i), - } - } + // MUTABLES (DANGEROUS) - /// Get the current validators. - pub fn validators() -> Vec { - session::Module::::validators() + /// Update the ledger for a controller. This will also update the stash lock. + fn update_ledger(controller: &T::AccountId, ledger: &StakingLedger, T::BlockNumber>) { + T::Currency::set_lock(STAKING_ID, &ledger.stash, ledger.total, T::BlockNumber::max_value(), WithdrawReasons::all()); + >::insert(controller, ledger); } - // PUBLIC MUTABLES (DANGEROUS) - /// Slash a given validator by a specific amount. Removes the slash from their balance by preference, /// and reduces the nominators' balance if needed. - fn slash_validator(v: &T::AccountId, slash: BalanceOf) { - // skip the slash in degenerate case of having only 4 staking participants despite having a larger - // desired number of validators (validator_count). - if Self::intentions().len() <= Self::minimum_validator_count() as usize { - return - } - - if let Some(rem) = T::Currency::slash(v, slash) { - let noms = Self::current_nominators_for(v); - let total = noms.iter().map(T::Currency::total_balance).fold(BalanceOf::::zero(), |acc, x| acc + x); + fn slash_validator(stash: &T::AccountId, slash: BalanceOf) { + // The exposure (backing stake) information of the validator to be slashed. + let exposure = Self::stakers(stash); + // The amount we are actually going to slash (can't be bigger than their total exposure) + let slash = slash.min(exposure.total); + // The amount we'll slash from the validator's stash directly. + let own_slash = exposure.own.min(slash); + let (mut imbalance, missing) = T::Currency::slash(stash, own_slash); + let own_slash = own_slash - missing; + // The amount remaining that we can't slash from the validator, that must be taken from the nominators. + let rest_slash = slash - own_slash; + if !rest_slash.is_zero() { + // The total to be slashed from the nominators. + let total = exposure.total - exposure.own; if !total.is_zero() { - let safe_mul_rational = |b| b * rem / total;// FIXME #1572 avoid overflow - for n in noms.iter() { - let _ = T::Currency::slash(n, safe_mul_rational(T::Currency::total_balance(n))); // best effort - not much that can be done on fail. + let safe_mul_rational = |b| b * rest_slash / total;// FIXME #1572 avoid overflow + for i in exposure.others.iter() { + // best effort - not much that can be done on fail. + imbalance.subsume(T::Currency::slash(&i.who, safe_mul_rational(i.value)).0) } } } + T::Slash::on_unbalanced(imbalance); + } + + /// Actually make a payment to a staker. This uses the currency's reward function + /// to pay the right payee for the given staker account. + fn make_payout(stash: &T::AccountId, amount: BalanceOf) -> Option> { + let dest = Self::payee(stash); + match dest { + RewardDestination::Controller => Self::bonded(stash) + .and_then(|controller| + T::Currency::deposit_into_existing(&controller, amount).ok() + ), + RewardDestination::Stash => + T::Currency::deposit_into_existing(stash, amount).ok(), + RewardDestination::Staked => Self::bonded(stash) + .and_then(|c| Self::ledger(&c).map(|l| (c, l))) + .and_then(|(controller, mut l)| { + l.active += amount; + l.total += amount; + let r = T::Currency::deposit_into_existing(stash, amount).ok(); + Self::update_ledger(&controller, &l); + r + }), + } } /// Reward a given validator by a specific amount. Add the reward to their, and their nominators' - /// balance, pro-rata. - fn reward_validator(who: &T::AccountId, reward: BalanceOf) { - let off_the_table = reward.min(Self::validator_preferences(who).validator_payment); + /// balance, pro-rata based on their exposure, after having removed the validator's pre-payout cut. + fn reward_validator(stash: &T::AccountId, reward: BalanceOf) { + let off_the_table = reward.min(Self::validators(stash).validator_payment); let reward = reward - off_the_table; + let mut imbalance = >::zero(); let validator_cut = if reward.is_zero() { Zero::zero() } else { - let noms = Self::current_nominators_for(who); - let total = noms.iter() - .map(T::Currency::total_balance) - .fold(T::Currency::total_balance(who), |acc, x| acc + x) - .max(One::one()); + let exposure = Self::stakers(stash); + let total = exposure.total.max(One::one()); let safe_mul_rational = |b| b * reward / total;// FIXME #1572: avoid overflow - for n in noms.iter() { - let _ = T::Currency::reward(n, safe_mul_rational(T::Currency::total_balance(n))); + for i in &exposure.others { + let nom_payout = safe_mul_rational(i.value); + imbalance.maybe_subsume(Self::make_payout(&i.who, nom_payout)); } - safe_mul_rational(T::Currency::total_balance(who)) + safe_mul_rational(exposure.own) }; - let _ = T::Currency::reward(who, validator_cut + off_the_table); - } - - /// Actually carry out the unstake operation. - /// Assumes `intentions()[intentions_index] == who`. - fn apply_unstake(who: &T::AccountId, intentions_index: usize) -> Result { - let mut intentions = Self::intentions(); - if intentions.get(intentions_index) != Some(who) { - return Err("Invalid index"); - } - intentions.swap_remove(intentions_index); - >::put(intentions); - >::remove(who); - >::remove(who); - >::insert(who, >::block_number() + Self::bonding_duration()); - Ok(()) + imbalance.maybe_subsume(Self::make_payout(stash, validator_cut + off_the_table)); + T::Reward::on_unbalanced(imbalance); } /// Get the reward for the session, assuming it ends with this block. @@ -394,23 +840,16 @@ impl Module { return Self::current_session_reward(); } let per65536: u64 = (T::Moment::sa(65536u64) * ideal_elapsed.clone() / actual_elapsed.max(ideal_elapsed)).as_(); - Self::current_session_reward() * BalanceOf::::sa(per65536) / BalanceOf::::sa(65536u64) + Self::current_session_reward() * >::sa(per65536) / >::sa(65536u64) } /// Session has just changed. We need to determine whether we pay a reward, slash and/or /// move to a new era. fn new_session(actual_elapsed: T::Moment, should_reward: bool) { if should_reward { - // apply good session reward + // accumulate good session reward let reward = Self::this_session_reward(actual_elapsed); - let validators = >::validators(); - for v in validators.iter() { - Self::reward_validator(v, reward); - } - Self::deposit_event(RawEvent::Reward(reward)); - let total_minted = reward * as As>::sa(validators.len()); - let total_rewarded_stake = Self::stake_range().1 * as As>::sa(validators.len()); - T::OnRewardMinted::on_dilution(total_minted, total_rewarded_stake); + >::mutate(|r| *r += reward); } let session_index = >::current_index(); @@ -426,6 +865,19 @@ 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() { + // Payout + let reward = >::take(); + if !reward.is_zero() { + let validators = Self::current_elected(); + for v in validators.iter() { + Self::reward_validator(v, reward); + } + Self::deposit_event(RawEvent::Reward(reward)); + let total_minted = reward * as As>::sa(validators.len()); + let total_rewarded_stake = Self::slot_stake() * as As>::sa(validators.len()); + T::OnRewardMinted::on_dilution(total_minted, total_rewarded_stake); + } + // Increment current era. >::put(&(>::get() + One::one())); @@ -437,133 +889,134 @@ impl Module { } } - // evaluate desired staking amounts and nominations and optimise to find the best - // combination of validators, then use session::internal::set_validators(). - // for now, this just orders would-be stakers by their balances and chooses the top-most - // >::get() of them. - // FIXME #1571 this is not sound. this should be moved to an off-chain solution mechanism. - let mut intentions = Self::intentions() - .into_iter() - .map(|v| (Self::slashable_balance(&v), v)) - .collect::>(); - - // Avoid reevaluate validator set if it would leave us with fewer than the minimum - // needed validators - if intentions.len() < Self::minimum_validator_count() as usize { - return - } + // Reassign all Stakers. + let slot_stake = Self::select_validators(); - intentions.sort_unstable_by(|&(ref b1, _), &(ref b2, _)| b2.cmp(&b1)); + // Update the balances for rewarding according to the stakes. + >::put(Self::session_reward() * slot_stake); + } - let desired_validator_count = >::get() as usize; - let stake_range = if !intentions.is_empty() { - let n = cmp::min(desired_validator_count, intentions.len()); - (intentions[0].0, intentions[n - 1].0) - } else { - (Zero::zero(), Zero::zero()) - }; - >::put(&stake_range); - - let vals = &intentions.into_iter() - .map(|(_, v)| v) - .take(desired_validator_count) - .collect::>(); - for v in >::validators().iter() { - >::remove(v); - let slash_count = >::take(v); - if slash_count > 1 { - >::insert(v, slash_count - 1); + fn slashable_balance_of(stash: &T::AccountId) -> BalanceOf { + Self::bonded(stash).and_then(Self::ledger).map(|l| l.total).unwrap_or_default() + } + + /// Select a new validator set from the assembled stakers and their role preferences. + /// + /// Returns the new SlotStake value. + fn select_validators() -> BalanceOf { + let rounds = || >::get() as usize; + let validators = || >::enumerate(); + let nominators = || >::enumerate(); + let min_validator_count = Self::minimum_validator_count() as usize; + let maybe_elected_candidates = elect::( + rounds, + validators, + nominators, + Self::slashable_balance_of, + min_validator_count, + ElectionConfig::> { + equalise: false, + tolerance: >::sa(10 as u64), + iterations: 10, + } + ); + + if let Some(elected_candidates) = maybe_elected_candidates { + // Clear Stakers and reduce their slash_count. + for v in Self::current_elected().iter() { + >::remove(v); + let slash_count = >::take(v); + if slash_count > 1 { + >::insert(v, slash_count - 1); + } } - } - for v in vals.iter() { - >::insert(v, Self::nominators_for(v)); - } - >::set_validators(vals); - // Update the balances for slashing/rewarding according to the stakes. - >::put(Self::offline_slash() * stake_range.1); - >::put(Self::session_reward() * stake_range.1); + // Populate Stakers and figure out the minimum stake behind a slot. + let mut slot_stake = elected_candidates[0].exposure.total; + for c in &elected_candidates { + if c.exposure.total < slot_stake { + slot_stake = c.exposure.total; + } + >::insert(c.who.clone(), c.exposure.clone()); + } + >::put(&slot_stake); + + // Set the new validator set. + let elected_stashes = elected_candidates.into_iter().map(|i| i.who).collect::>(); + >::put(&elected_stashes); + >::set_validators( + &elected_stashes.into_iter().map(|s| Self::bonded(s).unwrap_or_default()).collect::>() + ); + + slot_stake + } else { + // There were not enough candidates for even our minimal level of functionality. + // This is bad. + // We should probably disable all functionality except for block production + // and let the chain keep producing blocks until we can decide on a sufficiently + // substantial set. + Self::slot_stake() + } } /// Call when a validator is determined to be offline. `count` is the /// number of offences the validator has committed. - pub fn on_offline_validator(v: T::AccountId, count: usize) { - use primitives::traits::{CheckedAdd, CheckedShl}; - - // Early exit if validator is invulnerable. - if Self::invulnerables().contains(&v) { - return - } + /// + /// NOTE: This is called with the controller (not the stash) account id. + pub fn on_offline_validator(controller: T::AccountId, count: usize) { + use primitives::traits::CheckedShl; - let slash_count = Self::slash_count(&v); - let new_slash_count = slash_count + count as u32; - >::insert(&v, new_slash_count); - let grace = Self::offline_slash_grace(); - - if RECENT_OFFLINE_COUNT > 0 { - let item = (v.clone(), >::block_number(), count as u32); - >::mutate(|v| if v.len() >= RECENT_OFFLINE_COUNT { - let index = v.iter() - .enumerate() - .min_by_key(|(_, (_, block, _))| block) - .expect("v is non-empty; qed") - .0; - v[index] = item; - } else { - v.push(item); - }); - } + if let Some(l) = Self::ledger(&controller) { + let stash = l.stash; - let event = if new_slash_count > grace { - let slash = { - let base_slash = Self::current_offline_slash(); - let instances = slash_count - grace; - - let mut total_slash = BalanceOf::::default(); - for i in instances..(instances + count as u32) { - if let Some(total) = base_slash.checked_shl(i) - .and_then(|slash| total_slash.checked_add(&slash)) { - total_slash = total; - } else { - // reset slash count only up to the current - // instance. the total slash overflows the unit for - // balance in the system therefore we can slash all - // the slashable balance for the account - >::insert(v.clone(), slash_count + i); - total_slash = Self::slashable_balance(&v); - break; - } - } + // Early exit if validator is invulnerable. + if Self::invulnerables().contains(&stash) { + return + } - total_slash - }; + let slash_count = Self::slash_count(&stash); + let new_slash_count = slash_count + count as u32; + >::insert(&stash, new_slash_count); + let grace = Self::offline_slash_grace(); + + if RECENT_OFFLINE_COUNT > 0 { + let item = (stash.clone(), >::block_number(), count as u32); + >::mutate(|v| if v.len() >= RECENT_OFFLINE_COUNT { + let index = v.iter() + .enumerate() + .min_by_key(|(_, (_, block, _))| block) + .expect("v is non-empty; qed") + .0; + v[index] = item; + } else { + v.push(item); + }); + } - let _ = Self::slash_validator(&v, slash); + let prefs = Self::validators(&stash); + let unstake_threshold = prefs.unstake_threshold.min(MAX_UNSTAKE_THRESHOLD); + let max_slashes = grace + unstake_threshold; + + let event = if new_slash_count > max_slashes { + let slash_exposure = Self::stakers(&stash).total; + let offline_slash_base = Self::offline_slash() * slash_exposure; + // They're bailing. + let slash = offline_slash_base + // Multiply slash_mantissa by 2^(unstake_threshold with upper bound) + .checked_shl(unstake_threshold) + .map(|x| x.min(slash_exposure)) + .unwrap_or(slash_exposure); + let _ = Self::slash_validator(&stash, slash); + >::remove(&stash); + let _ = Self::apply_force_new_era(false); - let next_slash = match slash.checked_shl(1) { - Some(slash) => slash, - None => Self::slashable_balance(&v), + RawEvent::OfflineSlash(stash.clone(), slash) + } else { + RawEvent::OfflineWarning(stash.clone(), slash_count) }; - let instances = new_slash_count - grace; - if instances > Self::validator_preferences(&v).unstake_threshold - || Self::slashable_balance(&v) < next_slash - || next_slash <= slash - { - if let Some(pos) = Self::intentions().into_iter().position(|x| &x == &v) { - Self::apply_unstake(&v, pos) - .expect("pos derived correctly from Self::intentions(); \ - apply_unstake can only fail if pos wrong; \ - Self::intentions() doesn't change; qed"); - } - let _ = Self::apply_force_new_era(false); - } - RawEvent::OfflineSlash(v.clone(), slash) - } else { - RawEvent::OfflineWarning(v.clone(), slash_count) - }; - - Self::deposit_event(event); + Self::deposit_event(event); + } } } @@ -573,19 +1026,15 @@ impl OnSessionChange for Module { } } -impl EnsureAccountLiquid for Module { - fn ensure_account_liquid(who: &T::AccountId) -> Result { - if Self::bondage(who) <= >::block_number() { - Ok(()) - } else { - Err("cannot transfer illiquid funds") - } - } -} - impl OnFreeBalanceZero for Module { - fn on_free_balance_zero(who: &T::AccountId) { - >::remove(who); + fn on_free_balance_zero(stash: &T::AccountId) { + if let Some(controller) = >::take(stash) { + >::remove(&controller); + } + >::remove(stash); + >::remove(stash); + >::remove(stash); + >::remove(stash); } } diff --git a/srml/staking/src/mock.rs b/srml/staking/src/mock.rs index a76c0fed85aad29cee8cc6939e8d534ed8d71d9a..5871306f4977bca944140f76fb0bb8b36ffb360d 100644 --- a/srml/staking/src/mock.rs +++ b/srml/staking/src/mock.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -23,7 +23,10 @@ use primitives::testing::{Digest, DigestItem, Header, UintAuthorityId, ConvertUi use substrate_primitives::{H256, Blake2Hasher}; use runtime_io; use srml_support::impl_outer_origin; -use crate::{GenesisConfig, Module, Trait}; +use crate::{GenesisConfig, Module, Trait, StakerStatus}; + +// The AccountId alias in this test module. +pub type AccountIdType = u64; impl_outer_origin!{ pub enum Origin for Test {} @@ -44,8 +47,8 @@ impl system::Trait for Test { type Hash = H256; type Hashing = ::primitives::traits::BlakeTwo256; type Digest = Digest; - type AccountId = u64; - type Lookup = IdentityLookup; + type AccountId = AccountIdType; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; @@ -54,8 +57,10 @@ impl balances::Trait for Test { type Balance = u64; type OnFreeBalanceZero = Staking; type OnNewAccount = (); - type EnsureAccountLiquid = Staking; type Event = (); + type TransactionPayment = (); + type TransferPayment = (); + type DustRemoval = (); } impl session::Trait for Test { type ConvertAccountIdToSessionKey = ConvertUintAuthorityId; @@ -70,63 +75,153 @@ impl Trait for Test { type Currency = balances::Module; type OnRewardMinted = (); type Event = (); + type Slash = (); + type Reward = (); } -pub fn new_test_ext( - ext_deposit: u64, +pub struct ExtBuilder { + existential_deposit: u64, session_length: u64, sessions_per_era: u64, current_era: u64, - monied: bool, - reward: u64 -) -> runtime_io::TestExternalities { - let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; - let balance_factor = if ext_deposit > 0 { - 256 - } else { - 1 - }; - t.extend(consensus::GenesisConfig::{ - code: vec![], - authorities: vec![], - }.build_storage().unwrap().0); - t.extend(session::GenesisConfig::{ - session_length, - validators: vec![10, 20], - }.build_storage().unwrap().0); - t.extend(balances::GenesisConfig::{ - balances: if monied { - if reward > 0 { - vec![(1, 10 * balance_factor), (2, 20 * balance_factor), (3, 30 * balance_factor), (4, 40 * balance_factor), (10, balance_factor), (20, balance_factor)] - } else { - vec![(1, 10 * balance_factor), (2, 20 * balance_factor), (3, 30 * balance_factor), (4, 40 * balance_factor)] - } + reward: u64, + validator_pool: bool, + nominate: bool, + validator_count: u32, + minimum_validator_count: u32, + fare: bool, +} + +impl Default for ExtBuilder { + fn default() -> Self { + Self { + existential_deposit: 0, + session_length: 1, + sessions_per_era: 1, + current_era: 0, + reward: 10, + validator_pool: false, + nominate: true, + validator_count: 2, + minimum_validator_count: 0, + fare: true + } + } +} + +impl ExtBuilder { + pub fn existential_deposit(mut self, existential_deposit: u64) -> Self { + self.existential_deposit = existential_deposit; + self + } + pub fn session_length(mut self, session_length: u64) -> Self { + self.session_length = session_length; + self + } + pub fn sessions_per_era(mut self, sessions_per_era: u64) -> Self { + self.sessions_per_era = sessions_per_era; + self + } + pub fn _current_era(mut self, current_era: u64) -> Self { + self.current_era = current_era; + self + } + pub fn validator_pool(mut self, validator_pool: bool) -> Self { + self.validator_pool = validator_pool; + self + } + pub fn nominate(mut self, nominate: bool) -> Self { + // NOTE: this only sets a dummy nominator for tests that want 10 and 20 (default validators) to be chosen by default. + self.nominate = nominate; + self + } + pub fn validator_count(mut self, count: u32) -> Self { + self.validator_count = count; + self + } + pub fn minimum_validator_count(mut self, count: u32) -> Self { + self.minimum_validator_count = count; + self + } + pub fn fare(mut self, is_fare: bool) -> Self { + self.fare = is_fare; + self + } + pub fn build(self) -> runtime_io::TestExternalities { + let (mut t, mut c) = system::GenesisConfig::::default().build_storage().unwrap(); + let balance_factor = if self.existential_deposit > 0 { + 256 } else { - vec![(10, balance_factor), (20, balance_factor)] - }, - existential_deposit: ext_deposit, - transfer_fee: 0, - creation_fee: 0, - vesting: vec![], - }.build_storage().unwrap().0); - t.extend(GenesisConfig::{ - sessions_per_era, - current_era, - intentions: vec![10, 20], - validator_count: 2, - minimum_validator_count: 0, - bonding_duration: sessions_per_era * session_length * 3, - session_reward: Perbill::from_millionths((1000000 * reward / balance_factor) as u32), - offline_slash: if monied { Perbill::from_percent(40) } else { Perbill::zero() }, - current_session_reward: reward, - current_offline_slash: 20, - offline_slash_grace: 0, - invulnerables: vec![], - }.build_storage().unwrap().0); - t.extend(timestamp::GenesisConfig::{ - period: 5, - }.build_storage().unwrap().0); - runtime_io::TestExternalities::new(t) + 1 + }; + let _ = consensus::GenesisConfig::{ + code: vec![], + authorities: vec![], + }.assimilate_storage(&mut t, &mut c); + let _ = session::GenesisConfig::{ + session_length: self.session_length, + // NOTE: if config.nominate == false then 100 is also selected in the initial round. + validators: if self.validator_pool { vec![10, 20, 30, 40] } else { vec![10, 20] }, + keys: vec![], + }.assimilate_storage(&mut t, &mut c); + let _ = balances::GenesisConfig::{ + balances: vec![ + (1, 10 * balance_factor), + (2, 20 * balance_factor), + (3, 300 * balance_factor), + (4, 400 * balance_factor), + (10, balance_factor), + (11, balance_factor * 1000), + (20, balance_factor), + (21, balance_factor * 2000), + (30, balance_factor), + (31, balance_factor * 2000), + (40, balance_factor), + (41, balance_factor * 2000), + (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 _ = GenesisConfig::{ + sessions_per_era: self.sessions_per_era, + current_era: self.current_era, + stakers: if self.validator_pool { + vec![ + (11, 10, balance_factor * 1000, StakerStatus::::Validator), + (21, 20, balance_factor * if self.fare { 1000 } else { 2000 }, StakerStatus::::Validator), + (31, 30, balance_factor * 1000, if self.validator_pool { StakerStatus::::Validator } else { StakerStatus::::Idle }), + (41, 40, balance_factor * 1000, if self.validator_pool { StakerStatus::::Validator } else { StakerStatus::::Idle }), + // nominator + (101, 100, balance_factor * 500, if self.nominate { StakerStatus::::Nominator(vec![11, 21]) } else { StakerStatus::::Nominator(vec![]) }) + ] + } else { + vec![ + (11, 10, balance_factor * 1000, StakerStatus::::Validator), + (21, 20, balance_factor * if self.fare { 1000 } else { 2000 }, StakerStatus::::Validator), + // nominator + (101, 100, balance_factor * 500, if self.nominate { StakerStatus::::Nominator(vec![11, 21]) } else { StakerStatus::::Nominator(vec![]) }) + ] + }, + validator_count: self.validator_count, + minimum_validator_count: self.minimum_validator_count, + bonding_duration: self.sessions_per_era * self.session_length * 3, + session_reward: Perbill::from_millionths((1000000 * self.reward / balance_factor) as u32), + offline_slash: Perbill::from_percent(5), + current_session_reward: self.reward, + offline_slash_grace: 0, + invulnerables: vec![], + }.assimilate_storage(&mut t, &mut c); + let _ = timestamp::GenesisConfig::{ + minimum_period: 5, + }.assimilate_storage(&mut t, &mut c); + t.into() + } } pub type System = system::Module; diff --git a/srml/staking/src/phragmen.rs b/srml/staking/src/phragmen.rs new file mode 100644 index 0000000000000000000000000000000000000000..9c388e5184af98aa9df65b8f2300229a80d2e4f6 --- /dev/null +++ b/srml/staking/src/phragmen.rs @@ -0,0 +1,364 @@ +// 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 . + +//! Rust implementation of the Phragmén election algorithm. + +use rstd::prelude::*; +use primitives::Perquintill; +use primitives::traits::{Zero, As, Bounded, CheckedMul, Saturating}; +use parity_codec::{HasCompact, Encode, Decode}; +use crate::{Exposure, BalanceOf, Trait, ValidatorPrefs, IndividualExposure}; + + +/// Configure the behavior of the Phragmen election. +/// Might be deprecated. +pub struct ElectionConfig { + /// Perform equalise?. + pub equalise: bool, + /// Number of equalise iterations. + pub iterations: usize, + /// Tolerance of max change per equalise iteration. + pub tolerance: Balance, +} + +/// Wrapper around validation candidates some metadata. +#[derive(Clone, Encode, Decode, Default)] +#[cfg_attr(feature = "std", derive(Debug))] +pub struct Candidate { + /// The validator's account + pub who: AccountId, + /// Exposure struct, holding info about the value that the validator has in stake. + pub exposure: Exposure, + /// Intermediary value used to sort candidates. + pub score: Perquintill, + /// Accumulator of the stake of this candidate based on received votes. + approval_stake: Balance, + /// Flag for being elected. + elected: bool, + /// This is most often equal to `Exposure.total` but not always. Needed for [`equalise`] + backing_stake: Balance +} + +/// Wrapper around the nomination info of a single nominator for a group of validators. +#[derive(Clone, Encode, Decode, Default)] +#[cfg_attr(feature = "std", derive(Debug))] +pub struct Nominator { + /// The nominator's account. + who: AccountId, + /// List of validators proposed by this nominator. + edges: Vec>, + /// the stake amount proposed by the nominator as a part of the vote. + budget: Balance, + /// Incremented each time a nominee that this nominator voted for has been elected. + load: Perquintill, +} + +/// Wrapper around a nominator vote and the load of that vote. +#[derive(Clone, Encode, Decode, Default)] +#[cfg_attr(feature = "std", derive(Debug))] +pub struct Edge { + /// Account being voted for + who: AccountId, + /// Load of this vote. + load: Perquintill, + /// Final backing stake of this vote. + backing_stake: Balance, + /// Index of the candidate stored in the 'candidates' vector + candidate_index: usize, + /// Index of the candidate stored in the 'elected_candidates' vector. Used only with equalise. + elected_idx: usize, + /// Indicates if this edge is a vote for an elected candidate. Used only with equalise. + elected: bool, +} + +/// Perform election based on Phragmén algorithm. +/// +/// Reference implementation: https://github.com/w3f/consensus +/// +/// Returns an Option of elected candidates, if election is performed. +/// Returns None if not enough candidates exist. +pub fn elect( + get_rounds: FR, + get_validators: FV, + get_nominators: FN, + stash_of: FS, + minimum_validator_count: usize, + config: ElectionConfig>, +) -> Option>>> where + FR: Fn() -> usize, + FV: Fn() -> Box>) + >>, + FN: Fn() -> Box) + >>, + for <'r> FS: Fn(&'r T::AccountId) -> BalanceOf, +{ + let rounds = get_rounds(); + let mut elected_candidates; + + // 1- Pre-process candidates and place them in a container + let mut candidates = get_validators().map(|(who, _)| { + let stash_balance = stash_of(&who); + Candidate { + who, + exposure: Exposure { total: stash_balance, own: stash_balance, others: vec![] }, + ..Default::default() + } + }).collect::>>>(); + + // 1.1- Add phantom votes. + let mut nominators: Vec>> = Vec::with_capacity(candidates.len()); + candidates.iter_mut().enumerate().for_each(|(idx, c)| { + c.approval_stake += c.exposure.total; + nominators.push(Nominator { + who: c.who.clone(), + edges: vec![ Edge { who: c.who.clone(), candidate_index: idx, ..Default::default() }], + budget: c.exposure.total, + load: Perquintill::zero(), + }) + }); + + // 2- Collect the nominators with the associated votes. + // Also collect approval stake along the way. + nominators.extend(get_nominators().map(|(who, nominees)| { + let nominator_stake = stash_of(&who); + let mut edges: Vec>> = Vec::with_capacity(nominees.len()); + for n in &nominees { + if let Some(idx) = candidates.iter_mut().position(|i| i.who == *n) { + candidates[idx].approval_stake = candidates[idx].approval_stake.saturating_add(nominator_stake); + edges.push(Edge { who: n.clone(), candidate_index: idx, ..Default::default() }); + } + } + + Nominator { + who, + edges: edges, + budget: nominator_stake, + load: Perquintill::zero(), + } + })); + + + // 3- optimization: + // Candidates who have 0 stake => have no votes or all null-votes. Kick them out not. + let mut candidates = candidates.into_iter().filter(|c| c.approval_stake > BalanceOf::::zero()) + .collect::>>>(); + + // 4- If we have more candidates then needed, run Phragmén. + if candidates.len() >= rounds { + elected_candidates = Vec::with_capacity(rounds); + // Main election loop + for _round in 0..rounds { + // Loop 1: initialize score + for c in &mut candidates { + if !c.elected { + c.score = Perquintill::from_xth(c.approval_stake.as_()); + } + } + // Loop 2: increment score. + for n in &nominators { + for e in &n.edges { + let c = &mut candidates[e.candidate_index]; + if !c.elected { + // Note: This seems to never overflow, ok to be safe though + let temp = n.budget.as_().saturating_mul(*n.load) / c.approval_stake.as_(); + // Note: This seems to never overflow, ok to be safe though + c.score = Perquintill::from_quintillionths((*c.score).saturating_add(temp)); + } + } + } + + // Find the best + let winner = candidates + .iter_mut() + .filter(|c| !c.elected) + .min_by_key(|c| *c.score) + .expect("candidates length is checked to be >0; qed"); + + // loop 3: update nominator and edge load + winner.elected = true; + for n in &mut nominators { + for e in &mut n.edges { + if e.who == winner.who { + e.load = Perquintill::from_quintillionths(*winner.score - *n.load); + n.load = winner.score; + } + } + } + + elected_candidates.push(winner.clone()); + } // end of all rounds + + // 4.1- Update backing stake of candidates and nominators + for n in &mut nominators { + for e in &mut n.edges { + // if the target of this vote is among the winners, otherwise let go. + if let Some(c) = elected_candidates.iter_mut().find(|c| c.who == e.who) { + e.elected = true; + // NOTE: always divide last to avoid collapse to zero. + e.backing_stake = >::sa(n.budget.as_().saturating_mul(*e.load) / *n.load); + c.backing_stake = c.backing_stake.saturating_add(e.backing_stake); + if c.who != n.who { + // Only update the exposure if this vote is from some other account. + c.exposure.total = c.exposure.total.saturating_add(e.backing_stake); + c.exposure.others.push( + IndividualExposure { who: n.who.clone(), value: e.backing_stake } + ); + } + } + } + } + + // Optionally perform equalise post-processing. + if config.equalise { + let tolerance = config.tolerance; + let equalise_iterations = config.iterations; + + // Fix indexes + nominators.iter_mut().for_each(|n| { + n.edges.iter_mut().for_each(|e| { + if let Some(idx) = elected_candidates.iter().position(|c| c.who == e.who) { + e.elected_idx = idx; + } + }); + }); + + for _i in 0..equalise_iterations { + let mut max_diff = >::zero(); + nominators.iter_mut().for_each(|mut n| { + let diff = equalise::(&mut n, &mut elected_candidates, tolerance); + if diff > max_diff { + max_diff = diff; + } + }); + if max_diff < tolerance { + break; + } + } + } + + } else { + if candidates.len() > minimum_validator_count { + // if we don't have enough candidates, just choose all that have some vote. + elected_candidates = candidates; + for n in &mut nominators { + let nominator = n.who.clone(); + for e in &mut n.edges { + if let Some(c) = elected_candidates.iter_mut().find(|c| c.who == e.who && c.who != nominator) { + c.exposure.total = c.exposure.total.saturating_add(n.budget); + c.exposure.others.push( + IndividualExposure { who: n.who.clone(), value: n.budget } + ); + } + } + } + } else { + // if we have less than minimum, use the previous validator set. + return None + } + } + Some(elected_candidates) +} + +pub fn equalise( + nominator: &mut Nominator>, + elected_candidates: &mut Vec>>, + tolerance: BalanceOf +) -> BalanceOf { + + let mut elected_edges = nominator.edges + .iter_mut() + .filter(|e| e.elected) + .collect::>>>(); + if elected_edges.len() == 0 { return >::zero(); } + let stake_used = elected_edges + .iter() + .fold(>::zero(), |s, e| s.saturating_add(e.backing_stake)); + let backed_stakes = elected_edges + .iter() + .map(|e| elected_candidates[e.elected_idx].backing_stake) + .collect::>>(); + let backing_backed_stake = elected_edges + .iter() + .filter(|e| e.backing_stake > >::zero()) + .map(|e| elected_candidates[e.elected_idx].backing_stake) + .collect::>>(); + + let mut difference; + if backing_backed_stake.len() > 0 { + let max_stake = *backing_backed_stake + .iter() + .max() + .expect("vector with positive length will have a max; qed"); + let min_stake = *backed_stakes + .iter() + .min() + .expect("vector with positive length will have a min; qed"); + difference = max_stake.saturating_sub(min_stake); + difference = difference.saturating_add(nominator.budget.saturating_sub(stake_used)); + if difference < tolerance { + return difference; + } + } else { + difference = nominator.budget; + } + + // Undo updates to exposure + elected_edges.iter_mut().for_each(|e| { + // NOTE: no assertions in the runtime, but this should nonetheless be indicative. + //assert_eq!(elected_candidates[e.elected_idx].who, e.who); + elected_candidates[e.elected_idx].backing_stake -= e.backing_stake; + elected_candidates[e.elected_idx].exposure.total -= e.backing_stake; + e.backing_stake = >::zero(); + }); + + elected_edges.sort_unstable_by_key(|e| elected_candidates[e.elected_idx].backing_stake); + + let mut cumulative_stake = >::zero(); + let mut last_index = elected_edges.len() - 1; + let budget = nominator.budget; + elected_edges.iter_mut().enumerate().for_each(|(idx, e)| { + let stake = elected_candidates[e.elected_idx].backing_stake; + let stake_mul = stake.checked_mul(&>::sa(idx as u64)).unwrap_or(>::max_value()); + let stake_sub = stake_mul.saturating_sub(cumulative_stake); + if stake_sub > budget { + last_index = idx.checked_sub(1).unwrap_or(0); + return + } + cumulative_stake = cumulative_stake.saturating_add(stake); + }); + + let last_stake = elected_candidates[elected_edges[last_index].elected_idx].backing_stake; + let split_ways = last_index + 1; + let excess = nominator.budget + .saturating_add(cumulative_stake) + .saturating_sub( + last_stake.checked_mul(&>::sa(split_ways as u64)) + .unwrap_or(>::max_value()) + ); + let nominator_address = nominator.who.clone(); + elected_edges.iter_mut().take(split_ways).for_each(|e| { + let c = &mut elected_candidates[e.elected_idx]; + e.backing_stake = (excess / >::sa(split_ways as u64)).saturating_add(last_stake) - c.backing_stake; + c.exposure.total = c.exposure.total.saturating_add(e.backing_stake); + c.backing_stake = c.backing_stake.saturating_add(e.backing_stake); + if let Some(i_expo) = c.exposure.others.iter_mut().find(|i| i.who == nominator_address) { + i_expo.value = e.backing_stake; + } + }); + difference +} diff --git a/srml/staking/src/tests.rs b/srml/staking/src/tests.rs index ecc506ba3d0a15e2c6e26c8d32293bc917c8258c..e8716c13fb4269bfe8d9413c8468bc1a39e9b8dc 100644 --- a/srml/staking/src/tests.rs +++ b/srml/staking/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -20,423 +20,786 @@ use super::*; use runtime_io::with_externalities; -use srml_support::{assert_ok, assert_noop}; -use mock::{Balances, Session, Staking, System, Timestamp, Test, new_test_ext, Origin}; -use srml_support::traits::Currency; +use phragmen; +use primitives::Perquintill; +use srml_support::{assert_ok, assert_noop, EnumerableStorageMap}; +use mock::{Balances, Session, Staking, System, Timestamp, Test, ExtBuilder, Origin}; +use srml_support::traits::{Currency, ReservableCurrency}; #[test] -fn note_null_offline_should_work() { - with_externalities(&mut new_test_ext(0, 3, 3, 0, true, 10), || { - assert_eq!(Staking::offline_slash_grace(), 0); - assert_eq!(Staking::slash_count(&10), 0); - assert_eq!(Balances::free_balance(&10), 1); - System::set_extrinsic_index(1); - assert_eq!(Staking::slash_count(&10), 0); - assert_eq!(Balances::free_balance(&10), 1); - assert!(Staking::forcing_new_era().is_none()); +fn basic_setup_works() { + // Verifies initial conditions of mock + with_externalities(&mut ExtBuilder::default() + .build(), + || { + assert_eq!(Staking::bonded(&11), Some(10)); // Account 11 is stashed and locked, and account 10 is the controller + assert_eq!(Staking::bonded(&21), Some(20)); // Account 21 is stashed and locked, and account 20 is the controller + assert_eq!(Staking::bonded(&1), None); // Account 1 is not a stashed + + // Account 10 controls the stash from account 11, which is 100 * balance_factor units + assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000, active: 1000, unlocking: vec![] })); + // Account 20 controls the stash from account 21, which is 200 * balance_factor units + assert_eq!(Staking::ledger(&20), Some(StakingLedger { stash: 21, total: 1000, active: 1000, unlocking: vec![] })); + // Account 1 does not control any stash + assert_eq!(Staking::ledger(&1), None); + + // ValidatorPrefs are default, thus unstake_threshold is 3, other values are default for their type + assert_eq!(>::enumerate().collect::>(), vec![ + (21, ValidatorPrefs { unstake_threshold: 3, validator_payment: 0 }), + (11, ValidatorPrefs { unstake_threshold: 3, validator_payment: 0 }) + ]); + + // Account 100 is the default nominator + 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 }] }); + + // The number of validators required. + assert_eq!(Staking::validator_count(), 2); + + // Initial Era and session + assert_eq!(Staking::current_era(), 0); + assert_eq!(Session::current_index(), 0); + + // initial rewards + assert_eq!(Staking::current_session_reward(), 10); + + // initial slot_stake + assert_eq!(Staking::slot_stake(), 1125); // Naive + // assert_eq!(Staking::slot_stake(), 1250); // Post-process + + // initial slash_count of validators + assert_eq!(Staking::slash_count(&11), 0); + assert_eq!(Staking::slash_count(&21), 0); }); } #[test] -fn invulnerability_should_work() { - with_externalities(&mut new_test_ext(0, 3, 3, 0, true, 10), || { - assert_ok!(Staking::set_invulnerables(vec![10])); - Balances::set_free_balance(&10, 70); +fn no_offline_should_work() { + // Test the staking module works when no validators are offline + with_externalities(&mut ExtBuilder::default().build(), + || { + // Slashing begins for validators immediately if found offline assert_eq!(Staking::offline_slash_grace(), 0); + // Account 10 has not been reported offline assert_eq!(Staking::slash_count(&10), 0); - assert_eq!(Balances::free_balance(&10), 70); - System::set_extrinsic_index(1); - Staking::on_offline_validator(10, 1); + // Account 10 has `balance_factor` free balance + assert_eq!(Balances::free_balance(&10), 1); + // Nothing happens to Account 10, as expected assert_eq!(Staking::slash_count(&10), 0); - assert_eq!(Balances::free_balance(&10), 70); + assert_eq!(Balances::free_balance(&10), 1); + // New era is not being forced assert!(Staking::forcing_new_era().is_none()); }); } #[test] -fn note_offline_should_work() { - with_externalities(&mut new_test_ext(0, 3, 3, 0, true, 10), || { - Balances::set_free_balance(&10, 70); +fn invulnerability_should_work() { + // Test that users can be invulnerable from slashing and being kicked + with_externalities(&mut ExtBuilder::default().build(), + || { + // Make account 11 invulnerable + assert_ok!(Staking::set_invulnerables(vec![11])); + // Give account 11 some funds + let _ = Balances::make_free_balance_be(&11, 70); + // There is no slash grace -- slash immediately. assert_eq!(Staking::offline_slash_grace(), 0); - assert_eq!(Staking::slash_count(&10), 0); - assert_eq!(Balances::free_balance(&10), 70); - System::set_extrinsic_index(1); - Staking::on_offline_validator(10, 1); - assert_eq!(Staking::slash_count(&10), 1); - assert_eq!(Balances::free_balance(&10), 50); + // Account 11 has not been slashed + assert_eq!(Staking::slash_count(&11), 0); + // Account 11 has the 70 funds we gave it above + assert_eq!(Balances::free_balance(&11), 70); + // Account 11 should be a validator + assert!(>::exists(&11)); + + // Set account 11 as an offline validator with a large number of reports + // Should exit early if invulnerable + Staking::on_offline_validator(10, 100); + + // Show that account 11 has not been touched + assert_eq!(Staking::slash_count(&11), 0); + assert_eq!(Balances::free_balance(&11), 70); + assert!(>::exists(&11)); + // New era not being forced + // NOTE: new era is always forced once slashing happens -> new validators need to be chosen. assert!(Staking::forcing_new_era().is_none()); }); } #[test] -fn note_offline_exponent_should_work() { - with_externalities(&mut new_test_ext(0, 3, 3, 0, true, 10), || { - Balances::set_free_balance(&10, 150); +fn offline_should_slash_and_kick() { + // Test that an offline validator gets slashed and kicked + with_externalities(&mut ExtBuilder::default().build(), || { + // Give account 10 some balance + let _ = Balances::make_free_balance_be(&11, 1000); + // Confirm account 10 is a validator + assert!(>::exists(&11)); + // Validators get slashed immediately assert_eq!(Staking::offline_slash_grace(), 0); - assert_eq!(Staking::slash_count(&10), 0); - assert_eq!(Balances::free_balance(&10), 150); - System::set_extrinsic_index(1); - Staking::on_offline_validator(10, 1); - assert_eq!(Staking::slash_count(&10), 1); - assert_eq!(Balances::free_balance(&10), 130); - System::set_extrinsic_index(1); - Staking::on_offline_validator(10, 1); - assert_eq!(Staking::slash_count(&10), 2); - assert_eq!(Balances::free_balance(&10), 90); - assert!(Staking::forcing_new_era().is_none()); + // Unstake threshold is 3 + assert_eq!(Staking::validators(&11).unstake_threshold, 3); + // Account 10 has not been slashed before + assert_eq!(Staking::slash_count(&11), 0); + // Account 10 has the funds we just gave it + assert_eq!(Balances::free_balance(&11), 1000); + // Report account 10 as offline, one greater than unstake threshold + Staking::on_offline_validator(10, 4); + // Confirm user has been reported + assert_eq!(Staking::slash_count(&11), 4); + // Confirm balance has been reduced by 2^unstake_threshold * offline_slash() * amount_at_stake. + let slash_base = Staking::offline_slash() * Staking::stakers(11).total; + assert_eq!(Balances::free_balance(&11), 1000 - 2_u64.pow(3) * slash_base); + // Confirm account 10 has been removed as a validator + assert!(!>::exists(&11)); + // A new era is forced due to slashing + assert!(Staking::forcing_new_era().is_some()); }); } #[test] -fn note_offline_grace_should_work() { - with_externalities(&mut new_test_ext(0, 3, 3, 0, true, 10), || { - Balances::set_free_balance(&10, 70); - Balances::set_free_balance(&20, 70); - assert_ok!(Staking::set_offline_slash_grace(1)); +fn offline_grace_should_delay_slashing() { + // Tests that with grace, slashing is delayed + with_externalities(&mut ExtBuilder::default().build(), || { + // Initialize account 10 with balance + let _ = Balances::make_free_balance_be(&11, 70); + // Verify account 11 has balance + assert_eq!(Balances::free_balance(&11), 70); + + // Set offline slash grace + let offline_slash_grace = 1; + assert_ok!(Staking::set_offline_slash_grace(offline_slash_grace)); assert_eq!(Staking::offline_slash_grace(), 1); - assert_eq!(Staking::slash_count(&10), 0); - assert_eq!(Balances::free_balance(&10), 70); + // Check unstaked_threshold is 3 (default) + let default_unstake_threshold = 3; + assert_eq!(Staking::validators(&11), ValidatorPrefs { unstake_threshold: default_unstake_threshold, validator_payment: 0 }); - System::set_extrinsic_index(1); - Staking::on_offline_validator(10, 1); - assert_eq!(Staking::slash_count(&10), 1); - assert_eq!(Balances::free_balance(&10), 70); - assert_eq!(Staking::slash_count(&20), 0); - assert_eq!(Balances::free_balance(&20), 70); + // Check slash count is zero + assert_eq!(Staking::slash_count(&11), 0); + + // Report account 10 up to the threshold + Staking::on_offline_validator(10, default_unstake_threshold as usize + offline_slash_grace as usize); + // Confirm slash count + assert_eq!(Staking::slash_count(&11), 4); - System::set_extrinsic_index(1); + // Nothing should happen + assert_eq!(Balances::free_balance(&11), 70); + + // Report account 10 one more time Staking::on_offline_validator(10, 1); - Staking::on_offline_validator(20, 1); - assert_eq!(Staking::slash_count(&10), 2); - assert_eq!(Balances::free_balance(&10), 50); - assert_eq!(Staking::slash_count(&20), 1); - assert_eq!(Balances::free_balance(&20), 70); - assert!(Staking::forcing_new_era().is_none()); + assert_eq!(Staking::slash_count(&11), 5); + // User gets slashed + assert_eq!(Balances::free_balance(&11), 0); + // New era is forced + assert!(Staking::forcing_new_era().is_some()); }); } + #[test] -fn note_offline_force_unstake_session_change_should_work() { - with_externalities(&mut new_test_ext(0, 3, 3, 0, true, 10), || { - Balances::set_free_balance(&10, 70); - Balances::set_free_balance(&20, 70); - assert_ok!(Staking::stake(Origin::signed(1))); +fn max_unstake_threshold_works() { + // Tests that max_unstake_threshold gets used when prefs.unstake_threshold is large + with_externalities(&mut ExtBuilder::default().build(), || { + const MAX_UNSTAKE_THRESHOLD: u32 = 10; + // Two users with maximum possible balance + let _ = Balances::make_free_balance_be(&11, u64::max_value()); + let _ = Balances::make_free_balance_be(&21, u64::max_value()); + + // Give them full exposure as a staker + >::insert(&11, Exposure { total: 1000000, own: 1000000, others: vec![]}); + >::insert(&21, Exposure { total: 2000000, own: 2000000, others: vec![]}); + + // Check things are initialized correctly + assert_eq!(Balances::free_balance(&11), u64::max_value()); + assert_eq!(Balances::free_balance(&21), u64::max_value()); + assert_eq!(Staking::offline_slash_grace(), 0); + // Account 10 will have max unstake_threshold + assert_ok!(Staking::validate(Origin::signed(10), ValidatorPrefs { + unstake_threshold: MAX_UNSTAKE_THRESHOLD, + validator_payment: 0, + })); + // Account 20 could not set their unstake_threshold past 10 + assert_noop!(Staking::validate(Origin::signed(20), ValidatorPrefs { + unstake_threshold: MAX_UNSTAKE_THRESHOLD + 1, + validator_payment: 0}), + "unstake threshold too large" + ); + // Give Account 20 unstake_threshold 11 anyway, should still be limited to 10 + >::insert(21, ValidatorPrefs { + unstake_threshold: MAX_UNSTAKE_THRESHOLD + 1, + validator_payment: 0, + }); - assert_eq!(Staking::slash_count(&10), 0); - assert_eq!(Balances::free_balance(&10), 70); - assert_eq!(Staking::intentions(), vec![10, 20, 1]); - assert_eq!(Session::validators(), vec![10, 20]); + >::put(Perbill::from_fraction(0.0001)); - System::set_extrinsic_index(1); - Staking::on_offline_validator(10, 1); - assert_eq!(Balances::free_balance(&10), 50); - assert_eq!(Staking::slash_count(&10), 1); - assert_eq!(Staking::intentions(), vec![10, 20, 1]); + // Report each user 1 more than the max_unstake_threshold + Staking::on_offline_validator(10, MAX_UNSTAKE_THRESHOLD as usize + 1); + Staking::on_offline_validator(20, MAX_UNSTAKE_THRESHOLD as usize + 1); - System::set_extrinsic_index(1); - Staking::on_offline_validator(10, 1); - assert_eq!(Staking::intentions(), vec![1, 20]); - assert_eq!(Balances::free_balance(&10), 10); - assert!(Staking::forcing_new_era().is_some()); + // Show that each balance only gets reduced by 2^max_unstake_threshold times 10% + // of their total stake. + assert_eq!(Balances::free_balance(&11), u64::max_value() - 2_u64.pow(MAX_UNSTAKE_THRESHOLD) * 100); + assert_eq!(Balances::free_balance(&21), u64::max_value() - 2_u64.pow(MAX_UNSTAKE_THRESHOLD) * 200); }); } #[test] -fn note_offline_auto_unstake_session_change_should_work() { - with_externalities(&mut new_test_ext(0, 3, 3, 0, true, 10), || { - Balances::set_free_balance(&10, 7000); - Balances::set_free_balance(&20, 7000); - assert_ok!(Staking::register_preferences(Origin::signed(10), 0, ValidatorPrefs { unstake_threshold: 1, validator_payment: 0 })); - - assert_eq!(Staking::intentions(), vec![10, 20]); +fn slashing_does_not_cause_underflow() { + // Tests that slashing more than a user has does not underflow + with_externalities(&mut ExtBuilder::default().build(), || { + // Verify initial conditions + assert_eq!(Balances::free_balance(&11), 1000); + assert_eq!(Staking::offline_slash_grace(), 0); - System::set_extrinsic_index(1); - Staking::on_offline_validator(10, 1); - Staking::on_offline_validator(20, 1); - assert_eq!(Balances::free_balance(&10), 6980); - assert_eq!(Balances::free_balance(&20), 6980); - assert_eq!(Staking::intentions(), vec![10, 20]); - assert!(Staking::forcing_new_era().is_none()); + // Set validator preference so that 2^unstake_threshold would cause overflow (greater than 64) + >::insert(11, ValidatorPrefs { + unstake_threshold: 10, + validator_payment: 0, + }); - System::set_extrinsic_index(1); - Staking::on_offline_validator(10, 1); - Staking::on_offline_validator(20, 1); - assert_eq!(Balances::free_balance(&10), 6940); - assert_eq!(Balances::free_balance(&20), 6940); - assert_eq!(Staking::intentions(), vec![20]); - assert!(Staking::forcing_new_era().is_some()); + System::set_block_number(1); + Session::check_rotate_session(System::block_number()); - System::set_extrinsic_index(1); - Staking::on_offline_validator(20, 1); - assert_eq!(Balances::free_balance(&10), 6940); - assert_eq!(Balances::free_balance(&20), 6860); - assert_eq!(Staking::intentions(), vec![20]); - - System::set_extrinsic_index(1); - Staking::on_offline_validator(20, 1); - assert_eq!(Balances::free_balance(&10), 6940); - assert_eq!(Balances::free_balance(&20), 6700); - assert_eq!(Staking::intentions(), vec![0u64; 0]); + // Should not panic + Staking::on_offline_validator(10, 100); + // Confirm that underflow has not occurred, and account balance is set to zero + assert_eq!(Balances::free_balance(&11), 0); }); } #[test] fn rewards_should_work() { - with_externalities(&mut new_test_ext(0, 3, 3, 0, true, 10), || { + // should check that: + // * rewards get recorded per session + // * rewards get paid per Era + // * Check that nominators are also rewarded + with_externalities(&mut ExtBuilder::default() + .session_length(3) + .sessions_per_era(3) + .build(), + || { + let delay = 0; + // this test is only in the scope of one era. Since this variable changes + // at the last block/new era, we'll save it. + let session_reward = 10; + + // Set payee to controller + assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); + + // Initial config should be correct assert_eq!(Staking::era_length(), 9); assert_eq!(Staking::sessions_per_era(), 3); assert_eq!(Staking::last_era_length_change(), 0); assert_eq!(Staking::current_era(), 0); assert_eq!(Session::current_index(), 0); - assert_eq!(Balances::total_balance(&10), 1); + assert_eq!(Staking::current_session_reward(), 10); + + // check the balance of a validator accounts. + assert_eq!(Balances::total_balance(&11), 1000); + // and the nominator (to-be) + let _ = Balances::make_free_balance_be(&2, 500); + assert_eq!(Balances::total_balance(&2), 500); + + // add a dummy nominator. + // NOTE: this nominator is being added 'manually'. a Further test (nomination_and_reward..) will add it via '.nominate()' + >::insert(&11, Exposure { + own: 500, // equal division indicates that the reward will be equally divided among validator and nominator. + total: 1000, + others: vec![IndividualExposure {who: 2, value: 500 }] + }); - System::set_block_number(3); - Timestamp::set_timestamp(15); // on time. + >::insert(&2, RewardDestination::Stash); + assert_eq!(Staking::payee(2), RewardDestination::Stash); + assert_eq!(Staking::payee(11), RewardDestination::Controller); + + let mut block = 3; + // Block 3 => Session 1 => Era 0 + System::set_block_number(block); + Timestamp::set_timestamp(block*5); // on time. Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 0); assert_eq!(Session::current_index(), 1); - assert_eq!(Balances::total_balance(&10), 11); - System::set_block_number(6); - Timestamp::set_timestamp(31); // a little late + + // session triggered: the reward value stashed should be 10 -- defined in ExtBuilder genesis. + assert_eq!(Staking::current_session_reward(), session_reward); + assert_eq!(Staking::current_era_reward(), session_reward); + + block = 6; // Block 6 => Session 2 => Era 0 + System::set_block_number(block); + Timestamp::set_timestamp(block*5 + delay); // a little late. Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 0); assert_eq!(Session::current_index(), 2); - assert_eq!(Balances::total_balance(&10), 20); // less reward - System::set_block_number(9); - Timestamp::set_timestamp(50); // very late + + // session reward is the same, + assert_eq!(Staking::current_session_reward(), session_reward); + // though 2 will be deducted while stashed in the era reward due to delay + assert_eq!(Staking::current_era_reward(), 2*session_reward - delay); + + block = 9; // Block 9 => Session 3 => Era 1 + System::set_block_number(block); + Timestamp::set_timestamp(block*5); // back to being on time. no delays Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 1); assert_eq!(Session::current_index(), 3); - assert_eq!(Balances::total_balance(&10), 27); // much less reward + + assert_eq!(Balances::total_balance(&10), 1 + (3*session_reward - delay)/2); + assert_eq!(Balances::total_balance(&2), 500 + (3*session_reward - delay)/2); }); } #[test] -fn slashing_should_work() { - with_externalities(&mut new_test_ext(0, 3, 3, 0, true, 10), || { - assert_eq!(Staking::era_length(), 9); - assert_eq!(Staking::sessions_per_era(), 3); - assert_eq!(Staking::last_era_length_change(), 0); - assert_eq!(Staking::current_era(), 0); - assert_eq!(Session::current_index(), 0); +fn multi_era_reward_should_work() { + // should check that: + // The value of current_session_reward is set at the end of each era, based on + // slot_stake and session_reward. Check and verify this. + with_externalities(&mut ExtBuilder::default() + .session_length(3) + .sessions_per_era(3) + .nominate(false) + .build(), + || { + let delay = 0; + let session_reward = 10; + + // This is set by the test config builder. + assert_eq!(Staking::current_session_reward(), session_reward); + + // check the balance of a validator accounts. assert_eq!(Balances::total_balance(&10), 1); - System::set_block_number(3); + // Set payee to controller + assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); + + let mut block = 3; + // Block 3 => Session 1 => Era 0 + System::set_block_number(block); + Timestamp::set_timestamp(block*5); // on time. Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 0); assert_eq!(Session::current_index(), 1); - assert_eq!(Balances::total_balance(&10), 11); - System::set_block_number(6); + // session triggered: the reward value stashed should be 10 -- defined in ExtBuilder genesis. + assert_eq!(Staking::current_session_reward(), session_reward); + assert_eq!(Staking::current_era_reward(), session_reward); + + block = 6; // Block 6 => Session 2 => Era 0 + System::set_block_number(block); + Timestamp::set_timestamp(block*5 + delay); // a little late. Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 0); assert_eq!(Session::current_index(), 2); - assert_eq!(Balances::total_balance(&10), 21); - System::set_block_number(7); - System::set_extrinsic_index(1); - Staking::on_offline_validator(10, 1); - Staking::on_offline_validator(20, 1); - assert_eq!(Balances::total_balance(&10), 1); - }); -} + assert_eq!(Staking::current_session_reward(), session_reward); + assert_eq!(Staking::current_era_reward(), 2*session_reward - delay); + + block = 9; // Block 9 => Session 3 => Era 1 + System::set_block_number(block); + Timestamp::set_timestamp(block*5); // back to being punktlisch. no delayss + Session::check_rotate_session(System::block_number()); + assert_eq!(Staking::current_era(), 1); + assert_eq!(Session::current_index(), 3); + + // 1 + sum of of the session rewards accumulated + let recorded_balance = 1 + 3*session_reward - delay; + assert_eq!(Balances::total_balance(&10), recorded_balance); + + // the reward for next era will be: session_reward * slot_stake + let new_session_reward = Staking::session_reward() * Staking::slot_stake(); + assert_eq!(Staking::current_session_reward(), new_session_reward); + + // fast forward to next era: + block=12;System::set_block_number(block);Timestamp::set_timestamp(block*5);Session::check_rotate_session(System::block_number()); + block=15;System::set_block_number(block);Timestamp::set_timestamp(block*5);Session::check_rotate_session(System::block_number()); + // intermediate test. + assert_eq!(Staking::current_era_reward(), 2*new_session_reward); + // new era is triggered here. + block=18;System::set_block_number(block);Timestamp::set_timestamp(block*5);Session::check_rotate_session(System::block_number()); + + // pay time + assert_eq!(Balances::total_balance(&10), 3*new_session_reward + recorded_balance); + }); +} #[test] fn staking_should_work() { - with_externalities(&mut new_test_ext(0, 1, 2, 0, true, 0), || { - - assert_eq!(Staking::era_length(), 2); - assert_eq!(Staking::validator_count(), 2); - assert_eq!(Session::validators(), vec![10, 20]); + // should test: + // * new validators can be added to the default set + // * new ones will be chosen per era + // * either one can unlock the stash and back-down from being a validator via `chill`ing. + with_externalities(&mut ExtBuilder::default() + .sessions_per_era(3) + .nominate(false) + .fare(false) // to give 20 more staked value + .build(), + || { + // remember + compare this along with the test. + assert_eq!(Session::validators(), vec![20, 10]); assert_ok!(Staking::set_bonding_duration(2)); assert_eq!(Staking::bonding_duration(), 2); - // Block 1: Add three validators. No obvious change. + // 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); - assert_ok!(Staking::stake(Origin::signed(1))); - assert_ok!(Staking::stake(Origin::signed(2))); - assert_ok!(Staking::stake(Origin::signed(4))); Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 0); - assert_eq!(Session::validators(), vec![10, 20]); - // Block 2: New validator set now. + // 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!(Session::validators(), vec![20, 10]); + + // --- Block 2: System::set_block_number(2); Session::check_rotate_session(System::block_number()); - assert_eq!(Staking::current_era(), 1); - assert_eq!(Session::validators(), vec![4, 2]); + assert_eq!(Staking::current_era(), 0); - // Block 3: Unstake highest, introduce another staker. No change yet. + // No effects will be seen so far. Era has not been yet triggered. + assert_eq!(Session::validators(), vec![20, 10]); + + + // --- Block 3: the validators will now change. System::set_block_number(3); - assert_ok!(Staking::stake(Origin::signed(3))); - assert_ok!(Staking::unstake(Origin::signed(4), (Staking::intentions().iter().position(|&x| x == 4).unwrap() as u32).into())); - assert_eq!(Staking::current_era(), 1); Session::check_rotate_session(System::block_number()); - // Block 4: New era - validators change. + // 2 only voted for 4 and 20 + assert_eq!(Session::validators().len(), 2); + assert_eq!(Session::validators(), vec![20, 4]); + assert_eq!(Staking::current_era(), 1); + + + // --- Block 4: Unstake 4 as a validator, freeing up the balance stashed in 3 System::set_block_number(4); Session::check_rotate_session(System::block_number()); - assert_eq!(Staking::current_era(), 2); - assert_eq!(Session::validators(), vec![3, 2]); - // Block 5: Transfer stake from highest to lowest. No change yet. - System::set_block_number(5); - assert_ok!(Balances::transfer(Origin::signed(4), 1, 40)); - Session::check_rotate_session(System::block_number()); + // 4 will chill + Staking::chill(Origin::signed(4)).unwrap(); - // Block 6: Lowest now validator. - System::set_block_number(6); - Session::check_rotate_session(System::block_number()); - assert_eq!(Session::validators(), vec![1, 3]); + // nothing should be changed so far. + assert_eq!(Session::validators(), vec![20, 4]); + assert_eq!(Staking::current_era(), 1); - // Block 7: Unstake three. No change yet. - System::set_block_number(7); - assert_ok!(Staking::unstake(Origin::signed(3), (Staking::intentions().iter().position(|&x| x == 3).unwrap() as u32).into())); + + // --- Block 5: nothing. 4 is still there. + System::set_block_number(5); Session::check_rotate_session(System::block_number()); - assert_eq!(Session::validators(), vec![1, 3]); + assert_eq!(Session::validators(), vec![20, 4]); + assert_eq!(Staking::current_era(), 1); + - // Block 8: Back to one and two. - System::set_block_number(8); + // --- Block 6: 4 will not be a validator. + System::set_block_number(6); Session::check_rotate_session(System::block_number()); - assert_eq!(Session::validators(), vec![1, 2]); + assert_eq!(Staking::current_era(), 2); + assert_eq!(Session::validators().contains(&4), false); + assert_eq!(Session::validators(), 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![] })); + // 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)); }); } #[test] -fn nominating_and_rewards_should_work() { - with_externalities(&mut new_test_ext(0, 1, 1, 0, true, 10), || { +fn less_than_needed_candidates_works() { + // Test the situation where the number of validators are less than `ValidatorCount` but more than + // The expected behavior is to choose all the candidates that have some vote. + with_externalities(&mut ExtBuilder::default() + .minimum_validator_count(1) + .validator_count(3) + .nominate(false) + .build(), + || { assert_eq!(Staking::era_length(), 1); - assert_eq!(Staking::validator_count(), 2); - assert_eq!(Staking::bonding_duration(), 3); - assert_eq!(Session::validators(), vec![10, 20]); + assert_eq!(Staking::validator_count(), 3); + assert_eq!(Staking::minimum_validator_count(), 1); + // initial validators + assert_eq!(Session::validators(), vec![20, 10]); + + // 10 and 20 are now valid candidates. + // trigger era System::set_block_number(1); - assert_ok!(Staking::stake(Origin::signed(1))); - assert_ok!(Staking::stake(Origin::signed(2))); - assert_ok!(Staking::stake(Origin::signed(3))); - assert_ok!(Staking::nominate(Origin::signed(4), 1)); Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 1); - assert_eq!(Session::validators(), vec![1, 3]); // 4 + 1, 3 - assert_eq!(Balances::total_balance(&1), 10); - assert_eq!(Balances::total_balance(&2), 20); - assert_eq!(Balances::total_balance(&3), 30); - assert_eq!(Balances::total_balance(&4), 40); - System::set_block_number(2); - assert_ok!(Staking::unnominate(Origin::signed(4), 0)); - Session::check_rotate_session(System::block_number()); - assert_eq!(Staking::current_era(), 2); - assert_eq!(Session::validators(), vec![3, 2]); - assert_eq!(Balances::total_balance(&1), 16); - assert_eq!(Balances::total_balance(&2), 20); - assert_eq!(Balances::total_balance(&3), 60); - assert_eq!(Balances::total_balance(&4), 64); + // both validators will be chosen again. NO election algorithm is even executed. + assert_eq!(Session::validators(), vec![20, 10]); - System::set_block_number(3); - assert_ok!(Staking::stake(Origin::signed(4))); - assert_ok!(Staking::unstake(Origin::signed(3), (Staking::intentions().iter().position(|&x| x == 3).unwrap() as u32).into())); - assert_ok!(Staking::nominate(Origin::signed(3), 1)); - Session::check_rotate_session(System::block_number()); - assert_eq!(Session::validators(), vec![1, 4]); - assert_eq!(Balances::total_balance(&1), 16); - assert_eq!(Balances::total_balance(&2), 40); - assert_eq!(Balances::total_balance(&3), 80); - assert_eq!(Balances::total_balance(&4), 64); + // But the exposure is updated in a simple way. No external votes exists. This is purely self-vote. + assert_eq!(Staking::stakers(10).others.iter().map(|e| e.who).collect::>>(), vec![]); + assert_eq!(Staking::stakers(20).others.iter().map(|e| e.who).collect::>>(), vec![]); + }); +} - System::set_block_number(4); +#[test] +fn no_candidate_emergency_condition() { + // Test the situation where the number of validators are less than `ValidatorCount` and less than + // The expected behavior is to choose all candidates from the previous era. + with_externalities(&mut ExtBuilder::default() + .minimum_validator_count(10) + .validator_count(15) + .validator_pool(true) + .nominate(false) + .build(), + || { + assert_eq!(Staking::era_length(), 1); + assert_eq!(Staking::validator_count(), 15); + + // initial validators + assert_eq!(Session::validators(), vec![10, 20, 30, 40]); + + // trigger era + System::set_block_number(1); Session::check_rotate_session(System::block_number()); - assert_eq!(Balances::total_balance(&1), 26); - assert_eq!(Balances::total_balance(&2), 40); - assert_eq!(Balances::total_balance(&3), 133); - assert_eq!(Balances::total_balance(&4), 128); + assert_eq!(Staking::current_era(), 1); + + // No one nominates => no one has a proper vote => no change + assert_eq!(Session::validators(), vec![10, 20, 30, 40]); }); } #[test] -fn rewards_with_off_the_table_should_work() { - with_externalities(&mut new_test_ext(0, 1, 1, 0, true, 10), || { +fn nominating_and_rewards_should_work() { + // For now it tests a functionality which somehow overlaps with other tests: + // the fact that the nominator is rewarded properly. + // + // PHRAGMEN OUTPUT: running this test with the reference impl gives: + // + // Votes [('10', 1000, ['10']), ('20', 1000, ['20']), ('30', 1000, ['30']), ('40', 1000, ['40']), ('2', 1000, ['10', '20', '30']), ('4', 1000, ['10', '20', '40'])] + // Sequential Phragmén gives + // 10 is elected with stake 2200.0 and score 0.0003333333333333333 + // 20 is elected with stake 1800.0 and score 0.0005555555555555556 + + // 10 has load 0.0003333333333333333 and supported + // 10 with stake 1000.0 + // 20 has load 0.0005555555555555556 and supported + // 20 with stake 1000.0 + // 30 has load 0 and supported + // 30 with stake 0 + // 40 has load 0 and supported + // 40 with stake 0 + // 2 has load 0.0005555555555555556 and supported + // 10 with stake 600.0 20 with stake 400.0 30 with stake 0.0 + // 4 has load 0.0005555555555555556 and supported + // 10 with stake 600.0 20 with stake 400.0 40 with stake 0.0 + + // Sequential Phragmén with post processing gives + // 10 is elected with stake 2000.0 and score 0.0003333333333333333 + // 20 is elected with stake 2000.0 and score 0.0005555555555555556 + + // 10 has load 0.0003333333333333333 and supported + // 10 with stake 1000.0 + // 20 has load 0.0005555555555555556 and supported + // 20 with stake 1000.0 + // 30 has load 0 and supported + // 30 with stake 0 + // 40 has load 0 and supported + // 40 with stake 0 + // 2 has load 0.0005555555555555556 and supported + // 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!(Session::validators(), vec![40, 30]); + + // Set payee to controller + assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); + assert_ok!(Staking::set_payee(Origin::signed(20), RewardDestination::Controller)); + assert_ok!(Staking::set_payee(Origin::signed(30), RewardDestination::Controller)); + assert_ok!(Staking::set_payee(Origin::signed(40), RewardDestination::Controller)); + + // default reward for the first session. + let session_reward = 10; + assert_eq!(Staking::current_session_reward(), session_reward); + + // give the man some money + let initial_balance = 1000; + for i in [1, 2, 3, 4, 5, 10, 11, 20, 21].iter() { + let _ = Balances::make_free_balance_be(i, initial_balance); + } + + // record their balances. + for i in 1..5 { assert_eq!(Balances::total_balance(&i), initial_balance); } + + // bond two account pairs and state interest in nomination. + // 2 will nominate for 10, 20, 30 + assert_ok!(Staking::bond(Origin::signed(1), 2, 1000, RewardDestination::Controller)); + assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 21, 31])); + // 4 will nominate for 10, 20, 40 + assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::Controller)); + assert_ok!(Staking::nominate(Origin::signed(4), vec![11, 21, 41])); + System::set_block_number(1); - assert_ok!(Staking::stake(Origin::signed(1))); - assert_ok!(Staking::nominate(Origin::signed(2), 1)); - assert_ok!(Staking::stake(Origin::signed(3))); Session::check_rotate_session(System::block_number()); - assert_eq!(Session::validators(), vec![1, 3]); // 1 + 2, 3 - assert_eq!(Balances::total_balance(&1), 10); - assert_eq!(Balances::total_balance(&2), 20); - assert_eq!(Balances::total_balance(&3), 30); + assert_eq!(Staking::current_era(), 1); + + // 10 and 20 have more votes, they will be chosen by phragmen. + assert_eq!(Session::validators(), vec![20, 10]); + + // OLD validators must have already received some rewards. + assert_eq!(Balances::total_balance(&40), 1 + session_reward); + assert_eq!(Balances::total_balance(&30), 1 + session_reward); + + // ------ 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 + 1200); + // 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![600, 600]); + 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); + assert_eq!(Staking::stakers(41).total, 0); + System::set_block_number(2); - assert_ok!(Staking::register_preferences( - Origin::signed(1), - (Staking::intentions().into_iter().position(|i| i == 1).unwrap() as u32).into(), - ValidatorPrefs { unstake_threshold: 3, validator_payment: 4 } - )); - Session::check_rotate_session(System::block_number()); - assert_eq!(Balances::total_balance(&1), 22); - assert_eq!(Balances::total_balance(&2), 37); - assert_eq!(Balances::total_balance(&3), 60); + Session::check_rotate_session(System::block_number()); + // next session reward. + let new_session_reward = Staking::session_reward() * 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)); + // 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)); + + // 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); }); } #[test] -fn nominating_slashes_should_work() { - with_externalities(&mut new_test_ext(0, 2, 2, 0, true, 10), || { - assert_eq!(Staking::era_length(), 4); +fn nominators_also_get_slashed() { + // A nominator should be slashed if the validator they nominated is slashed + with_externalities(&mut ExtBuilder::default().nominate(false).build(), || { + assert_eq!(Staking::era_length(), 1); assert_eq!(Staking::validator_count(), 2); - assert_eq!(Staking::bonding_duration(), 12); - assert_eq!(Session::validators(), vec![10, 20]); + // slash happens immediately. + assert_eq!(Staking::offline_slash_grace(), 0); + // Account 10 has not been reported offline + assert_eq!(Staking::slash_count(&10), 0); + // initial validators + assert_eq!(Session::validators(), vec![20, 10]); + >::put(Perbill::from_percent(12)); - System::set_block_number(2); - Session::check_rotate_session(System::block_number()); + // Set payee to controller + assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); - Timestamp::set_timestamp(15); - System::set_block_number(4); - assert_ok!(Staking::stake(Origin::signed(1))); - assert_ok!(Staking::stake(Origin::signed(3))); - assert_ok!(Staking::nominate(Origin::signed(2), 3)); - assert_ok!(Staking::nominate(Origin::signed(4), 1)); - Session::check_rotate_session(System::block_number()); + // give the man some money. + let initial_balance = 1000; + for i in [1, 2, 3, 10].iter() { + let _ = Balances::make_free_balance_be(i, initial_balance); + } - assert_eq!(Staking::current_era(), 1); - assert_eq!(Session::validators(), vec![1, 3]); // 1 + 4, 3 + 2 - assert_eq!(Balances::total_balance(&1), 10); - assert_eq!(Balances::total_balance(&2), 20); - assert_eq!(Balances::total_balance(&3), 30); - assert_eq!(Balances::total_balance(&4), 40); + // 2 will nominate for 10 + let nominator_stake = 500; + assert_ok!(Staking::bond(Origin::signed(1), 2, nominator_stake, RewardDestination::default())); + assert_ok!(Staking::nominate(Origin::signed(2), vec![20, 10])); - System::set_block_number(5); - System::set_extrinsic_index(1); - Staking::on_offline_validator(1, 1); - Staking::on_offline_validator(3, 1); - assert_eq!(Balances::total_balance(&1), 0); //slashed - assert_eq!(Balances::total_balance(&2), 20); //not slashed - assert_eq!(Balances::total_balance(&3), 10); //slashed - assert_eq!(Balances::total_balance(&4), 30); //slashed + // new era, pay rewards, + System::set_block_number(1); + Session::check_rotate_session(System::block_number()); + + // Nominator stash didn't collect any. + assert_eq!(Balances::total_balance(&2), initial_balance); + + // 10 goes offline + Staking::on_offline_validator(10, 4); + let expo = Staking::stakers(10); + let slash_value = Staking::offline_slash() * expo.total * 2_u64.pow(3); + let total_slash = expo.total.min(slash_value); + let validator_slash = expo.own.min(total_slash); + let nominator_slash = nominator_stake.min(total_slash - validator_slash); + + // initial + first era reward + slash + assert_eq!(Balances::total_balance(&10), initial_balance + 10 - validator_slash); + assert_eq!(Balances::total_balance(&2), initial_balance - nominator_slash); + // Because slashing happened. + assert!(Staking::forcing_new_era().is_some()); }); } #[test] fn double_staking_should_fail() { - with_externalities(&mut new_test_ext(0, 1, 2, 0, true, 0), || { - System::set_block_number(1); - assert_ok!(Staking::stake(Origin::signed(1))); - assert_noop!(Staking::stake(Origin::signed(1)), "Cannot stake if already staked."); - assert_noop!(Staking::nominate(Origin::signed(1), 1), "Cannot nominate if already staked."); - assert_ok!(Staking::nominate(Origin::signed(2), 1)); - assert_noop!(Staking::stake(Origin::signed(2)), "Cannot stake if already nominating."); - assert_noop!(Staking::nominate(Origin::signed(2), 1), "Cannot nominate if already nominating."); - }); + // should test (in the same order): + // * an account already bonded as controller CAN be reused as the controller of another account. + // * an account already bonded as stash cannot be the controller of another account. + // * an account already bonded as stash cannot nominate. + // * an account already bonded as controller can nominate. + with_externalities(&mut ExtBuilder::default() + .sessions_per_era(2) + .build(), + || { + let arbitrary_value = 5; + System::set_block_number(1); + // 2 = controller, 1 stashed => ok + 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"); + // 1 = stashed => attempting to nominate should fail. + assert_noop!(Staking::nominate(Origin::signed(1), vec![1]), "not a controller"); + // 2 = controller => nominating should work. + assert_ok!(Staking::nominate(Origin::signed(2), vec![1])); + }); +} + +#[test] +fn double_controlling_should_fail() { + // should test (in the same order): + // * an account already bonded as controller CAN be reused as the controller of another account. + // * an account already bonded as stash cannot be the controller of another account. + // * an account already bonded as stash cannot nominate. + // * an account already bonded as controller can nominate. + with_externalities(&mut ExtBuilder::default() + .sessions_per_era(2) + .build(), + || { + let arbitrary_value = 5; + System::set_block_number(1); + // 2 = controller, 1 stashed => ok + assert_ok!(Staking::bond(Origin::signed(1), 2, arbitrary_value, RewardDestination::default())); + // 2 = controller, 3 stashed (Note that 2 is reused.) => no-op + assert_noop!(Staking::bond(Origin::signed(3), 2, arbitrary_value, RewardDestination::default()), "controller already paired"); + }); } #[test] -fn staking_eras_work() { - with_externalities(&mut new_test_ext(0, 1, 2, 0, true, 0), || { +fn session_and_eras_work() { + with_externalities(&mut ExtBuilder::default() + .sessions_per_era(2) + .build(), + || { assert_eq!(Staking::era_length(), 2); assert_eq!(Staking::sessions_per_era(), 2); assert_eq!(Staking::last_era_length_change(), 0); @@ -503,97 +866,1124 @@ fn staking_eras_work() { } #[test] -fn staking_balance_transfer_when_bonded_should_not_work() { - with_externalities(&mut new_test_ext(0, 1, 3, 1, false, 0), || { - Balances::set_free_balance(&1, 111); - assert_ok!(Staking::stake(Origin::signed(1))); - assert_noop!(Balances::transfer(Origin::signed(1), 2, 69), "cannot transfer illiquid funds"); +fn cannot_transfer_staked_balance() { + // Tests that a stash account cannot transfer funds + with_externalities(&mut ExtBuilder::default().nominate(false).build(), || { + // Confirm account 11 is stashed + assert_eq!(Staking::bonded(&11), Some(10)); + // Confirm account 11 has some free balance + assert_eq!(Balances::free_balance(&11), 1000); + // Confirm account 11 (via controller 10) is totally staked + assert_eq!(Staking::stakers(&11).total, 1000); + // Confirm account 11 cannot transfer as a result + assert_noop!(Balances::transfer(Origin::signed(11), 20, 1), "account liquidity restrictions prevent withdrawal"); + + // Give account 11 extra free balance + let _ = Balances::make_free_balance_be(&11, 10000); + // Confirm that account 11 can now transfer some balance + assert_ok!(Balances::transfer(Origin::signed(11), 20, 1)); + }); +} + +#[test] +fn cannot_transfer_staked_balance_2() { + // Tests that a stash account cannot transfer funds + // Same test as above but with 20 + // 21 has 2000 free balance but 1000 at stake + with_externalities(&mut ExtBuilder::default() + .nominate(false) + .fare(true) + .build(), + || { + // Confirm account 21 is stashed + assert_eq!(Staking::bonded(&21), Some(20)); + // Confirm account 21 has some free balance + assert_eq!(Balances::free_balance(&21), 2000); + // Confirm account 21 (via controller 20) is totally staked + assert_eq!(Staking::stakers(&21).total, 1000); + // Confirm account 21 can transfer at most 1000 + assert_noop!(Balances::transfer(Origin::signed(21), 20, 1001), "account liquidity restrictions prevent withdrawal"); + assert_ok!(Balances::transfer(Origin::signed(21), 20, 1000)); }); } #[test] -fn deducting_balance_when_bonded_should_not_work() { - with_externalities(&mut new_test_ext(0, 1, 3, 1, false, 0), || { - Balances::set_free_balance(&1, 111); - >::insert(1, 2); +fn cannot_reserve_staked_balance() { + // Checks that a bonded account cannot reserve balance from free balance + with_externalities(&mut ExtBuilder::default().build(), || { + // Confirm account 11 is stashed + assert_eq!(Staking::bonded(&11), Some(10)); + // Confirm account 11 has some free balance + assert_eq!(Balances::free_balance(&11), 1000); + // Confirm account 11 (via controller 10) is totally staked + assert_eq!(Staking::stakers(&11).total, 1125); + // Confirm account 11 cannot transfer as a result + assert_noop!(Balances::reserve(&11, 1), "account liquidity restrictions prevent withdrawal"); + + // Give account 11 extra free balance + let _ = Balances::make_free_balance_be(&11, 10000); + // Confirm account 11 can now reserve balance + assert_ok!(Balances::reserve(&11, 1)); + }); +} + +#[test] +fn reward_destination_works() { + // Rewards go to the correct destination as determined in Payee + with_externalities(&mut ExtBuilder::default().nominate(false).build(), || { + // Check that account 11 is a validator + assert!(>::exists(11)); + // Check that account 11 is a validator + assert!(Staking::current_elected().contains(&11)); + // Check the balance of the validator account + assert_eq!(Balances::free_balance(&10), 1); + // Check the balance of the stash account + assert_eq!(Balances::free_balance(&11), 1000); + // Check these two accounts are bonded + assert_eq!(Staking::bonded(&11), Some(10)); + // Check how much is at stake + assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000, active: 1000, unlocking: vec![] })); + // Track current session reward + let mut current_session_reward = Staking::current_session_reward(); + + // Move forward the system for payment System::set_block_number(1); - assert_eq!(Staking::unlock_block(&1), LockStatus::LockedUntil(2)); - assert_noop!(Balances::reserve(&1, 69), "cannot transfer illiquid funds"); + Timestamp::set_timestamp(5); + Session::check_rotate_session(System::block_number()); + + // Check that RewardDestination is Staked (default) + assert_eq!(Staking::payee(&11), RewardDestination::Staked); + // Check current session reward is 10 + assert_eq!(current_session_reward, 10); + // Check that reward went to the stash account of validator + assert_eq!(Balances::free_balance(&11), 1000 + current_session_reward); + // Check that amount at stake increased accordingly + assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000 + 10, active: 1000 + 10, unlocking: vec![] })); + // Update current session reward + current_session_reward = Staking::current_session_reward(); // 1010 (1* slot_stake) + + //Change RewardDestination to Stash + >::insert(&11, RewardDestination::Stash); + + // Move forward the system for payment + System::set_block_number(2); + Timestamp::set_timestamp(10); + Session::check_rotate_session(System::block_number()); + + // Check that RewardDestination is Stash + assert_eq!(Staking::payee(&11), RewardDestination::Stash); + // Check that reward went to the stash account + assert_eq!(Balances::free_balance(&11), 1000 + 10 + current_session_reward); + // Record this value + let recorded_stash_balance = 1000 + 10 + current_session_reward; + + // Check that amount at stake is NOT increased + assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000 + 10, active: 1000 + 10, unlocking: vec![] })); + + // Change RewardDestination to Controller + >::insert(&11, RewardDestination::Controller); + + // Check controller balance + assert_eq!(Balances::free_balance(&10), 1); + + // Move forward the system for payment + System::set_block_number(3); + Timestamp::set_timestamp(15); + Session::check_rotate_session(System::block_number()); + + // Check that RewardDestination is Controller + assert_eq!(Staking::payee(&11), RewardDestination::Controller); + // Check that reward went to the controller account + assert_eq!(Balances::free_balance(&10), 1 + 1010); + // Check that amount at stake is NOT increased + assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000 + 10, active: 1000 + 10, unlocking: vec![] })); + // Check that amount in staked account is NOT increased. + assert_eq!(Balances::free_balance(&11), recorded_stash_balance); }); } #[test] -fn slash_value_calculation_does_not_overflow() { - with_externalities(&mut new_test_ext(0, 3, 3, 0, true, 10), || { +fn validator_payment_prefs_work() { + // Test that validator preferences are correctly honored + // Note: unstake threshold is being directly tested in slashing tests. + // This test will focus on validator payment. + with_externalities(&mut ExtBuilder::default() + .session_length(3) + .sessions_per_era(3) + .build(), + || { + let session_reward = 10; + let validator_cut = 5; + let validator_initial_balance = Balances::total_balance(&11); + // Initial config should be correct assert_eq!(Staking::era_length(), 9); assert_eq!(Staking::sessions_per_era(), 3); assert_eq!(Staking::last_era_length_change(), 0); assert_eq!(Staking::current_era(), 0); assert_eq!(Session::current_index(), 0); - assert_eq!(Balances::total_balance(&10), 1); - assert_eq!(Staking::intentions(), vec![10, 20]); - assert_eq!(Staking::offline_slash_grace(), 0); - // set validator preferences so the validator doesn't back down after - // slashing. - >::insert(10, ValidatorPrefs { - unstake_threshold: u32::max_value(), - validator_payment: 0, + assert_eq!(Staking::current_session_reward(), session_reward); + + // check the balance of a validator accounts. + assert_eq!(Balances::total_balance(&10), 1); + // check the balance of a validator's stash accounts. + assert_eq!(Balances::total_balance(&11), validator_initial_balance); + // and the nominator (to-be) + let _ = Balances::make_free_balance_be(&2, 500); + + // add a dummy nominator. + // NOTE: this nominator is being added 'manually', use '.nominate()' to do it realistically. + >::insert(&11, Exposure { + own: 500, // equal division indicates that the reward will be equally divided among validator and nominator. + total: 1000, + others: vec![IndividualExposure {who: 2, value: 500 }] + }); + >::insert(&2, RewardDestination::Stash); + >::insert(&11, ValidatorPrefs { + unstake_threshold: 3, + validator_payment: validator_cut }); - System::set_block_number(3); + // ------------ Fast forward + let mut block = 3; + // Block 3 => Session 1 => Era 0 + System::set_block_number(block); + Timestamp::set_timestamp(block*5); // on time. Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 0); assert_eq!(Session::current_index(), 1); - assert_eq!(Balances::total_balance(&10), 11); - // the balance type is u64, so after slashing 64 times, - // the slash value should have overflowed. add a couple extra for - // good measure with the slash grace. - trait TypeEq {} - impl TypeEq for (A, A) {} - fn assert_type_eq() {} - assert_type_eq::<(u64, ::Balance)>(); + // session triggered: the reward value stashed should be 10 -- defined in ExtBuilder genesis. + assert_eq!(Staking::current_session_reward(), session_reward); + assert_eq!(Staking::current_era_reward(), session_reward); - Staking::on_offline_validator(10, 100); + block = 6; // Block 6 => Session 2 => Era 0 + System::set_block_number(block); + Timestamp::set_timestamp(block*5); // a little late. + Session::check_rotate_session(System::block_number()); + assert_eq!(Staking::current_era(), 0); + assert_eq!(Session::current_index(), 2); + + assert_eq!(Staking::current_session_reward(), session_reward); + assert_eq!(Staking::current_era_reward(), 2*session_reward); + + block = 9; // Block 9 => Session 3 => Era 1 + System::set_block_number(block); + Timestamp::set_timestamp(block*5); + Session::check_rotate_session(System::block_number()); + assert_eq!(Staking::current_era(), 1); + assert_eq!(Session::current_index(), 3); + + // whats left to be shared is the sum of 3 rounds minus the validator's cut. + let shared_cut = 3 * session_reward - validator_cut; + // Validator's payee is Staked account, 11, reward will be paid here. + assert_eq!(Balances::total_balance(&11), validator_initial_balance + shared_cut/2 + validator_cut); + // Controller account will not get any reward. + assert_eq!(Balances::total_balance(&10), 1); + // Rest of the reward will be shared and paid to the nominator in stake. + assert_eq!(Balances::total_balance(&2), 500 + shared_cut/2); }); + } #[test] -fn next_slash_value_calculation_does_not_overflow() { - with_externalities(&mut new_test_ext(0, 3, 3, 0, true, 10), || { - assert_eq!(Staking::era_length(), 9); - assert_eq!(Staking::sessions_per_era(), 3); - assert_eq!(Staking::last_era_length_change(), 0); +fn bond_extra_works() { + // Tests that extra `free_balance` in the stash can be added to stake + // NOTE: this tests only verifies `StakingLedger` for correct updates + // See `bond_extra_and_withdraw_unbonded_works` for more details and updates on `Exposure`. + with_externalities(&mut ExtBuilder::default().build(), + || { + // Check that account 10 is a validator + assert!(>::exists(11)); + // Check that account 10 is bonded to account 11 + assert_eq!(Staking::bonded(&11), Some(10)); + // Check how much is at stake + assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000, active: 1000, unlocking: vec![] })); + + // Give account 11 some large free balance greater than total + let _ = Balances::make_free_balance_be(&11, 1000000); + + // Call the bond_extra function from controller, add only 100 + assert_ok!(Staking::bond_extra(Origin::signed(11), 100)); + // There should be 100 more `total` and `active` in the ledger + assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000 + 100, active: 1000 + 100, unlocking: vec![] })); + + // Call the bond_extra function with a large number, should handle it + assert_ok!(Staking::bond_extra(Origin::signed(11), u64::max_value())); + // The full amount of the funds should now be in the total and active + assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000000, active: 1000000, unlocking: vec![] })); + + }); +} + +#[test] +fn bond_extra_and_withdraw_unbonded_works() { + // * Should test + // * Given an account being bonded [and chosen as a validator](not mandatory) + // * It can add extra funds to the bonded account. + // * it can unbond a portion of its funds from the stash account. + // * Once the unbonding period is done, it can actually take the funds out of the stash. + with_externalities(&mut ExtBuilder::default() + .nominate(false) + .build(), + || { + // Set payee to controller. avoids confusion + assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); + + // Set unbonding era (bonding_duration) to 2 + assert_ok!(Staking::set_bonding_duration(2)); + + // Give account 11 some large free balance greater than total + let _ = Balances::make_free_balance_be(&11, 1000000); + + // Initial config should be correct + assert_eq!(Staking::sessions_per_era(), 1); assert_eq!(Staking::current_era(), 0); assert_eq!(Session::current_index(), 0); + assert_eq!(Staking::current_session_reward(), 10); + + // check the balance of a validator accounts. assert_eq!(Balances::total_balance(&10), 1); - assert_eq!(Staking::intentions(), vec![10, 20]); - assert_eq!(Staking::offline_slash_grace(), 0); - // set validator preferences so the validator doesn't back down after - // slashing. - >::insert(10, ValidatorPrefs { - unstake_threshold: u32::max_value(), - validator_payment: 0, - }); + // confirm that 10 is a normal validator and gets paid at the end of the era. + System::set_block_number(1); + Timestamp::set_timestamp(5); + Session::check_rotate_session(System::block_number()); + assert_eq!(Staking::current_era(), 1); + assert_eq!(Session::current_index(), 1); - // we have enough balance to cover the last slash before overflow - Balances::set_free_balance(&10, u64::max_value()); - assert_eq!(Balances::total_balance(&10), u64::max_value()); + // NOTE: despite having .nominate() in extBuilder, 20 doesn't have a share since + // rewards are paid before election in new_era() + assert_eq!(Balances::total_balance(&10), 1 + 10); - // the balance type is u64, so after slashing 64 times, - // the slash value should have overflowed. add a couple extra for - // good measure with the slash grace. - trait TypeEq {} - impl TypeEq for (A, A) {} - fn assert_type_eq() {} - assert_type_eq::<(u64, ::Balance)>(); + // Initial state of 10 + assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000, active: 1000, unlocking: vec![] })); + assert_eq!(Staking::stakers(&11), Exposure { total: 1000, own: 1000, others: vec![] }); - // the total slash value should overflow the balance type - // therefore the total validator balance should be slashed - Staking::on_offline_validator(10, 100); + // deposit the extra 100 units + Staking::bond_extra(Origin::signed(11), 100).unwrap(); + + assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000 + 100, active: 1000 + 100, unlocking: vec![] })); + // Exposure is a snapshot! only updated after the next era update. + assert_ne!(Staking::stakers(&11), Exposure { total: 1000 + 100, own: 1000 + 100, others: vec![] }); + + // trigger next era. + System::set_block_number(2);Timestamp::set_timestamp(10);Session::check_rotate_session(System::block_number()); + assert_eq!(Staking::current_era(), 2); + assert_eq!(Session::current_index(), 2); + + // ledger should be the same. + assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000 + 100, active: 1000 + 100, unlocking: vec![] })); + // Exposure is now updated. + assert_eq!(Staking::stakers(&11), Exposure { total: 1000 + 100, own: 1000 + 100, others: vec![] }); + // Note that by this point 10 also have received more rewards, but we don't care now. + // assert_eq!(Balances::total_balance(&10), 1 + 10 + MORE_REWARD); + + // Unbond almost all of the funds in stash. + Staking::unbond(Origin::signed(10), 1000).unwrap(); + assert_eq!(Staking::ledger(&10), Some(StakingLedger { + stash: 11, total: 1000 + 100, active: 100, unlocking: vec![UnlockChunk{ value: 1000, era: 2 + 2}] })); + + // Attempting to free the balances now will fail. 2 eras need to pass. + Staking::withdraw_unbonded(Origin::signed(10)).unwrap(); + assert_eq!(Staking::ledger(&10), Some(StakingLedger { + stash: 11, total: 1000 + 100, active: 100, unlocking: vec![UnlockChunk{ value: 1000, era: 2 + 2}] })); + + // trigger next era. + System::set_block_number(3);Timestamp::set_timestamp(15);Session::check_rotate_session(System::block_number()); + assert_eq!(Staking::current_era(), 3); + assert_eq!(Session::current_index(), 3); + + // nothing yet + Staking::withdraw_unbonded(Origin::signed(10)).unwrap(); + assert_eq!(Staking::ledger(&10), Some(StakingLedger { + stash: 11, total: 1000 + 100, active: 100, unlocking: vec![UnlockChunk{ value: 1000, era: 2 + 2}] })); + + // trigger next era. + System::set_block_number(4);Timestamp::set_timestamp(20);Session::check_rotate_session(System::block_number()); + assert_eq!(Staking::current_era(), 4); + assert_eq!(Session::current_index(), 4); + + Staking::withdraw_unbonded(Origin::signed(10)).unwrap(); + // Now the value is free and the staking ledger is updated. + assert_eq!(Staking::ledger(&10), Some(StakingLedger { + stash: 11, total: 100, active: 100, unlocking: vec![] })); + }) +} + +#[test] +fn slot_stake_is_least_staked_validator_and_limits_maximum_punishment() { + // Test that slot_stake is determined by the least staked validator + // Test that slot_stake is the maximum punishment that can happen to a validator + // Note that rewardDestination is the stash account by default + // Note that unlike reward slash will affect free_balance, not the stash account. + with_externalities(&mut ExtBuilder::default() + .nominate(false) + .fare(false) + .build(), + || { + // Give the man some money. + // Confirm validator count is 2 + assert_eq!(Staking::validator_count(), 2); + // Confirm account 10 and 20 are validators + assert!(>::exists(&11) && >::exists(&21)); + + assert_eq!(Staking::stakers(&11).total, 1000); + assert_eq!(Staking::stakers(&21).total, 2000); + + // Give the man some money. + let _ = Balances::make_free_balance_be(&10, 1000); + let _ = Balances::make_free_balance_be(&20, 1000); + + // We confirm initialized slot_stake is this value + assert_eq!(Staking::slot_stake(), Staking::stakers(&11).total); + + // Now lets lower account 20 stake + >::insert(&21, Exposure { total: 69, own: 69, others: vec![] }); + assert_eq!(Staking::stakers(&21).total, 69); + >::insert(&20, StakingLedger { stash: 22, total: 69, active: 69, unlocking: vec![] }); + + // New era --> rewards are paid --> stakes are changed + System::set_block_number(1); + Timestamp::set_timestamp(5); + Session::check_rotate_session(System::block_number()); + + assert_eq!(Staking::current_era(), 1); + // -- new balances + reward + assert_eq!(Staking::stakers(&11).total, 1000 + 10); + assert_eq!(Staking::stakers(&21).total, 69 + 10); + + // -- Note that rewards are going directly to stash, not as free balance. + assert_eq!(Balances::free_balance(&10), 1000); + assert_eq!(Balances::free_balance(&20), 1000); + + // -- slot stake should also be updated. + assert_eq!(Staking::slot_stake(), 79); + + // // If 10 gets slashed now, despite having +1000 in stash, it will be slashed byt 79, which is the slot stake + Staking::on_offline_validator(10, 4); + // // Confirm user has been reported + assert_eq!(Staking::slash_count(&11), 4); + // // check the balance of 10 (slash will be deducted from free balance.) + assert_eq!(Balances::free_balance(&11), 1000 + 10 - 50 /*5% of 1000*/ * 8 /*2**3*/); + }); +} +#[test] +fn on_free_balance_zero_stash_removes_validator() { + // Tests that validator storage items are cleaned up when stash is empty + // Tests that storage items are untouched when controller is empty + with_externalities(&mut ExtBuilder::default() + .existential_deposit(10) + .build(), + || { + // Check that account 10 is a validator + assert!(>::exists(11)); + // Check the balance of the validator account + assert_eq!(Balances::free_balance(&10), 256); + // Check the balance of the stash account + assert_eq!(Balances::free_balance(&11), 256000); + // Check these two accounts are bonded + assert_eq!(Staking::bonded(&11), Some(10)); + + // Set some storage items which we expect to be cleaned up + // Initiate slash count storage item + Staking::on_offline_validator(10, 1); + // Set payee information + assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Stash)); + + // Check storage items that should be cleaned up + assert!(>::exists(&10)); + assert!(>::exists(&11)); + assert!(>::exists(&11)); + assert!(>::exists(&11)); + assert!(>::exists(&11)); + + // Reduce free_balance of controller to 0 + Balances::slash(&10, u64::max_value()); + + // Check the balance of the stash account has not been touched + assert_eq!(Balances::free_balance(&11), 256000); + // Check these two accounts are still bonded + assert_eq!(Staking::bonded(&11), Some(10)); + + // Check storage items have not changed + assert!(>::exists(&10)); + assert!(>::exists(&11)); + assert!(>::exists(&11)); + assert!(>::exists(&11)); + assert!(>::exists(&11)); + + // Reduce free_balance of stash to 0 + Balances::slash(&11, u64::max_value()); + // Check total balance of stash + assert_eq!(Balances::total_balance(&11), 0); + + // Check storage items do not exist + assert!(!>::exists(&10)); + assert!(!>::exists(&11)); + assert!(!>::exists(&11)); + assert!(!>::exists(&11)); + assert!(!>::exists(&11)); + assert!(!>::exists(&11)); + }); +} + +#[test] +fn on_free_balance_zero_stash_removes_nominator() { + // Tests that nominator storage items are cleaned up when stash is empty + // Tests that storage items are untouched when controller is empty + with_externalities(&mut ExtBuilder::default() + .existential_deposit(10) + .build(), + || { + // Make 10 a nominator + assert_ok!(Staking::nominate(Origin::signed(10), vec![20])); + // Check that account 10 is a nominator + assert!(>::exists(11)); + // Check the balance of the nominator account + assert_eq!(Balances::free_balance(&10), 256); + // Check the balance of the stash account + assert_eq!(Balances::free_balance(&11), 256000); + // Check these two accounts are bonded + assert_eq!(Staking::bonded(&11), Some(10)); + + // Set payee information + assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Stash)); + + + // Check storage items that should be cleaned up + assert!(>::exists(&10)); + assert!(>::exists(&11)); + assert!(>::exists(&11)); + assert!(>::exists(&11)); + + // Reduce free_balance of controller to 0 + Balances::slash(&10, u64::max_value()); + // Check total balance of account 10 assert_eq!(Balances::total_balance(&10), 0); + + // Check the balance of the stash account has not been touched + assert_eq!(Balances::free_balance(&11), 256000); + // Check these two accounts are still bonded + assert_eq!(Staking::bonded(&11), Some(10)); + + // Check storage items have not changed + assert!(>::exists(&10)); + assert!(>::exists(&11)); + assert!(>::exists(&11)); + assert!(>::exists(&11)); + + // Reduce free_balance of stash to 0 + Balances::slash(&11, u64::max_value()); + // Check total balance of stash + assert_eq!(Balances::total_balance(&11), 0); + + // Check storage items do not exist + assert!(!>::exists(&10)); + assert!(!>::exists(&11)); + assert!(!>::exists(&11)); + assert!(!>::exists(&11)); + assert!(!>::exists(&11)); + assert!(!>::exists(&11)); + }); +} + +#[test] +fn phragmen_poc_works() { + // Tests the POC test of the phragmen, mentioned in the paper and reference implementation. + // Initial votes: + // Votes [ + // ('2', 500, ['10', '20', '30']), + // ('4', 500, ['10', '20', '40']), + // ('10', 1000, ['10']), + // ('20', 1000, ['20']), + // ('30', 1000, ['30']), + // ('40', 1000, ['40'])] + // + // Sequential Phragmén gives + // 10 is elected with stake 1666.6666666666665 and score 0.0005 + // 20 is elected with stake 1333.3333333333333 and score 0.00075 + + // 2 has load 0.00075 and supported + // 10 with stake 333.3333333333333 20 with stake 166.66666666666666 30 with stake 0.0 + // 4 has load 0.00075 and supported + // 10 with stake 333.3333333333333 20 with stake 166.66666666666666 40 with stake 0.0 + // 10 has load 0.0005 and supported + // 10 with stake 1000.0 + // 20 has load 0.00075 and supported + // 20 with stake 1000.0 + // 30 has load 0 and supported + // 30 with stake 0 + // 40 has load 0 and supported + // 40 with stake 0 + + // Sequential Phragmén with post processing gives + // 10 is elected with stake 1500.0 and score 0.0005 + // 20 is elected with stake 1500.0 and score 0.00075 + // + // 10 has load 0.0005 and supported + // 10 with stake 1000.0 + // 20 has load 0.00075 and supported + // 20 with stake 1000.0 + // 30 has load 0 and supported + // 30 with stake 0 + // 40 has load 0 and supported + // 40 with stake 0 + // 2 has load 0.00075 and supported + // 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!(Session::validators(), vec![40, 30]); + + assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000, active: 1000, unlocking: vec![] })); + assert_eq!(Staking::ledger(&20), Some(StakingLedger { stash: 21, total: 1000, active: 1000, unlocking: vec![] })); + assert_eq!(Staking::ledger(&30), Some(StakingLedger { stash: 31, total: 1000, active: 1000, unlocking: vec![] })); + assert_eq!(Staking::ledger(&40), Some(StakingLedger { stash: 41, total: 1000, active: 1000, unlocking: vec![] })); + + assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); + assert_ok!(Staking::set_payee(Origin::signed(20), RewardDestination::Controller)); + assert_ok!(Staking::set_payee(Origin::signed(30), RewardDestination::Controller)); + assert_ok!(Staking::set_payee(Origin::signed(40), RewardDestination::Controller)); + + // no one is a nominator + assert_eq!(>::enumerate().count(), 0 as usize); + + // bond [2,1] / [4,3] a nominator + let _ = Balances::deposit_creating(&1, 1000); + let _ = Balances::deposit_creating(&3, 1000); + + assert_ok!(Staking::bond(Origin::signed(1), 2, 500, RewardDestination::default())); + assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 21, 31])); + + assert_ok!(Staking::bond(Origin::signed(3), 4, 500, RewardDestination::default())); + assert_ok!(Staking::nominate(Origin::signed(4), vec![11, 21, 41])); + + // New era => election algorithm will trigger + System::set_block_number(1); + Session::check_rotate_session(System::block_number()); + + assert_eq!(Session::validators(), 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); + + // 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]); + }); +} + +#[test] +fn phragmen_election_works_example_2() { + // tests the encapsulated phragmen::elect function. + with_externalities(&mut ExtBuilder::default().nominate(false).build(), || { + // initial setup of 10 and 20, both validators + assert_eq!(Session::validators(), vec![20, 10]); + + // no one is a nominator + assert_eq!(>::enumerate().count(), 0 as usize); + + // Bond [30, 31] as the third validator + assert_ok!(Staking::bond(Origin::signed(31), 30, 1000, RewardDestination::default())); + assert_ok!(Staking::validate(Origin::signed(30), ValidatorPrefs::default())); + + // bond [2,1](A), [4,3](B), as 2 nominators + // Give all of them some balance to be able to bond properly. + for i in &[1, 3] { let _ = Balances::deposit_creating(i, 2000); } + assert_ok!(Staking::bond(Origin::signed(1), 2, 50, RewardDestination::default())); + assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 21])); + + assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::default())); + assert_ok!(Staking::nominate(Origin::signed(4), vec![11, 31])); + + let rounds = || 2 as usize; + let validators = || >::enumerate(); + let nominators = || >::enumerate(); + let min_validator_count = Staking::minimum_validator_count() as usize; + + let winners = phragmen::elect::( + rounds, + validators, + nominators, + Staking::slashable_balance_of, + min_validator_count, + ElectionConfig::> { + equalise: true, + tolerance: >::sa(10 as u64), + iterations: 10, + } + ); + + let winners = winners.unwrap(); + + // 10 and 30 must be the winners + assert_eq!(winners.iter().map(|w| w.who).collect::>>(), vec![11, 31]); + + let winner_10 = winners.iter().filter(|w| w.who == 11).nth(0).unwrap(); + let winner_30 = winners.iter().filter(|w| w.who == 31).nth(0).unwrap(); + + // python implementation output: + /* + Votes [ + ('10', 1000, ['10']), + ('20', 1000, ['20']), + ('30', 1000, ['30']), + ('2', 50, ['10', '20']), + ('4', 1000, ['10', '30']) + ] + Sequential Phragmén gives + 10 is elected with stake 1705.7377049180327 and score 0.0004878048780487805 + 30 is elected with stake 1344.2622950819673 and score 0.0007439024390243903 + + 10 has load 0.0004878048780487805 and supported + 10 with stake 1000.0 + 20 has load 0 and supported + 20 with stake 0 + 30 has load 0.0007439024390243903 and supported + 30 with stake 1000.0 + 2 has load 0.0004878048780487805 and supported + 10 with stake 50.0 20 with stake 0.0 + 4 has load 0.0007439024390243903 and supported + 10 with stake 655.7377049180328 30 with stake 344.26229508196724 + + Sequential Phragmén with post processing gives + 10 is elected with stake 1525.0 and score 0.0004878048780487805 + 30 is elected with stake 1525.0 and score 0.0007439024390243903 + + 10 has load 0.0004878048780487805 and supported + 10 with stake 1000.0 + 20 has load 0 and supported + 20 with stake 0 + 30 has load 0.0007439024390243903 and supported + 30 with stake 1000.0 + 2 has load 0.0004878048780487805 and supported + 10 with stake 50.0 20 with stake 0.0 + 4 has load 0.0007439024390243903 and supported + 10 with stake 475.0 30 with stake 525.0 + + + */ + + assert_eq!(winner_10.exposure.total, 1000 + 525); + assert_eq!(winner_10.score, Perquintill::from_quintillionths(487804878048780)); + assert_eq!(winner_10.exposure.others[0].value, 475); + assert_eq!(winner_10.exposure.others[1].value, 50); + + assert_eq!(winner_30.exposure.total, 1000 + 525); + assert_eq!(winner_30.score, Perquintill::from_quintillionths(743902439024390)); + assert_eq!(winner_30.exposure.others[0].value, 525); + }) +} + +#[test] +fn switching_roles() { + // Show: It should be possible to switch between roles (nominator, validator, idle) with minimal overhead. + with_externalities(&mut ExtBuilder::default() + .nominate(false) + .sessions_per_era(3) + .build(), + || { + // Reset reward destination + for i in &[10, 20] { assert_ok!(Staking::set_payee(Origin::signed(*i), RewardDestination::Controller)); } + + assert_eq!(Session::validators(), vec![20, 10]); + + // put some money in account that we'll use. + for i in 1..7 { let _ = Balances::deposit_creating(&i, 5000); } + + // add 2 nominators + assert_ok!(Staking::bond(Origin::signed(1), 2, 2000, RewardDestination::Controller)); + assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 5])); + + assert_ok!(Staking::bond(Origin::signed(3), 4, 500, RewardDestination::Controller)); + assert_ok!(Staking::nominate(Origin::signed(4), vec![21, 1])); + + // add a new validator candidate + assert_ok!(Staking::bond(Origin::signed(5), 6, 1000, RewardDestination::Controller)); + assert_ok!(Staking::validate(Origin::signed(6), ValidatorPrefs::default())); + + // new block + System::set_block_number(1); + Session::check_rotate_session(System::block_number()); + + // no change + assert_eq!(Session::validators(), vec![20, 10]); + + // new block + System::set_block_number(2); + Session::check_rotate_session(System::block_number()); + + // no change + assert_eq!(Session::validators(), vec![20, 10]); + + // new block --> ne era --> new validators + System::set_block_number(3); + Session::check_rotate_session(System::block_number()); + + // with current nominators 10 and 5 have the most stake + assert_eq!(Session::validators(), vec![6, 10]); + + // 2 decides to be a validator. Consequences: + // new stakes: + // 10: 1000 self vote + // 6: 1000 self vote + // 20: 1000 self vote + 500 vote + // 2: 2000 self vote + 500 vote. + assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default())); + + System::set_block_number(4); + Session::check_rotate_session(System::block_number()); + assert_eq!(Session::validators(), vec![6, 10]); + + System::set_block_number(5); + Session::check_rotate_session(System::block_number()); + assert_eq!(Session::validators(), vec![6, 10]); + + // ne era + System::set_block_number(6); + Session::check_rotate_session(System::block_number()); + assert_eq!(Session::validators(), vec![2, 20]); + }); +} + +#[test] +fn wrong_vote_is_null() { + with_externalities(&mut ExtBuilder::default() + .nominate(false) + .validator_pool(true) + .build(), + || { + assert_eq!(Session::validators(), vec![40, 30]); + + // put some money in account that we'll use. + for i in 1..3 { let _ = Balances::deposit_creating(&i, 5000); } + + // add 1 nominators + assert_ok!(Staking::bond(Origin::signed(1), 2, 2000, RewardDestination::default())); + assert_ok!(Staking::nominate(Origin::signed(2), vec![ + 11, 21, // good votes + 1, 2, 15, 1000, 25 // crap votes. No effect. + ])); + + // new block + System::set_block_number(1); + Session::check_rotate_session(System::block_number()); + + assert_eq!(Session::validators(), vec![20, 10]); + }); +} + +#[test] +fn bond_with_no_staked_value() { + // Behavior when someone bonds with no staked value. + // Particularly when she votes and the candidate is elected. + with_externalities(&mut ExtBuilder::default() + .validator_count(3) + .nominate(false) + .minimum_validator_count(1) + .build(), || { + // setup + assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); + assert_ok!(Staking::set_payee(Origin::signed(20), RewardDestination::Controller)); + let _ = Balances::deposit_creating(&3, 1000); + let initial_balance_2 = Balances::free_balance(&2); + let initial_balance_4 = Balances::free_balance(&4); + + // initial validators + assert_eq!(Session::validators(), vec![20, 10]); + + // Stingy validator. + assert_ok!(Staking::bond(Origin::signed(1), 2, 0, RewardDestination::Controller)); + assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default())); + + System::set_block_number(1); + Session::check_rotate_session(System::block_number()); + + // Not elected even though we want 3. + assert_eq!(Session::validators(), vec![20, 10]); + + // min of 10 and 20. + assert_eq!(Staking::slot_stake(), 1000); + + // let's 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])); + + assert_eq!(Staking::ledger(4), Some(StakingLedger { stash: 3, active: 500, total: 500, unlocking: vec![]})); + + assert_eq!(Balances::free_balance(&2), initial_balance_2); + assert_eq!(Balances::free_balance(&4), initial_balance_4); + + System::set_block_number(2); + Session::check_rotate_session(System::block_number()); + + assert_eq!(Session::validators(), vec![20, 10, 2]); + assert_eq!(Staking::stakers(1), Exposure { own: 0, total: 500, others: vec![IndividualExposure { who: 3, value: 500}]}); + + assert_eq!(Staking::slot_stake(), 500); + + // 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); + + System::set_block_number(3); + Session::check_rotate_session(System::block_number()); + + let reward = Staking::current_session_reward(); + // 2 will not get any reward + // 4 will get all the reward share + assert_eq!(Balances::free_balance(&2), initial_balance_2); + // assert_eq!(Balances::free_balance(&4), initial_balance_4 + reward); + assert_eq!(Balances::free_balance(&4), initial_balance_4 + reward); + }); +} + +#[test] +fn bond_with_little_staked_value() { + // Behavior when someone bonds with little staked value. + // Particularly when she votes and the candidate is elected. + with_externalities(&mut ExtBuilder::default() + .validator_count(3) + .nominate(false) + .minimum_validator_count(1) + .build(), + || { + // setup + assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); + assert_ok!(Staking::set_payee(Origin::signed(20), RewardDestination::Controller)); + let initial_balance_2 = Balances::free_balance(&2); + + // initial validators + assert_eq!(Session::validators(), vec![20, 10]); + + // Stingy validator. + assert_ok!(Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller)); + assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default())); + + System::set_block_number(1); + Session::check_rotate_session(System::block_number()); + + // 2 is elected. + // and fucks up the slot stake. + assert_eq!(Session::validators(), vec![20, 10, 2]); + assert_eq!(Staking::slot_stake(), 1); + + // Old ones are rewarded. + assert_eq!(Balances::free_balance(&10), 1 + 10); + assert_eq!(Balances::free_balance(&20), 1 + 10); + // no rewards paid to 2. This was initial election. + assert_eq!(Balances::free_balance(&2), initial_balance_2); + + System::set_block_number(2); + Session::check_rotate_session(System::block_number()); + + assert_eq!(Session::validators(), vec![20, 10, 2]); + assert_eq!(Staking::slot_stake(), 1); + + let reward = Staking::current_session_reward(); + // 2 will not get the full reward, practically 1 + assert_eq!(Balances::free_balance(&2), initial_balance_2 + reward.max(1)); }); } + + +#[test] +#[ignore] // Enable this once post-processing is on. +fn phragmen_linear_worse_case_equalise() { + with_externalities(&mut ExtBuilder::default() + .nominate(false) + .validator_pool(true) + .fare(true) + .build(), + || { + let bond_validator = |a, b| { + let _ = Balances::deposit_creating(&(a-1), b); + assert_ok!(Staking::bond(Origin::signed(a-1), a, b, RewardDestination::Controller)); + assert_ok!(Staking::validate(Origin::signed(a), ValidatorPrefs::default())); + }; + let bond_nominator = |a, b, v| { + let _ = Balances::deposit_creating(&(a-1), b); + assert_ok!(Staking::bond(Origin::signed(a-1), a, b, RewardDestination::Controller)); + assert_ok!(Staking::nominate(Origin::signed(a), v)); + }; + + 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); + bond_validator(70, 1000); + + bond_nominator(2, 2000, vec![11]); + bond_nominator(4, 1000, vec![11, 21]); + bond_nominator(6, 1000, vec![21, 31]); + bond_nominator(8, 1000, vec![31, 41]); + bond_nominator(110, 1000, vec![41, 51]); + bond_nominator(112, 1000, vec![51, 61]); + bond_nominator(114, 1000, vec![61, 71]); + + assert_eq!(Session::validators(), vec![40, 30]); + assert_ok!(Staking::set_validator_count(7)); + + System::set_block_number(1); + Session::check_rotate_session(System::block_number()); + + assert_eq!(Session::validators(), vec![10, 60, 40, 20, 50, 30, 70]); + + // Sequential Phragmén with post processing gives + // 10 is elected with stake 3000.0 and score 0.00025 + // 30 is elected with stake 2008.8712884829595 and score 0.0003333333333333333 + // 50 is elected with stake 2000.0001049958742 and score 0.0003333333333333333 + // 60 is elected with stake 1991.128921508789 and score 0.0004444444444444444 + // 20 is elected with stake 2017.7421569824219 and score 0.0005277777777777777 + // 40 is elected with stake 2000.0001049958742 and score 0.0005555555555555556 + // 70 is elected with stake 1982.2574230340813 and score 0.0007222222222222222 + + assert_eq!(Staking::stakers(11).total, 3000); + assert_eq!(Staking::stakers(31).total, 2035); + assert_eq!(Staking::stakers(51).total, 2000); + assert_eq!(Staking::stakers(61).total, 1968); + assert_eq!(Staking::stakers(21).total, 2035); + assert_eq!(Staking::stakers(41).total, 2024); + assert_eq!(Staking::stakers(71).total, 1936); + }) +} + +#[test] +fn phragmen_chooses_correct_validators() { + with_externalities(&mut ExtBuilder::default() + .nominate(true) + .validator_pool(true) + .fare(true) + .validator_count(1) + .build(), + || { + // 4 validator candidates + // self vote + default account 100 is nominator. + assert_eq!(Staking::validator_count(), 1); + assert_eq!(Session::validators().len(), 1); + + System::set_block_number(1); + Session::check_rotate_session(System::block_number()); + + assert_eq!(Session::validators().len(), 1); + }) +} + +#[test] +fn phragmen_should_not_overflow_validators() { + with_externalities(&mut ExtBuilder::default() + .nominate(false) + .build() + , || { + let bond_validator = |a, b| { + assert_ok!(Staking::bond(Origin::signed(a-1), a, b, RewardDestination::Controller)); + assert_ok!(Staking::validate(Origin::signed(a), ValidatorPrefs::default())); + }; + let bond_nominator = |a, b, v| { + assert_ok!(Staking::bond(Origin::signed(a-1), a, b, RewardDestination::Controller)); + assert_ok!(Staking::nominate(Origin::signed(a), v)); + }; + + for i in 1..=8 { + let _ = Balances::make_free_balance_be(&i, u64::max_value()); + } + + let _ = Staking::chill(Origin::signed(10)); + let _ = Staking::chill(Origin::signed(20)); + + bond_validator(2, u64::max_value()); + bond_validator(4, u64::max_value()); + + bond_nominator(6, u64::max_value()/2, vec![1, 3]); + bond_nominator(8, u64::max_value()/2, vec![1, 3]); + + System::set_block_number(2); + Session::check_rotate_session(System::block_number()); + + assert_eq!(Session::validators(), vec![4, 2]); + }) +} + +#[test] +fn phragmen_should_not_overflow_nominators() { + with_externalities(&mut ExtBuilder::default() + .nominate(false) + .build() + , || { + let bond_validator = |a, b| { + assert_ok!(Staking::bond(Origin::signed(a-1), a, b, RewardDestination::Controller)); + assert_ok!(Staking::validate(Origin::signed(a), ValidatorPrefs::default())); + }; + let bond_nominator = |a, b, v| { + assert_ok!(Staking::bond(Origin::signed(a-1), a, b, RewardDestination::Controller)); + assert_ok!(Staking::nominate(Origin::signed(a), v)); + }; + + let _ = Staking::chill(Origin::signed(10)); + let _ = Staking::chill(Origin::signed(20)); + + for i in 1..=8 { + let _ = Balances::make_free_balance_be(&i, u64::max_value()); + } + + bond_validator(2, u64::max_value()/2); + bond_validator(4, u64::max_value()/2); + + bond_nominator(6, u64::max_value(), vec![1, 3]); + bond_nominator(8, u64::max_value(), vec![1, 3]); + + System::set_block_number(2); + Session::check_rotate_session(System::block_number()); + + assert_eq!(Session::validators(), vec![4, 2]); + }) +} + +#[test] +fn phragmen_should_not_overflow_ultimate() { + with_externalities(&mut ExtBuilder::default() + .nominate(false) + .build() + , || { + let bond_validator = |a, b| { + assert_ok!(Staking::bond(Origin::signed(a-1), a, b, RewardDestination::Controller)); + assert_ok!(Staking::validate(Origin::signed(a), ValidatorPrefs::default())); + }; + let bond_nominator = |a, b, v| { + assert_ok!(Staking::bond(Origin::signed(a-1), a, b, RewardDestination::Controller)); + assert_ok!(Staking::nominate(Origin::signed(a), v)); + }; + + for i in 1..=8 { + let _ = Balances::make_free_balance_be(&i, u64::max_value()); + } + + bond_validator(2, u64::max_value()); + bond_validator(4, u64::max_value()); + + bond_nominator(6, u64::max_value(), vec![1, 3]); + bond_nominator(8, u64::max_value(), vec![1, 3]); + + System::set_block_number(2); + Session::check_rotate_session(System::block_number()); + + assert_eq!(Session::validators(), vec![4, 2]); + }) +} \ No newline at end of file diff --git a/srml/sudo/Cargo.toml b/srml/sudo/Cargo.toml index 49df1575f44f6ca29585ff1cf4ab756dcdabdb8b..ef0bb59b538c5519b6b1f1cb7e4301d115eb5cac 100644 --- a/srml/sudo/Cargo.toml +++ b/srml/sudo/Cargo.toml @@ -6,9 +6,9 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +serde = { version = "1.0", optional = true } +parity-codec = { version = "3.2", default-features = false } +parity-codec-derive = { version = "3.1", default-features = false } sr-std = { path = "../../core/sr-std", default-features = false } sr-primitives = { path = "../../core/sr-primitives", default-features = false } srml-support = { path = "../support", default-features = false } @@ -22,7 +22,7 @@ substrate-primitives = { path = "../../core/primitives" } [features] default = ["std"] std = [ - "serde/std", + "serde", "parity-codec/std", "parity-codec-derive/std", "sr-std/std", diff --git a/srml/sudo/src/lib.rs b/srml/sudo/src/lib.rs index 5ff7fee52d2fbf1b3695ceed083e9befb1e5f929..b0650cf373ef7a19f6d0f5aa956211665adab73e 100644 --- a/srml/sudo/src/lib.rs +++ b/srml/sudo/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -58,7 +58,6 @@ decl_module! { } } -/// An event in this module. decl_event!( pub enum Event where AccountId = ::AccountId { /// A sudo just took place. diff --git a/srml/support/Cargo.toml b/srml/support/Cargo.toml index 29c4b54044fa3426e81f7a5a53302313660f32ab..318eba343b95e1258fd69a439d970ecb63257755 100644 --- a/srml/support/Cargo.toml +++ b/srml/support/Cargo.toml @@ -6,10 +6,9 @@ edition = "2018" [dependencies] hex-literal = { version = "0.1.0", optional = true } -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", 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 } @@ -18,6 +17,7 @@ inherents = { package = "substrate-inherents", path = "../../core/inherents", de srml-support-procedural = { path = "./procedural" } paste = "0.1" once_cell = { version = "0.1.6", default-features = false, optional = true } +bitmask = { git = "https://github.com/paritytech/bitmask", default-features = false } [dev-dependencies] pretty_assertions = "0.5.1" @@ -27,7 +27,8 @@ default = ["std"] std = [ "hex-literal", "once_cell", - "serde/std", + "bitmask/std", + "serde", "serde_derive", "runtime_io/std", "parity-codec/std", diff --git a/srml/support/procedural/src/lib.rs b/srml/support/procedural/src/lib.rs index dbf7c216330b3e2a44989652c6f8293693f59673..342745efde0ef4fbb4f203a39a1c7dd172f0787d 100644 --- a/srml/support/procedural/src/lib.rs +++ b/srml/support/procedural/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -33,31 +33,73 @@ use proc_macro::TokenStream; /// ```nocompile /// decl_storage! { /// trait Store for Module as Example { -/// Dummy get(dummy) config(): Option; -/// Foo get(foo) config(): T::Balance; +/// Foo get(foo) config(): u32=12; +/// Bar: map u32 => u32; +/// pub Zed build(|config| vec![(0, 0)]): linked_map u32 => u32; /// } /// } /// ``` /// -/// For now we implement a convenience trait with pre-specialised associated types, one for each -/// storage item. This allows you to gain access to publicly visible storage items from a -/// module type. Currently you must disambiguate by using `::Item` rather than -/// the simpler `Module::Item`. Hopefully the rust guys with fix this soon. +/// Declaration is set with this header `(pub) trait Store for Module as Example` +/// with `Store` a (pub) trait generated associating each storage to the Module and +/// `as Example` setting the prefix used for storages of this module, it must be unique, +/// another module with same name and same inner storage name will conflict. /// -/// An optional `GenesisConfig` struct for storage initialization can be defined, either specifically as in : +/// Basic storage consist of a name and a type, supported types are: +/// * storage value: `Foo: type`: implements [StorageValue](https://crates.parity.io/srml_support/storage/trait.StorageValue.html) +/// * storage map: `Foo: map type => type`: implements [StorageMap](https://crates.parity.io/srml_support/storage/trait.StorageMap.html) +/// * storage linked map: `Foo: linked_map type => type`: implements [StorageMap](https://crates.parity.io/srml_support/storage/trait.StorageMap.html) and [EnumarableStorageMap](https://crates.parity.io/srml_support/storage/trait.EnumerableStorageMap.html) +/// * storage double map: Foo: double_map u32, $hash(u32) => u32;` implements `StorageDoubleMap` with hasher $hash one available in `Hashable` trait +/// /!\ be careful while choosing the Hash, indeed malicious could craft second keys to lower the trie. +/// +/// And it can be extended as such: +/// +/// `#vis #name get(#getter) config(#field_name) build(#closure): #type = #default;` +/// * `#vis`: set the visibility of the structure +/// * `#name`: name of the storage, used as a prefix in the storage +/// * [optional] `get(#getter)`: implements the function #getter to `Module` +/// * [optional] `config(#field_name)`: `field_name` is optional if get is set: include in `GenesisConfig` +/// * [optional] `build(#closure)`: closure called with storage overlays +/// * `#type`: storage type +/// * [optional] `#default`: value returned when none +/// +/// Storages are accessible in multiples ways, using: +/// * the structure: `Foo::` +/// * the `Store` trait structure: ` as Store>::Foo` +/// * the getter on the module which calls get on the structure: `Module::::foo()` +/// +/// ## GenesisConfig +/// +/// An optional `GenesisConfig` struct for storage initialization can be defined, either +/// when at least one storage field requires default initialization +/// (both `get` and `config` or `build`), or specifically as in : /// ```nocompile /// decl_storage! { /// trait Store for Module as Example { /// } /// add_extra_genesis { /// config(genesis_field): GenesisFieldType; +/// config(genesis_field2): GenesisFieldType; +/// ... /// build(|_: &mut StorageOverlay, _: &mut ChildrenStorageOverlay, _: &GenesisConfig| { +/// // Modification of storages /// }) /// } /// } /// ``` -/// or when at least one storage field requires default initialization (both `get` and `config` or `build`). /// This struct can be expose as `Config` by `decl_runtime` macro. +/// +/// ### Module with instances +/// +/// `decl_storage!` macro support building modules with instances with the following syntax: (DefaultInstance type +/// is optional) +/// ```nocompile +/// trait Store for Module, I: Instance=DefaultInstance> as Example {} +/// ``` +/// +/// Then the genesis config is generated with two generic parameter `GenesisConfig` +/// and storages are now accessible using two generic parameters like: +/// `>::get()` or `Dummy::::get()` #[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 e008c81f83496e4f4e40832f4ea19165e0cab87e..5a8f7f65d5d8e835e59fc691844ee18166ffb70a 100644 --- a/srml/support/procedural/src/storage/impls.rs +++ b/srml/support/procedural/src/storage/impls.rs @@ -17,7 +17,7 @@ use proc_macro2::TokenStream as TokenStream2; use syn; use quote::quote; -use crate::storage::transformation::DeclStorageTypeInfos; +use crate::storage::transformation::{DeclStorageTypeInfos, InstanceOpts}; pub fn option_unwrap(is_option: bool) -> TokenStream2 { if !is_option { @@ -29,28 +29,38 @@ pub fn option_unwrap(is_option: bool) -> TokenStream2 { } } -pub(crate) struct Impls<'a> { +// prefix for consts in trait Instance +pub(crate) const PREFIX_FOR: &str = "PREFIX_FOR_"; +pub(crate) const HEAD_KEY_FOR: &str = "HEAD_KEY_FOR_"; + +pub(crate) struct Impls<'a, I: Iterator> { pub scrate: &'a TokenStream2, pub visibility: &'a syn::Visibility, pub traitinstance: &'a syn::Ident, pub traittype: &'a syn::TypeParamBound, + pub instance_opts: &'a InstanceOpts, pub type_infos: DeclStorageTypeInfos<'a>, pub fielddefault: TokenStream2, pub prefix: String, + pub cratename: &'a syn::Ident, pub name: &'a syn::Ident, + pub attrs: I, } -impl<'a> Impls<'a> { +impl<'a, I: Iterator> Impls<'a, I> { pub fn simple_value(self) -> TokenStream2 { let Self { scrate, visibility, traitinstance, traittype, + instance_opts, type_infos, fielddefault, prefix, name, + attrs, + .. } = self; let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos; let option_simple_1 = option_unwrap(is_option); @@ -68,17 +78,32 @@ impl<'a> Impls<'a> { } }; + let InstanceOpts { + comma_instance, + equal_default_instance, + bound_instantiable, + instance, + .. + } = 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()); + quote!{ #instance::#const_name.as_bytes() } + } else { + quote!{ #prefix.as_bytes() } + }; + // generator for value quote!{ + #( #[ #attrs ] )* + #visibility struct #name<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance>(#scrate::storage::generator::PhantomData<(#traitinstance #comma_instance)>); - #visibility struct #name<#traitinstance: #traittype>(#scrate::storage::generator::PhantomData<#traitinstance>); - - impl<#traitinstance: #traittype> #scrate::storage::generator::StorageValue<#typ> for #name<#traitinstance> { + impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::storage::generator::StorageValue<#typ> for #name<#traitinstance, #instance> { type Query = #value_type; /// Get the storage key. fn key() -> &'static [u8] { - #prefix.as_bytes() + #final_prefix } /// Load the value from the provided storage instance. @@ -102,7 +127,6 @@ impl<'a> Impls<'a> { ret } } - } } @@ -112,10 +136,13 @@ impl<'a> Impls<'a> { visibility, traitinstance, traittype, + instance_opts, type_infos, fielddefault, prefix, name, + attrs, + .. } = self; let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos; let option_simple_1 = option_unwrap(is_option); @@ -132,21 +159,38 @@ impl<'a> Impls<'a> { } } }; + + let InstanceOpts { + comma_instance, + equal_default_instance, + bound_instantiable, + instance, + .. + } = 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()); + quote!{ #instance::#const_name.as_bytes() } + } else { + quote!{ #prefix.as_bytes() } + }; + // generator for map quote!{ - #visibility struct #name<#traitinstance: #traittype>(#scrate::storage::generator::PhantomData<#traitinstance>); + #( #[ #attrs ] )* + #visibility struct #name<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance>(#scrate::storage::generator::PhantomData<(#traitinstance #comma_instance)>); - impl<#traitinstance: #traittype> #scrate::storage::generator::StorageMap<#kty, #typ> for #name<#traitinstance> { + impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::storage::generator::StorageMap<#kty, #typ> for #name<#traitinstance, #instance> { type Query = #value_type; /// Get the prefix key in storage. fn prefix() -> &'static [u8] { - #prefix.as_bytes() + #final_prefix } /// Get the storage key used to fetch a value corresponding to a specific key. fn key_for(x: &#kty) -> #scrate::rstd::vec::Vec { - let mut key = #prefix.as_bytes().to_vec(); + let mut key = >::prefix().to_vec(); #scrate::codec::Encode::encode_to(x, &mut key); key } @@ -182,16 +226,41 @@ impl<'a> Impls<'a> { visibility, traitinstance, traittype, + instance_opts, type_infos, fielddefault, prefix, name, + attrs, + .. } = self; + + let InstanceOpts { + comma_instance, + equal_default_instance, + bound_instantiable, + instance, + .. + } = 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()); + quote!{ #instance::#const_name.as_bytes() } + } else { + quote!{ #prefix.as_bytes() } + }; + + // 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()); + quote!{ #instance::#const_name.as_bytes() } + } else { + let final_head_key = format!("head of {}", prefix); + quote!{ #final_head_key.as_bytes() } + }; + let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos; let option_simple_1 = option_unwrap(is_option); - // make sure to use different prefix for head and elements. - let head_key = format!("head of {}", prefix); - let prefix = format!("{}", prefix); 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()); @@ -217,7 +286,7 @@ impl<'a> Impls<'a> { // generator for linked map let helpers = quote! { /// Linkage data of an element (it's successor and predecessor) - #[derive(#scrate::parity_codec_derive::Encode, #scrate::parity_codec_derive::Decode)] + #[derive(#scrate::codec::Encode, #scrate::codec::Decode)] pub(crate) struct #linkage { /// Previous element key in storage (None for the first element) pub previous: Option, @@ -247,30 +316,22 @@ impl<'a> Impls<'a> { pub _data: #phantom_data, } - impl<'a, S: #scrate::GenericStorage, K, V> Iterator for Enumerator<'a, S, K, V> where - K: 'a + #scrate::codec::Codec, - V: 'a + #scrate::codec::Decode, + impl<'a, S: #scrate::GenericStorage, #traitinstance: #traittype, #instance #bound_instantiable> Iterator for Enumerator<'a, S, #kty, (#typ, #traitinstance, #instance)> + where #traitinstance: 'a { - type Item = (K, V); + type Item = (#kty, #typ); fn next(&mut self) -> Option { let next = self.next.take()?; - let key_for = key_for(&next); - let (val, linkage): (V, Linkage) = self.storage.get(&*key_for) + let key_for = as #scrate::storage::generator::StorageMap<#kty, #typ>>::key_for(&next); + let (val, linkage): (#typ, Linkage<#kty>) = self.storage.get(&*key_for) .expect("previous/next only contain existing entires; we enumerate using next; entry exists; qed"); self.next = linkage.next; Some((next, val)) } } - /// Generate a storage key for given item. - pub(crate) fn key_for(key: &Key) -> #scrate::rstd::vec::Vec { - let mut key_for = #prefix.as_bytes().to_vec(); - #scrate::codec::Encode::encode_to(&key, &mut key_for); - key_for - } - - pub(crate) trait Utils<#traitinstance: #traittype> { + pub(crate) trait Utils<#traitinstance: #traittype, #instance #bound_instantiable> { /// Update linkage when this element is removed. /// /// Takes care of updating previous and next elements points @@ -300,17 +361,18 @@ impl<'a> Impls<'a> { }; let structure = quote! { - #visibility struct #name<#traitinstance: #traittype>(#phantom_data<#traitinstance>); + #( #[ #attrs ] )* + #visibility struct #name<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance>(#phantom_data<(#traitinstance #comma_instance)>); - impl<#traitinstance: #traittype> self::#inner_module::Utils<#traitinstance> for #name<#traitinstance> { + impl<#traitinstance: #traittype, #instance #bound_instantiable> self::#inner_module::Utils<#traitinstance, #instance> for #name<#traitinstance, #instance> { fn remove_linkage( linkage: self::#inner_module::Linkage<#kty>, storage: &S, ) { - use self::#inner_module::{key_for, Utils}; + use self::#inner_module::Utils; - let next_key = linkage.next.as_ref().map(|x| key_for(x)); - let prev_key = linkage.previous.as_ref().map(|x| key_for(x)); + let next_key = linkage.next.as_ref().map(|x| #as_map::key_for(x)); + let prev_key = linkage.previous.as_ref().map(|x| #as_map::key_for(x)); if let Some(prev_key) = prev_key { // Retrieve previous element and update `next` @@ -343,12 +405,12 @@ impl<'a> Impls<'a> { storage: &S, key: &#kty, ) -> self::#inner_module::Linkage<#kty> { - use self::#inner_module::{key_for, Utils}; + use self::#inner_module::Utils; if let Some(head) = Self::read_head(storage) { // update previous head predecessor { - let head_key = key_for(&head); + let head_key = #as_map::key_for(&head); let (data, linkage) = Self::read_with_linkage(storage, &*head_key).expect(r#" head is set when first element is inserted and unset when last element is removed; if head is Some then it points to existing key; qed @@ -372,13 +434,13 @@ impl<'a> Impls<'a> { } fn read_head(storage: &S) -> Option<#kty> { - storage.get(#head_key.as_bytes()) + storage.get(#final_head_key) } fn write_head(storage: &S, head: Option<&#kty>) { match head { - Some(head) => storage.put(#head_key.as_bytes(), head), - None => storage.kill(#head_key.as_bytes()), + Some(head) => storage.put(#final_head_key, head), + None => storage.kill(#final_head_key), } } } @@ -389,17 +451,19 @@ impl<'a> Impls<'a> { #structure - impl<#traitinstance: #traittype> #scrate::storage::generator::StorageMap<#kty, #typ> for #name<#traitinstance> { + impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::storage::generator::StorageMap<#kty, #typ> for #name<#traitinstance, #instance> { type Query = #value_type; /// Get the prefix key in storage. fn prefix() -> &'static [u8] { - #prefix.as_bytes() + #final_prefix } /// Get the storage key used to fetch a value corresponding to a specific key. - fn key_for(x: &#kty) -> #scrate::rstd::vec::Vec { - self::#inner_module::key_for(x) + fn key_for(key: &#kty) -> #scrate::rstd::vec::Vec { + let mut key_for = #as_map::prefix().to_vec(); + #scrate::codec::Encode::encode_to(&key, &mut key_for); + key_for } /// Load the value associated with the given key from the map. @@ -409,9 +473,9 @@ impl<'a> Impls<'a> { /// Take the value, reading and removing it. fn take(key: &#kty, storage: &S) -> Self::Query { - use self::#inner_module::{Utils, key_for}; + use self::#inner_module::Utils; - let res: Option<(#value_type, self::#inner_module::Linkage<#kty>)> = storage.take(&*key_for(key)); + let res: Option<(#value_type, self::#inner_module::Linkage<#kty>)> = storage.take(&*#as_map::key_for(key)); match res { Some((data, linkage)) => { Self::remove_linkage(linkage, storage); @@ -428,9 +492,9 @@ impl<'a> Impls<'a> { /// Store a value to be associated with the given key from the map. fn insert(key: &#kty, val: &#typ, storage: &S) { - use self::#inner_module::{Utils, key_for}; + use self::#inner_module::Utils; - let key_for = &*key_for(key); + let key_for = &*#as_map::key_for(key); let linkage = match Self::read_with_linkage(storage, key_for) { // overwrite but reuse existing linkage Some((_data, linkage)) => linkage, @@ -442,9 +506,9 @@ impl<'a> Impls<'a> { /// Mutate the value under a key fn mutate R, S: #scrate::GenericStorage>(key: &#kty, f: F, storage: &S) -> R { - use self::#inner_module::{Utils, key_for}; + use self::#inner_module::Utils; - let key_for = &*key_for(key); + let key_for = &*#as_map::key_for(key); let (mut val, linkage) = Self::read_with_linkage(storage, key_for) .map(|(data, linkage)| (data, Some(linkage))) .unwrap_or_else(|| (#fielddefault, None)); @@ -455,7 +519,7 @@ impl<'a> Impls<'a> { } } - impl<#traitinstance: #traittype> #scrate::storage::generator::EnumerableStorageMap<#kty, #typ> for #name<#traitinstance> { + impl<#traitinstance: 'static + #traittype, #instance #bound_instantiable> #scrate::storage::generator::EnumerableStorageMap<#kty, #typ> for #name<#traitinstance, #instance> { fn head(storage: &S) -> Option<#kty> { use self::#inner_module::Utils; @@ -471,10 +535,99 @@ impl<'a> Impls<'a> { #scrate::storage::generator::Box::new(Enumerator { next: Self::read_head(storage), storage, - _data: #phantom_data::<#typ>::default(), + _data: #phantom_data::<(#typ, #traitinstance, #instance)>::default(), }) } } } } + + pub fn double_map(self, k1ty: &syn::Type, k2ty: &syn::Type, k2_hasher: TokenStream2) -> TokenStream2 { + let Self { + scrate, + visibility, + traitinstance, + traittype, + type_infos, + fielddefault, + prefix, + name, + attrs, + instance_opts, + .. + } = self; + + let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos; + let option_simple_1 = option_unwrap(is_option); + + let as_double_map = quote!{ > }; + + let mutate_impl = if !is_option { + quote!{ + #as_double_map::insert(key1, key2, &val, storage) + } + } else { + quote!{ + match val { + Some(ref val) => #as_double_map::insert(key1, key2, &val, storage), + None => #as_double_map::remove(key1, key2, storage), + } + } + }; + + let InstanceOpts { + comma_instance, + equal_default_instance, + bound_instantiable, + instance, + .. + } = 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()); + quote!{ #instance::#const_name.as_bytes() } + } else { + quote!{ #prefix.as_bytes() } + }; + + // generator for double map + quote!{ + #( #[ #attrs ] )* + #visibility struct #name<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance>(#scrate::storage::generator::PhantomData<(#traitinstance #comma_instance)>); + + impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::storage::unhashed::generator::StorageDoubleMap<#k1ty, #k2ty, #typ> for #name<#traitinstance, #instance> { + type Query = #value_type; + + fn prefix() -> &'static [u8] { + #final_prefix + } + + fn key_for(k1: &#k1ty, k2: &#k2ty) -> Vec { + let mut key = #as_double_map::prefix_for(k1); + key.extend(&#scrate::Hashable::#k2_hasher(k2)); + key + } + + fn get(key1: &#k1ty, key2: &#k2ty, storage: &S) -> Self::Query { + let key = #as_double_map::key_for(key1, key2); + storage.get(&key).#option_simple_1(|| #fielddefault) + } + + fn take(key1: &#k1ty, key2: &#k2ty, storage: &S) -> Self::Query { + let key = #as_double_map::key_for(key1, key2); + storage.take(&key).#option_simple_1(|| #fielddefault) + } + + fn mutate R, S: #scrate::GenericUnhashedStorage>(key1: &#k1ty, key2: &#k2ty, f: F, storage: &S) -> R { + let mut val = #as_double_map::get(key1, key2, storage); + + let ret = f(&mut val); + #mutate_impl ; + ret + } + + } + } + + } } diff --git a/srml/support/procedural/src/storage/mod.rs b/srml/support/procedural/src/storage/mod.rs index 37f2a2f3f10a9112082ddc4259cf054bfab87c10..82290e0de458fb8f658b96199787d5dd86b97b9f 100644 --- a/srml/support/procedural/src/storage/mod.rs +++ b/srml/support/procedural/src/storage/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -39,14 +39,20 @@ struct StorageDefinition { pub module_ident: Ident, pub mod_lt_token: Token![<], pub mod_param: syn::GenericParam, + pub mod_instance_param_token: Option, + pub mod_instance: Option, + pub mod_instantiable_token: Option, + pub mod_instantiable: Option, + pub mod_default_instance_token: Option, + pub mod_default_instance: Option, pub mod_gt_token: Token![>], pub as_token: Token![as], pub crate_ident: Ident, pub content: ext::Braces>, pub extra_genesis: Option, + pub extra_genesis_skip_phantom_data_field: Option, } - #[derive(Parse, ToTokens, Debug)] struct SpecificHiddenCrate { pub keyword: ext::CustomToken, @@ -59,6 +65,12 @@ struct AddExtraGenesis { pub content: ext::Braces, } +#[derive(Parse, ToTokens, Debug)] +struct ExtraGenesisSkipPhantomDataField { + pub genesis_phantom_keyword: ext::CustomToken, + pub token: Token![;], +} + #[derive(Parse, ToTokens, Debug)] struct AddExtraGenesisContent { pub lines: ext::Punctuated, @@ -119,6 +131,7 @@ struct DeclStorageBuild { enum DeclStorageType { Map(DeclStorageMap), LinkedMap(DeclStorageLinkedMap), + DoubleMap(DeclStorageDoubleMap), Simple(syn::Type), } @@ -138,6 +151,24 @@ struct DeclStorageLinkedMap { pub value: syn::Type, } +#[derive(Parse, ToTokens, Debug)] +struct DeclStorageDoubleMap { + pub map_keyword: ext::CustomToken, + pub key1: syn::Type, + pub comma_keyword: Token![,], + pub key2_hasher: DeclStorageDoubleMapHasher, + pub key2: ext::Parens, + pub ass_keyword: Token![=>], + pub value: syn::Type, +} + +#[derive(Parse, ToTokens, Debug)] +enum DeclStorageDoubleMapHasher { + Blake2_256(ext::CustomToken), + Twox256(ext::CustomToken), + Twox128(ext::CustomToken), +} + #[derive(Parse, ToTokens, Debug)] struct DeclStorageDefault { pub equal_token: Token![=], @@ -153,3 +184,8 @@ custom_keyword_impl!(AddExtraGenesis, "add_extra_genesis", "storage extra genesi custom_keyword_impl!(DeclStorageGetter, "get", "storage getter"); custom_keyword!(MapKeyword, "map", "map as keyword"); custom_keyword!(LinkedMapKeyword, "linked_map", "linked_map as keyword"); +custom_keyword!(DoubleMapKeyword, "double_map", "double_map as keyword"); +custom_keyword!(Blake2_256Keyword, "blake2_256", "Blake2_256 as keyword"); +custom_keyword!(Twox256Keyword, "twox_256", "Twox_256 as keyword"); +custom_keyword!(Twox128Keyword, "twox_128", "Twox_128 as keyword"); +custom_keyword_impl!(ExtraGenesisSkipPhantomDataField, "extra_genesis_skip_phantom_data_field", "extra_genesis_skip_phantom_data_field as keyword"); diff --git a/srml/support/procedural/src/storage/transformation.rs b/srml/support/procedural/src/storage/transformation.rs index f5eefb7844b5c97f6aedf680b05b411154a44d38..f00b5e8309bcc043b372296bc34e8d39b66e2ea7 100644 --- a/srml/support/procedural/src/storage/transformation.rs +++ b/srml/support/procedural/src/storage/transformation.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -38,6 +38,8 @@ use quote::quote; use super::*; +const NUMBER_OF_INSTANCE: usize = 16; + // try macro but returning tokenized error macro_rules! try_tok(( $expre : expr ) => { match $expre { @@ -57,11 +59,21 @@ pub fn decl_storage_impl(input: TokenStream) -> TokenStream { ident: storetype, module_ident, mod_param: strait, + mod_instance, + mod_instantiable, + mod_default_instance, crate_ident: cratename, content: ext::Braces { content: storage_lines, ..}, extra_genesis, + extra_genesis_skip_phantom_data_field, .. } = def; + + 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(), + }; + let hidden_crate_name = hidden_crate.map(|rc| rc.ident.content).map(|i| i.to_string()) .unwrap_or_else(|| "decl_storage".to_string()); let scrate = generate_crate_access(&hidden_crate_name, "srml-support"); @@ -89,13 +101,16 @@ pub fn decl_storage_impl(input: TokenStream) -> TokenStream { &scrate, &traitinstance, &traittype, + &instance_opts, &storage_lines, &extra_genesis, + extra_genesis_skip_phantom_data_field.is_some(), )); let decl_storage_items = decl_storage_items( &scrate, &traitinstance, &traittype, + &instance_opts, &cratename, &storage_lines, ); @@ -104,19 +119,29 @@ pub fn decl_storage_impl(input: TokenStream) -> TokenStream { ); let impl_store_items = impl_store_items( &traitinstance, + &instance_opts.instance, &storage_lines, ); let impl_store_fns = impl_store_fns( &scrate, &traitinstance, + &instance_opts.instance, &storage_lines, ); let (store_default_struct, store_functions_to_metadata) = store_functions_to_metadata( &scrate, &traitinstance, &traittype, + &instance_opts, &storage_lines, ); + + let InstanceOpts { + instance, + bound_instantiable, + .. + } = instance_opts; + let cratename_string = cratename.to_string(); let expanded = quote! { #scrate_decl @@ -125,23 +150,25 @@ pub fn decl_storage_impl(input: TokenStream) -> TokenStream { #decl_store_items } #store_default_struct - impl<#traitinstance: #traittype> #storetype for #module_ident<#traitinstance> { + impl<#traitinstance: #traittype, #instance #bound_instantiable> #storetype for #module_ident<#traitinstance, #instance> { #impl_store_items } - impl<#traitinstance: 'static + #traittype> #module_ident<#traitinstance> { + impl<#traitinstance: 'static + #traittype, #instance #bound_instantiable> #module_ident<#traitinstance, #instance> { #impl_store_fns + #[doc(hidden)] pub fn store_metadata() -> #scrate::storage::generator::StorageMetadata { #scrate::storage::generator::StorageMetadata { functions: #scrate::storage::generator::DecodeDifferent::Encode(#store_functions_to_metadata) , } } + #[doc(hidden)] pub fn store_metadata_functions() -> &'static [#scrate::storage::generator::StorageFunctionMetadata] { #store_functions_to_metadata } + #[doc(hidden)] pub fn store_metadata_name() -> &'static str { #cratename_string } - } #extra_genesis @@ -155,10 +182,20 @@ fn decl_store_extra_genesis( scrate: &TokenStream2, traitinstance: &Ident, traittype: &syn::TypeParamBound, + instance_opts: &InstanceOpts, storage_lines: &ext::Punctuated, extra_genesis: &Option, + extra_genesis_skip_phantom_data_field: bool, ) -> Result { + let InstanceOpts { + comma_instance, + equal_default_instance, + bound_instantiable, + instance, + .. + } = instance_opts; + let mut is_trait_needed = false; let mut has_trait_field = false; let mut serde_complete_bound = std::collections::HashSet::new(); @@ -168,6 +205,7 @@ fn decl_store_extra_genesis( for sline in storage_lines.inner.iter() { let DeclStorageLine { + attrs, name, getter, config, @@ -181,12 +219,20 @@ fn decl_store_extra_genesis( let mut opt_build; // need build line - if let (Some(ref getter), Some(ref config)) = (getter, config) { + if let Some(ref config) = config { let ident = if let Some(ident) = config.expr.content.as_ref() { quote!( #ident ) - } else { + } else if let Some(ref getter) = getter { let ident = &getter.getfn.content; quote!( #ident ) + } else { + return Err( + Error::new_spanned( + name, + "Invalid storage definiton, couldn't find config identifier: storage must either have a get identifier \ + `get(ident)` or a defined config identifier `config(ident)`" + ) + ); }; if type_infos.kind.is_simple() && ext::has_parametric_type(type_infos.value_type, traitinstance) { is_trait_needed = true; @@ -197,17 +243,24 @@ fn decl_store_extra_genesis( if let DeclStorageTypeInfosKind::Map { key_type, .. } = type_infos.kind { serde_complete_bound.insert(key_type); } + + // Propagate doc attributes. + let attrs = attrs.inner.iter().filter_map(|a| a.parse_meta().ok()).filter(|m| m.name() == "doc"); + let storage_type = type_infos.typ.clone(); config_field.extend(match type_infos.kind { DeclStorageTypeInfosKind::Simple => { - quote!( pub #ident: #storage_type, ) + quote!( #( #[ #attrs ] )* pub #ident: #storage_type, ) }, DeclStorageTypeInfosKind::Map {key_type, .. } => { - quote!( pub #ident: Vec<(#key_type, #storage_type)>, ) + quote!( #( #[ #attrs ] )* pub #ident: Vec<(#key_type, #storage_type)>, ) + }, + DeclStorageTypeInfosKind::DoubleMap {key1_type, key2_type, .. } => { + quote!( #( #[ #attrs ] )* pub #ident: Vec<(#key1_type, #key2_type, #storage_type)>, ) }, }); opt_build = Some(build.as_ref().map(|b| &b.expr.content).map(|b|quote!( #b )) - .unwrap_or_else(|| quote!( (|config: &GenesisConfig<#traitinstance>| config.#ident.clone()) ))); + .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 { @@ -224,22 +277,14 @@ fn decl_store_extra_genesis( let typ = type_infos.typ; if let Some(builder) = opt_build { is_trait_needed = true; - let error_message = format!( - "Genesis parameters encoding of {} does not match the expected type ({:?}).", - name, - type_infos.value_type, - ); builders.extend(match type_infos.kind { DeclStorageTypeInfosKind::Simple => { quote!{{ use #scrate::rstd::{cell::RefCell, marker::PhantomData}; use #scrate::codec::{Encode, Decode}; - let storage = (RefCell::new(&mut r), PhantomData::::default()); let v = (#builder)(&self); - let v = Encode::using_encoded(&v, |mut v| Decode::decode(&mut v)) - .expect(#error_message); - <#name<#traitinstance> as #scrate::storage::generator::StorageValue<#typ>>::put(&v, &storage); + <#name<#traitinstance, #instance> as #scrate::storage::generator::StorageValue<#typ>>::put(&v, &storage); }} }, DeclStorageTypeInfosKind::Map { key_type, .. } => { @@ -247,12 +292,20 @@ fn decl_store_extra_genesis( use #scrate::rstd::{cell::RefCell, marker::PhantomData}; use #scrate::codec::{Encode, Decode}; - let storage = (RefCell::new(&mut r), PhantomData::::default()); let data = (#builder)(&self); for (k, v) in data.into_iter() { - let v = Encode::using_encoded(&v, |mut v| Decode::decode(&mut v)) - .expect(#error_message); - <#name<#traitinstance> as #scrate::storage::generator::StorageMap<#key_type, #typ>>::insert(&k, &v, &storage); + <#name<#traitinstance, #instance> as #scrate::storage::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 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); } }} }, @@ -330,24 +383,26 @@ fn decl_store_extra_genesis( || !genesis_extrafields.is_empty() || !builders.is_empty(); Ok(if is_extra_genesis_needed { - let (fparam, sparam, ph_field, ph_default) = if is_trait_needed { - if has_trait_field { + 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>), - quote!(<#traitinstance>), + 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>), - quote!(<#traitinstance>), + quote!(<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance>), + quote!(<#traitinstance: #traittype, #instance #bound_instantiable>), + quote!(<#traitinstance, #instance>), quote!{ #[serde(skip)] - pub _genesis_phantom_data: #scrate::storage::generator::PhantomData<#traitinstance>, + pub _genesis_phantom_data: #scrate::storage::generator::PhantomData<(#traitinstance #comma_instance)>, }, quote!{ _genesis_phantom_data: Default::default(), @@ -356,7 +411,7 @@ fn decl_store_extra_genesis( } } else { // do not even need type parameter - (quote!(), quote!(), quote!(), quote!()) + (quote!(), quote!(), quote!(), quote!(), quote!()) }; quote!{ @@ -365,14 +420,14 @@ fn decl_store_extra_genesis( #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] #serde_bug_bound - pub struct GenesisConfig#fparam { + pub struct GenesisConfig#fparam_struct { #ph_field #config_field #genesis_extrafields } #[cfg(feature = "std")] - impl#fparam Default for GenesisConfig#sparam { + impl#fparam_impl Default for GenesisConfig#sparam { fn default() -> Self { GenesisConfig { #ph_default @@ -383,17 +438,18 @@ fn decl_store_extra_genesis( } #[cfg(feature = "std")] - impl#fparam #scrate::runtime_primitives::BuildStorage for GenesisConfig#sparam { - - fn build_storage(self) -> ::std::result::Result<(#scrate::runtime_primitives::StorageOverlay, #scrate::runtime_primitives::ChildrenStorageOverlay), String> { - let mut r: #scrate::runtime_primitives::StorageOverlay = Default::default(); - let mut c: #scrate::runtime_primitives::ChildrenStorageOverlay = Default::default(); + 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> { + use #scrate::rstd::{cell::RefCell, marker::PhantomData}; + let storage = (RefCell::new(r), PhantomData::::default()); #builders - #scall(&mut r, &mut c, &self); + let r = storage.0.into_inner(); + + #scall(r, c, &self); - Ok((r, c)) + Ok(()) } } } @@ -406,13 +462,102 @@ fn decl_storage_items( scrate: &TokenStream2, traitinstance: &Ident, traittype: &syn::TypeParamBound, + instance_opts: &InstanceOpts, cratename: &Ident, storage_lines: &ext::Punctuated, ) -> TokenStream2 { let mut impls = TokenStream2::new(); + + let InstanceOpts { + instance, + default_instance, + instantiable, + .. + } = instance_opts; + + let build_prefix = |cratename, name| format!("{} {}", cratename, name); + + // Build Instantiable trait + if instance.is_some() { + let mut const_names = vec![]; + + for sline in storage_lines.inner.iter() { + let DeclStorageLine { + storage_type, + name, + .. + } = sline; + + let prefix = build_prefix(cratename, name); + + 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)); + + 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; + }); + } + + 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 + } + }); + } + + let instances = (0..NUMBER_OF_INSTANCE) + .map(|i| { + let name = format!("Instance{}", i); + let ident = syn::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"]}))); + + // Impl Instance trait for instances + for (prefix, ident, doc) in instances { + 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; + }); + } + + 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 + } + }); + } + } + for sline in storage_lines.inner.iter() { let DeclStorageLine { + attrs, name, storage_type, default_value, @@ -422,16 +567,22 @@ fn decl_storage_items( let type_infos = get_type_infos(storage_type); let kind = type_infos.kind.clone(); + // Propagate doc attributes. + let attrs = attrs.inner.iter().filter_map(|a| a.parse_meta().ok()).filter(|m| m.name() == "doc"); + let i = impls::Impls { scrate, visibility, + cratename, traitinstance, traittype, + instance_opts, type_infos, fielddefault: default_value.inner.as_ref().map(|d| &d.expr).map(|d| quote!( #d )) .unwrap_or_else(|| quote!{ Default::default() }), - prefix: format!("{} {}", cratename, name), + prefix: build_prefix(cratename, name), name, + attrs, }; let implementation = match kind { @@ -444,6 +595,9 @@ fn decl_storage_items( DeclStorageTypeInfosKind::Map { key_type, is_linked: true } => { i.linked_map(key_type) }, + DeclStorageTypeInfosKind::DoubleMap { key1_type, key2_type, key2_hasher } => { + i.double_map(key1_type, key2_type, key2_hasher) + }, }; impls.extend(implementation) } @@ -463,23 +617,30 @@ fn decl_store_items( fn impl_store_items( traitinstance: &Ident, + instance: &Option, storage_lines: &ext::Punctuated, ) -> TokenStream2 { storage_lines.inner.iter().map(|sline| &sline.name) .fold(TokenStream2::new(), |mut items, name| { - items.extend(quote!(type #name = #name<#traitinstance>;)); - items + items.extend( + quote!( + type #name = #name<#traitinstance, #instance>; + ) + ); + items }) } fn impl_store_fns( scrate: &TokenStream2, traitinstance: &Ident, + instance: &Option, storage_lines: &ext::Punctuated, ) -> TokenStream2 { let mut items = TokenStream2::new(); for sline in storage_lines.inner.iter() { let DeclStorageLine { + attrs, name, getter, storage_type, @@ -492,19 +653,35 @@ fn impl_store_fns( let type_infos = get_type_infos(storage_type); let value_type = type_infos.value_type; + // Propagate doc attributes. + let attrs = attrs.inner.iter().filter_map(|a| a.parse_meta().ok()).filter(|m| m.name() == "doc"); + let typ = type_infos.typ; let item = match type_infos.kind { DeclStorageTypeInfosKind::Simple => { quote!{ + #( #[ #attrs ] )* pub fn #get_fn() -> #value_type { - <#name<#traitinstance> as #scrate::storage::generator::StorageValue<#typ>> :: get(&#scrate::storage::RuntimeStorage) + <#name<#traitinstance, #instance> as #scrate::storage::generator::StorageValue<#typ>> :: get(&#scrate::storage::RuntimeStorage) } } }, DeclStorageTypeInfosKind::Map { key_type, .. } => { quote!{ + #( #[ #attrs ] )* pub fn #get_fn>(key: K) -> #value_type { - <#name<#traitinstance> as #scrate::storage::generator::StorageMap<#key_type, #typ>> :: get(key.borrow(), &#scrate::storage::RuntimeStorage) + <#name<#traitinstance, #instance> as #scrate::storage::generator::StorageMap<#key_type, #typ>> :: get(key.borrow(), &#scrate::storage::RuntimeStorage) + } + } + } + DeclStorageTypeInfosKind::DoubleMap { key1_type, key2_type, .. } => { + quote!{ + pub fn #get_fn(k1: KArg1, k2: KArg2) -> #value_type + where + KArg1: #scrate::storage::generator::Borrow<#key1_type>, + KArg2: #scrate::storage::generator::Borrow<#key2_type>, + { + <#name<#traitinstance> as #scrate::storage::unhashed::generator::StorageDoubleMap<#key1_type, #key2_type, #typ>> :: get(k1.borrow(), k2.borrow(), &#scrate::storage::RuntimeStorage) } } } @@ -519,9 +696,18 @@ fn store_functions_to_metadata ( scrate: &TokenStream2, traitinstance: &Ident, traittype: &syn::TypeParamBound, + instance_opts: &InstanceOpts, storage_lines: &ext::Punctuated, ) -> (TokenStream2, TokenStream2) { + let InstanceOpts { + comma_instance, + equal_default_instance, + bound_instantiable, + instance, + .. + } = instance_opts; + let mut items = TokenStream2::new(); let mut default_getter_struct_def = TokenStream2::new(); for sline in storage_lines.inner.iter() { @@ -546,12 +732,26 @@ fn store_functions_to_metadata ( ) } }, - DeclStorageTypeInfosKind::Map { key_type, .. } => { + DeclStorageTypeInfosKind::Map { key_type, is_linked } => { let kty = clean_type_string("e!(#key_type).to_string()); quote!{ #scrate::storage::generator::StorageFunctionType::Map { key: #scrate::storage::generator::DecodeDifferent::Encode(#kty), value: #scrate::storage::generator::DecodeDifferent::Encode(#styp), + is_linked: #is_linked, + } + } + }, + DeclStorageTypeInfosKind::DoubleMap { key1_type, key2_type, key2_hasher } => { + let k1ty = clean_type_string("e!(#key1_type).to_string()); + let k2ty = clean_type_string("e!(#key2_type).to_string()); + let k2_hasher = clean_type_string(&key2_hasher.to_string()); + quote!{ + #scrate::storage::generator::StorageFunctionType::DoubleMap { + key1: #scrate::storage::generator::DecodeDifferent::Encode(#k1ty), + key2: #scrate::storage::generator::DecodeDifferent::Encode(#k2ty), + value: #scrate::storage::generator::DecodeDifferent::Encode(#styp), + key2_hasher: #scrate::storage::generator::DecodeDifferent::Encode(#k2_hasher), } } }, @@ -571,7 +771,7 @@ fn store_functions_to_metadata ( }) .unwrap_or_else(|| quote!( Default::default() )); let mut docs = TokenStream2::new(); - for attr in attrs.inner.iter().filter_map(|v| v.interpret_meta()) { + for attr in attrs.inner.iter().filter_map(|v| v.parse_meta().ok()) { if let syn::Meta::NameValue(syn::MetaNameValue{ ref ident, ref lit, @@ -592,7 +792,7 @@ fn store_functions_to_metadata ( ty: #stype, default: #scrate::storage::generator::DecodeDifferent::Encode( #scrate::storage::generator::DefaultByteGetter( - &#struct_name::<#traitinstance>(#scrate::rstd::marker::PhantomData) + &#struct_name::<#traitinstance, #instance>(#scrate::rstd::marker::PhantomData) ) ), documentation: #scrate::storage::generator::DecodeDifferent::Encode(&[ #docs ]), @@ -600,12 +800,13 @@ fn store_functions_to_metadata ( }; items.extend(item); let def_get = quote! { - pub struct #struct_name<#traitinstance>(pub #scrate::rstd::marker::PhantomData<#traitinstance>); + #[doc(hidden)] + 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> #scrate::storage::generator::DefaultByte for #struct_name<#traitinstance> { + impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::storage::generator::DefaultByte for #struct_name<#traitinstance, #instance> { fn default_byte(&self) -> #scrate::rstd::vec::Vec { use #scrate::codec::Encode; #cache_name.get_or_init(|| { @@ -615,7 +816,7 @@ fn store_functions_to_metadata ( } } #[cfg(not(feature = "std"))] - impl<#traitinstance: #traittype> #scrate::storage::generator::DefaultByte for #struct_name<#traitinstance> { + impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::storage::generator::DefaultByte for #struct_name<#traitinstance, #instance> { fn default_byte(&self) -> #scrate::rstd::vec::Vec { use #scrate::codec::Encode; let def_val: #value_type = #default; @@ -650,6 +851,11 @@ enum DeclStorageTypeInfosKind<'a> { key_type: &'a syn::Type, is_linked: bool, }, + DoubleMap { + key1_type: &'a syn::Type, + key2_type: &'a syn::Type, + key2_hasher: TokenStream2, + } } impl<'a> DeclStorageTypeInfosKind<'a> { @@ -672,6 +878,11 @@ fn get_type_infos(storage_type: &DeclStorageType) -> DeclStorageTypeInfos { key_type: &map.key, is_linked: true, }), + DeclStorageType::DoubleMap(ref map) => (&map.value, DeclStorageTypeInfosKind::DoubleMap { + key1_type: &map.key1, + key2_type: &map.key2.content, + key2_hasher: { let h = &map.key2_hasher; quote! { #h } }, + }), }; let extracted_type = ext::extract_type_option(value_type); @@ -686,3 +897,44 @@ 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 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 { + + 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)) + } else { + (quote!{}, None) + }; + Ok(InstanceOpts { + comma_instance: quote!{, #instance}, + equal_default_instance, + bound_instantiable: quote!{: #instantiable}, + instance: Some(instance), + default_instance, + instantiable: Some(instantiable), + }) + }, + (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))), + } +} diff --git a/srml/support/procedural/tools/derive/src/lib.rs b/srml/support/procedural/tools/derive/src/lib.rs index fdaee5dceed40e7bfda233da6b10d975e8161461..0e3fcb22475fc2e9babeeb3a3c7268c4a16ab018 100644 --- a/srml/support/procedural/tools/derive/src/lib.rs +++ b/srml/support/procedural/tools/derive/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/srml/support/procedural/tools/src/lib.rs b/srml/support/procedural/tools/src/lib.rs index 8d0e1ae600905fe53b28f315416727d31039f077..34b96df8104b50e33656a3636cb55530d9f84963 100644 --- a/srml/support/procedural/tools/src/lib.rs +++ b/srml/support/procedural/tools/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -66,7 +66,7 @@ pub fn generate_crate_access(unique_id: &str, def_crate: &str) -> TokenStream { } else { let mod_name = generate_hidden_includes_mod_name(unique_id); quote::quote!( self::#mod_name::hidden_include ) - }.into() + } } /// Generates the hidden includes that are required to make the macro independent from its scope. @@ -92,7 +92,7 @@ pub fn generate_hidden_includes(unique_id: &str, def_crate: &str) -> TokenStream } } - }.into() + } } // fn to remove white spaces arount string types diff --git a/srml/support/procedural/tools/src/syn_ext.rs b/srml/support/procedural/tools/src/syn_ext.rs index 74233b2d0ba64253988d97f64b7d7f13dd48f5e7..c2136b2cd8f96599d09f8ce4ff34d5c6a2349142 100644 --- a/srml/support/procedural/tools/src/syn_ext.rs +++ b/srml/support/procedural/tools/src/syn_ext.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/srml/support/src/dispatch.rs b/srml/support/src/dispatch.rs index 8e5cc44092b35232fdaffab71aa2e9d74bc23f6e..c85415b25cf6431c40b4bcbccbeb20bcebae2577 100644 --- a/srml/support/src/dispatch.rs +++ b/srml/support/src/dispatch.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -27,7 +27,10 @@ pub use srml_metadata::{ FunctionArgumentMetadata, OuterDispatchMetadata, OuterDispatchCall }; -/// Result of a module function call; either nothing (functions are only called for "side efeects") +/// A type that can not be instantiated. +pub enum Never {} + +/// Result of a module function call; either nothing (functions are only called for "side effects") /// or an error message. pub type Result = result::Result<(), &'static str>; @@ -88,42 +91,52 @@ impl Parameter for T where T: Codec + Clone + Eq {} /// /// The `on_initialise` and `on_finalise` functions are special, since it can either take no /// parameters, or one parameter, which has the runtime's block number type. +/// +/// ### Module with instances +/// +/// decl_module! support modules with instances with the following syntax: (DefaultInstance type is +/// optionnal) +/// ```nocompile +/// pub struct Module, I: Instance = DefaultInstance> for enum Call where origin: T::Origin {} +/// ``` #[macro_export] macro_rules! decl_module { // Macro transformations (to convert invocations with incomplete parameters to the canonical // form) ( $(#[$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 { $($t:tt)* } ) => { - decl_module!(@normalize + $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 {} {} {} + {} [] $($t)* ); }; ( $(#[$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 { $($t:tt)* } ) => { - decl_module!(@normalize + $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 {} {} {} + {} [] $($t)* ); @@ -131,94 +144,102 @@ 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 {} { $( $on_initialise:tt )* } { $( $on_finalise:tt )* } + { $( $offchain:tt )* } [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* - $vis:vis fn deposit_event $(<$dpeg:ident>)* () = default; + $vis:vis fn deposit_event $(<$dpeg:ident $(, $dpeg_instance:ident)?>)* () = default; $($rest:tt)* ) => { - decl_module!(@normalize + $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 - { $vis fn deposit_event $(<$dpeg>)* () = default; } + { $vis fn deposit_event $(<$dpeg $(, $dpeg_instance)?>)* () = default; } { $( $on_initialise )* } { $( $on_finalise )* } + { $( $offchain )* } [ $($t)* ] $($rest)* ); }; (@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 {} { $( $on_initialise:tt )* } { $( $on_finalise:tt )* } + { $( $offchain:tt )* } [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* - $vis:vis fn deposit_event $(<$dpeg:ident>)* ( + $vis:vis fn deposit_event $(<$dpeg:ident $(, $dpeg_instance:ident)?>)* ( $($param_name:ident : $param:ty),* ) { $( $impl:tt )* } $($rest:tt)* ) => { - decl_module!(@normalize + $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 - { $vis fn deposit_event $(<$dpeg>)* ($( $param_name: $param ),* ) { $( $impl )* } } + { $vis fn deposit_event $(<$dpeg $(, $dpeg_instance)?>)* ($( $param_name: $param ),* ) { $( $impl )* } } { $( $on_initialise )* } { $( $on_finalise )* } + { $( $offchain )* } [ $($t)* ] $($rest)* ); }; (@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 { $( $deposit_event:tt )* } { $( $on_initialise:tt )* } {} + { $( $offchain:tt )* } [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* fn on_finalise($($param_name:ident : $param:ty),* ) { $( $impl:tt )* } $($rest:tt)* ) => { - decl_module!(@normalize + $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 { $( $deposit_event )* } { $( $on_initialise )* } { fn on_finalise( $( $param_name : $param ),* ) { $( $impl )* } } + { $( $offchain )* } [ $($t)* ] $($rest)* ); }; (@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 { $( $deposit_event:tt )* } {} { $( $on_finalise:tt )* } + { $( $offchain:tt )* } [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* fn on_initialise($($param_name:ident : $param:ty),* ) { $( $impl:tt )* } $($rest:tt)* ) => { - decl_module!(@normalize + $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 { $( $deposit_event )* } { fn on_initialise( $( $param_name : $param ),* ) { $( $impl )* } } { $( $on_finalise )* } + { $( $offchain )* } [ $($t)* ] $($rest)* ); @@ -230,6 +251,32 @@ macro_rules! decl_module { { $( $deposit_event:tt )* } { $( $on_initialise:tt )* } { $( $on_finalise:tt )* } + { } + [ $($t:tt)* ] + $(#[doc = $doc_attr:tt])* + fn offchain_worker($($param_name:ident : $param:ty),* ) { $( $impl:tt )* } + $($rest:tt)* + ) => { + decl_module!(@normalize + $(#[$attr])* + pub struct $mod_type<$trait_instance: $trait_name> + for enum $call_type where origin: $origin_type, system = $system + { $( $deposit_event )* } + { $( $on_initialise )* } + { $( $on_finalise )* } + { fn offchain_worker( $( $param_name : $param ),* ) { $( $impl )* } } + [ $($t)* ] + $($rest)* + ); + }; + (@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 + { $( $deposit_event:tt )* } + { $( $on_initialise:tt )* } + { $( $on_finalise:tt )* } + { $( $offchain:tt )* } [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* $fn_vis:vis fn $fn_name:ident( @@ -237,30 +284,33 @@ macro_rules! decl_module { ) $( -> $result:ty )* { $( $impl:tt )* } $($rest:tt)* ) => { - decl_module!(@normalize + $crate::decl_module!(@normalize $(#[$attr])* - pub struct $mod_type<$trait_instance: $trait_name> + 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_initialise )* } { $( $on_finalise )* } + { $( $offchain )* } [ $($t)* $(#[doc = $doc_attr])* $fn_vis fn $fn_name( $origin $( , $(#[$codec_attr])* $param_name : $param )* ) $( -> $result )* { $( $impl )* } + { $($instance: $instantiable)? } ] $($rest)* ); }; (@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 { $( $deposit_event:tt )* } { $( $on_initialise:tt )* } { $( $on_finalise:tt )* } + { $( $offchain:tt )* } [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* $fn_vis:vis fn $fn_name:ident( @@ -276,11 +326,12 @@ 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 { $( $deposit_event:tt )* } { $( $on_initialise:tt )* } { $( $on_finalise:tt )* } + { $( $offchain:tt )* } [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* $fn_vis:vis fn $fn_name:ident( @@ -296,11 +347,12 @@ 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$(, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident { $( $deposit_event:tt )* } { $( $on_initialise:tt )* } { $( $on_finalise:tt )* } + { $( $offchain:tt )* } [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* $fn_vis:vis fn $fn_name:ident( @@ -308,41 +360,45 @@ macro_rules! decl_module { ) $( -> $result:ty )* { $( $impl:tt )* } $($rest:tt)* ) => { - decl_module!(@normalize + $crate::decl_module!(@normalize $(#[$attr])* - pub struct $mod_type<$trait_instance: $trait_name> + 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_initialise )* } { $( $on_finalise )* } + { $( $offchain )* } [ $($t)* $(#[doc = $doc_attr])* $fn_vis fn $fn_name( root $( , $(#[$codec_attr])* $param_name : $param )* ) $( -> $result )* { $( $impl )* } + { $($instance: $instantiable)? } ] $($rest)* ); }; (@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 { $( $deposit_event:tt )* } { $( $on_initialise:tt )* } { $( $on_finalise:tt )* } + { $( $offchain:tt )* } [ $($t:tt)* ] ) => { - decl_module!(@imp + $crate::decl_module!(@imp $(#[$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 { $($t)* } { $( $deposit_event )* } { $( $on_initialise )* } { $( $on_finalise )* } + { $( $offchain )* } ); }; @@ -351,62 +407,46 @@ macro_rules! decl_module { (@call root - $mod_type:ident $trait_instance:ident $fn_name:ident $origin:ident $system:ident [ $( $param_name:ident),* ] + $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>>::$fn_name( $( $param_name ),* ) + <$mod_type<$trait_instance $(, $instance)?>>::$fn_name( $( $param_name ),* ) } }; (@call $ingore:ident - $mod_type:ident $trait_instance:ident $fn_name:ident $origin:ident $system:ident [ $( $param_name:ident),* ] + $mod_type:ident<$trait_instance:ident $(, $instance:ident)?> $fn_name:ident $origin:ident $system:ident [ $( $param_name:ident),* ] ) => { - <$mod_type<$trait_instance>>::$fn_name( $origin $(, $param_name )* ) + <$mod_type<$trait_instance $(, $instance)?>>::$fn_name( $origin $(, $param_name )* ) }; // no `deposit_event` function wanted (@impl_deposit_event - $module:ident<$trait_instance:ident: $trait_name:ident>; + $module:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path)?>; $system:ident; ) => {}; - // Non-generic event (@impl_deposit_event - $module:ident<$trait_instance:ident: $trait_name:ident>; + $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; $system:ident; - $vis:vis fn deposit_event() = default; + $vis:vis fn deposit_event$(<$event_trait_instance:ident $(, $event_instance:ident)?>)?() = default; ) => { - impl<$trait_instance: $trait_name> $module<$trait_instance> { - $vis fn deposit_event(event: Event) { + impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $module<$trait_instance $(, $instance)?> { + $vis fn deposit_event(event: Event$(<$event_trait_instance $(, $event_instance)?>)?) { <$system::Module<$trait_instance>>::deposit_event( - <$trait_instance as $trait_name>::Event::from(event).into() + <$trait_instance as $trait_name$(<$instance>)?>::Event::from(event).into() ); } } }; - // Generic event (@impl_deposit_event - $module:ident<$trait_instance:ident: $trait_name:ident>; - $system:ident; - $vis:vis fn deposit_event<$ignore:ident>() = default; - ) => { - impl<$trait_instance: $trait_name> $module<$trait_instance> { - $vis fn deposit_event(event: Event<$trait_instance>) { - <$system::Module<$trait_instance>>::deposit_event( - <$trait_instance as $trait_name>::Event::from(event).into() - ); - } - } - }; - - (@impl_deposit_event - $module:ident<$trait_instance:ident: $trait_name:ident>; + $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; $system:ident; $vis:vis fn deposit_event($param:ident : $param_ty:ty) { $( $impl:tt )* } ) => { - impl<$trait_instance: $trait_name> $module<$trait_instance> { + impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $module<$trait_instance $(, $instance)?> { $vis fn deposit_event($param: $param_ty) { $( $impl )* } @@ -414,131 +454,164 @@ macro_rules! decl_module { }; (@impl_on_initialise - $module:ident<$trait_instance:ident: $trait_name:ident>; + $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; fn on_initialise() { $( $impl:tt )* } ) => { - impl<$trait_instance: $trait_name> + impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OnInitialise<$trait_instance::BlockNumber> - for $module<$trait_instance> + for $module<$trait_instance$(, $instance)?> { fn on_initialise(_block_number_not_used: $trait_instance::BlockNumber) { $( $impl )* } } }; (@impl_on_initialise - $module:ident<$trait_instance:ident: $trait_name:ident>; + $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; fn on_initialise($param:ident : $param_ty:ty) { $( $impl:tt )* } ) => { - impl<$trait_instance: $trait_name> + impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OnInitialise<$trait_instance::BlockNumber> - for $module<$trait_instance> + for $module<$trait_instance$(, $instance)?> { fn on_initialise($param: $param_ty) { $( $impl )* } } }; (@impl_on_initialise - $module:ident<$trait_instance:ident: $trait_name:ident>; + $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; ) => { - impl<$trait_instance: $trait_name> + impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OnInitialise<$trait_instance::BlockNumber> - for $module<$trait_instance> + for $module<$trait_instance$(, $instance)?> {} }; (@impl_on_finalise - $module:ident<$trait_instance:ident: $trait_name:ident>; + $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; fn on_finalise() { $( $impl:tt )* } ) => { - impl<$trait_instance: $trait_name> + impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OnFinalise<$trait_instance::BlockNumber> - for $module<$trait_instance> + for $module<$trait_instance$(, $instance)?> { fn on_finalise(_block_number_not_used: $trait_instance::BlockNumber) { $( $impl )* } } }; (@impl_on_finalise - $module:ident<$trait_instance:ident: $trait_name:ident>; + $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; fn on_finalise($param:ident : $param_ty:ty) { $( $impl:tt )* } ) => { - impl<$trait_instance: $trait_name> + impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OnFinalise<$trait_instance::BlockNumber> - for $module<$trait_instance> + for $module<$trait_instance$(, $instance)?> { fn on_finalise($param: $param_ty) { $( $impl )* } } }; (@impl_on_finalise - $module:ident<$trait_instance:ident: $trait_name:ident>; + $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; ) => { - impl<$trait_instance: $trait_name> + impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OnFinalise<$trait_instance::BlockNumber> - for $module<$trait_instance> + for $module<$trait_instance$(, $instance)?> + { + } + }; + + (@impl_offchain + $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; + 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)?> { + fn generate_extrinsics(_block_number_not_used: $trait_instance::BlockNumber) { $( $impl )* } } }; + (@impl_offchain + $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; + 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)?> + { + fn generate_extrinsics($param: $param_ty) { $( $impl )* } + } + }; + + (@impl_offchain + $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; + ) => { + impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> + $crate::runtime_primitives::traits::OffchainWorker<$trait_instance::BlockNumber> + for $module<$trait_instance$(, $instance)?> + {} + }; + (@impl_function - $module:ident<$trait_instance:ident: $trait_name:ident>; + $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 )* } ) => { - impl<$trait_instance: $trait_name> $module<$trait_instance> { - $vis fn $name($( $param: $param_ty ),* ) -> $crate::dispatch::Result { - { $( $impl )* } - Ok(()) - } + $(#[doc = $doc_attr])* + $vis fn $name($( $param: $param_ty ),* ) -> $crate::dispatch::Result { + { $( $impl )* } + Ok(()) } }; (@impl_function - $module:ident<$trait_instance:ident: $trait_name:ident>; + $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 )* } ) => { - impl<$trait_instance: $trait_name> $module<$trait_instance> { - $vis fn $name($( $param: $param_ty ),* ) -> $result { - $( $impl )* - } + $(#[doc = $doc_attr])* + $vis fn $name($( $param: $param_ty ),* ) -> $result { + $( $impl )* } }; (@impl_function - $module:ident<$trait_instance:ident: $trait_name:ident>; + $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; $origin_ty:ty; $ignore:ident; + $(#[doc = $doc_attr:tt])* $vis:vis fn $name:ident ( $origin:ident $(, $param:ident : $param_ty:ty )* ) { $( $impl:tt )* } ) => { - impl<$trait_instance: $trait_name> $module<$trait_instance> { - $vis fn $name( - $origin: $origin_ty $(, $param: $param_ty )* - ) -> $crate::dispatch::Result { - { $( $impl )* } - Ok(()) - } + $(#[doc = $doc_attr])* + $vis fn $name( + $origin: $origin_ty $(, $param: $param_ty )* + ) -> $crate::dispatch::Result { + { $( $impl )* } + Ok(()) } }; (@impl_function - $module:ident<$trait_instance:ident: $trait_name:ident>; + $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; $origin_ty:ty; $ignore:ident; + $(#[doc = $doc_attr:tt])* $vis:vis fn $name:ident ( $origin:ident $(, $param:ident : $param_ty:ty )* ) -> $result:ty { $( $impl:tt )* } ) => { - impl<$trait_instance: $trait_name> $module<$trait_instance> { - $vis fn $name($origin: $origin_ty $(, $param: $param_ty )* ) -> $result { - $( $impl )* - } + $(#[doc = $doc_attr])* + $vis fn $name($origin: $origin_ty $(, $param: $param_ty )* ) -> $result { + $( $impl )* } }; @@ -546,18 +619,20 @@ macro_rules! decl_module { (@imp $(#[$attr:meta])* - pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident> + 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 { $( $(#[doc = $doc_attr:tt])* $fn_vis:vis fn $fn_name:ident( $from:ident $( , $(#[$codec_attr:ident])* $param_name:ident : $param:ty)* ) $( -> $result:ty )* { $( $impl:tt )* } + { $($fn_instance:ident: $fn_instantiable:path)? } )* } { $( $deposit_event:tt )* } { $( $on_initialise:tt )* } { $( $on_finalise:tt )* } + { $( $offchain:tt )* } ) => { // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, Copy, PartialEq, Eq)] @@ -566,71 +641,85 @@ macro_rules! decl_module { // serde-derive for when we attempt to derive `Deserialize` on these types, // in a situation where we've imported `srml_support` as another name. #[cfg(feature = "std")] - pub struct $mod_type<$trait_instance: $trait_name>(::std::marker::PhantomData<$trait_instance>); + pub struct $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable $( = $module_default_instance)?)?>(::std::marker::PhantomData<($trait_instance $(, $instance)?)>); // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Debug))] #[cfg(not(feature = "std"))] - pub struct $mod_type<$trait_instance: $trait_name>(::core::marker::PhantomData<$trait_instance>); + pub struct $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable $( = $module_default_instance)?)?>(::core::marker::PhantomData<($trait_instance $(, $instance)?)>); - decl_module! { + $crate::decl_module! { @impl_on_initialise - $mod_type<$trait_instance: $trait_name>; + $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?>; $( $on_initialise )* } - decl_module! { + $crate::decl_module! { @impl_on_finalise - $mod_type<$trait_instance: $trait_name>; + $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?>; $( $on_finalise )* } - decl_module! { + $crate::decl_module! { + @impl_offchain + $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?>; + $( $offchain )* + } + + $crate::decl_module! { @impl_deposit_event - $mod_type<$trait_instance: $trait_name>; + $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?>; $system; $( $deposit_event )* } - $( - decl_module! { - @impl_function - $mod_type<$trait_instance: $trait_name>; - $origin_type; - $from; - $fn_vis fn $fn_name ( - $from $(, $param_name : $param )* - ) $( -> $result )* { $( $impl )* } - } - )* + /// Can also be called using [`Call`]. + /// + /// [`Call`]: enum.Call.html + impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $mod_type<$trait_instance $(, $instance)?> { + $( + $crate::decl_module! { + @impl_function + $mod_type<$trait_instance: $trait_name $(, $fn_instance: $fn_instantiable)?>; + $origin_type; + $from; + $(#[doc = $doc_attr])* + $fn_vis fn $fn_name ( + $from $(, $param_name : $param )* + ) $( -> $result )* { $( $impl )* } + } + )* + } #[cfg(feature = "std")] $(#[$attr])* - pub enum $call_type<$trait_instance: $trait_name> { - __PhantomItem(::std::marker::PhantomData<$trait_instance>), - __OtherPhantomItem(::std::marker::PhantomData<$trait_instance>), + pub enum $call_type<$trait_instance: $trait_name$(, $instance: $instantiable $( = $module_default_instance)?)?> { + #[doc(hidden)] + __PhantomItem(::std::marker::PhantomData<($trait_instance $(, $instance)?)>, $crate::dispatch::Never), $( #[allow(non_camel_case_types)] + $(#[doc = $doc_attr])* $fn_name ( $( $param ),* ), )* } #[cfg(not(feature = "std"))] $(#[$attr])* - pub enum $call_type<$trait_instance: $trait_name> { - __PhantomItem(::core::marker::PhantomData<$trait_instance>), - __OtherPhantomItem(::core::marker::PhantomData<$trait_instance>), + pub enum $call_type<$trait_instance: $trait_name$(, $instance: $instantiable $( = $module_default_instance)?)?> { + #[doc(hidden)] + __PhantomItem(::core::marker::PhantomData<($trait_instance $(, $instance)?)>, $crate::dispatch::Never), $( #[allow(non_camel_case_types)] + $(#[doc = $doc_attr])* $fn_name ( $( $param ),* ), )* } // manual implementation of clone/eq/partialeq because using derive erroneously requires // clone/eq/partialeq from T. - impl<$trait_instance: $trait_name> $crate::dispatch::Clone - for $call_type<$trait_instance> + impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Clone + for $call_type<$trait_instance $(, $instance)?> { fn clone(&self) -> Self { match *self { @@ -642,8 +731,8 @@ macro_rules! decl_module { } } } - impl<$trait_instance: $trait_name> $crate::dispatch::PartialEq - for $call_type<$trait_instance> + impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::PartialEq + for $call_type<$trait_instance $(, $instance)?> { fn eq(&self, _other: &Self) -> bool { match *self { @@ -654,8 +743,7 @@ macro_rules! decl_module { self_params == ( $( $param_name, )* ) } else { match *_other { - $call_type::__PhantomItem(_) => unreachable!(), - $call_type::__OtherPhantomItem(_) => unreachable!(), + $call_type::__PhantomItem(_, _) => unreachable!(), _ => false, } } @@ -665,13 +753,13 @@ macro_rules! decl_module { } } } - impl<$trait_instance: $trait_name> $crate::dispatch::Eq - for $call_type<$trait_instance> + impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Eq + for $call_type<$trait_instance $(, $instance)?> {} #[cfg(feature = "std")] - impl<$trait_instance: $trait_name> $crate::dispatch::fmt::Debug - for $call_type<$trait_instance> + impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::fmt::Debug + for $call_type<$trait_instance $(, $instance)?> { fn fmt(&self, _f: &mut $crate::dispatch::fmt::Formatter) -> $crate::dispatch::result::Result<(), $crate::dispatch::fmt::Error> { match *self { @@ -687,22 +775,20 @@ macro_rules! decl_module { } } - impl<$trait_instance: $trait_name> $crate::dispatch::Decode for $call_type<$trait_instance> { - fn decode(input: &mut I) -> Option { + impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Decode for $call_type<$trait_instance $(, $instance)?> { + fn decode(input: &mut Input) -> Option { let _input_id = input.read_byte()?; $crate::__impl_decode!(input; _input_id; 0; $call_type; $( fn $fn_name( $( $(#[$codec_attr on type $param])* $param_name ),* ); )*) } } - impl<$trait_instance: $trait_name> $crate::dispatch::Encode for $call_type<$trait_instance> { + impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Encode for $call_type<$trait_instance $(, $instance)?> { fn encode_to(&self, _dest: &mut W) { $crate::__impl_encode!(_dest; *self; 0; $call_type; $( fn $fn_name( $( $(#[$codec_attr on type $param])* $param_name ),* ); )*); - if let $call_type::__PhantomItem(_) = *self { unreachable!() } - if let $call_type::__OtherPhantomItem(_) = *self { unreachable!() } } } - impl<$trait_instance: $trait_name> $crate::dispatch::Dispatchable - for $call_type<$trait_instance> + impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Dispatchable + for $call_type<$trait_instance $(, $instance)?> { type Trait = $trait_instance; type Origin = $origin_type; @@ -713,27 +799,28 @@ macro_rules! decl_module { $crate::decl_module!( @call $from - $mod_type $trait_instance $fn_name _origin $system [ $( $param_name ),* ] + $mod_type<$trait_instance $(, $fn_instance)?> $fn_name _origin $system [ $( $param_name ),* ] ) }, )* - _ => { panic!("__PhantomItem should never be used.") }, + $call_type::__PhantomItem(_, _) => { unreachable!("__PhantomItem should never be used.") }, } } } - impl<$trait_instance: $trait_name> $crate::dispatch::Callable - for $mod_type<$trait_instance> + impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Callable + for $mod_type<$trait_instance $(, $instance)?> { - type Call = $call_type<$trait_instance>; + type Call = $call_type<$trait_instance $(, $instance)?>; } - impl<$trait_instance: $trait_name> $mod_type<$trait_instance> { + impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $mod_type<$trait_instance $(, $instance)?> { + #[doc(hidden)] pub fn dispatch>(d: D, origin: D::Origin) -> $crate::dispatch::Result { d.dispatch(origin) } } $crate::__dispatch_impl_metadata! { - $mod_type $trait_instance $trait_name $call_type $origin_type + $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?> $call_type $origin_type {$( $(#[doc = $doc_attr])* fn $fn_name($from $(, $(#[$codec_attr])* $param_name : $param )*); )*} } } @@ -940,10 +1027,11 @@ macro_rules! __impl_outer_dispatch_common { #[doc(hidden)] macro_rules! __dispatch_impl_metadata { ( - $mod_type:ident $trait_instance:ident $trait_name:ident + $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?> $($rest:tt)* ) => { - impl<$trait_instance: $trait_name> $mod_type<$trait_instance> { + impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $mod_type<$trait_instance $(, $instance)?> { + #[doc(hidden)] pub fn call_functions() -> &'static [$crate::dispatch::FunctionMetadata] { $crate::__call_to_functions!($($rest)*) } @@ -1081,6 +1169,7 @@ mod tests { fn on_initialise(n: T::BlockNumber) { if n.into() == 42 { panic!("on_initialise") } } fn on_finalise(n: T::BlockNumber) { if n.into() == 42 { panic!("on_finalise") } } + fn offchain_worker() {} } } diff --git a/srml/support/src/double_map.rs b/srml/support/src/double_map.rs index bd3fd973c2b2ee46d8bc073429b046cc65ad951d..80d974064dedd41bbebd506e890e58575fd6f32c 100644 --- a/srml/support/src/double_map.rs +++ b/srml/support/src/double_map.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -31,7 +31,9 @@ use sr_std::borrow::Borrow; /// The storage key (i.e. the key under which the `Value` will be stored) is created from two parts. /// The first part is a hash of a concatenation of the `PREFIX` and `Key1`. And the second part /// is a hash of a `Key2`. -pub trait StorageDoubleMap { +/// +/// Hasher are implemented in derive_key* methods. +pub trait StorageDoubleMapWithHasher { type Key1: Codec; type Key2: Codec; type Value: Codec + Default; @@ -121,7 +123,7 @@ pub trait StorageDoubleMap { fn derive_key2(key2_data: Vec) -> Vec; /// Returns a compound key that consist of the two parts: (prefix, `k1`) and `k2`. - /// The first part is hased and then concatenated with a hash of `k2`. + /// The first part is hashed and then concatenated with a hash of `k2`. fn full_key(k1: &Q, k2: &R) -> Vec where Self::Key1: Borrow, diff --git a/srml/support/src/event.rs b/srml/support/src/event.rs index aa438c22f91307b4d768a20c9fc505722af380fe..9ca2bcf5321af5688b3395d9dea81770e4f2bb4c 100644 --- a/srml/support/src/event.rs +++ b/srml/support/src/event.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -26,9 +26,8 @@ pub use srml_metadata::{EventMetadata, DecodeDifferent, OuterEventMetadata, FnEn /// ```rust /// #[macro_use] /// extern crate srml_support; -/// extern crate parity_codec as codec; /// #[macro_use] -/// extern crate parity_codec_derive; +/// extern crate parity_codec as codec; /// #[macro_use] /// extern crate serde_derive; /// @@ -48,7 +47,7 @@ pub use srml_metadata::{EventMetadata, DecodeDifferent, OuterEventMetadata, FnEn /// extern crate srml_support; /// extern crate parity_codec as codec; /// #[macro_use] -/// extern crate parity_codec_derive; +/// extern crate parity_codec; /// #[macro_use] /// extern crate serde_derive; /// @@ -68,7 +67,7 @@ pub use srml_metadata::{EventMetadata, DecodeDifferent, OuterEventMetadata, FnEn /// /// mod event2 { /// // Event that uses the generic parameter `Balance`. -/// // If no name for the generic parameter is speciefied explicitly, +/// // If no name for the generic parameter is specified explicitly, /// // the name will be taken from the type name of the trait. /// decl_event!( /// pub enum Event where ::Balance { @@ -89,16 +88,48 @@ pub use srml_metadata::{EventMetadata, DecodeDifferent, OuterEventMetadata, FnEn /// ``` /// /// The syntax for generic events requires the `where`. +/// +/// # Generic Event with Instance Example: +/// +/// ```rust +/// #[macro_use] +/// extern crate srml_support; +/// extern crate parity_codec as codec; +/// #[macro_use] +/// extern crate parity_codec; +/// #[macro_use] +/// extern crate serde_derive; +/// +///# struct DefaultInstance; +///# trait Instance {} +///# impl Instance for DefaultInstance {} +/// trait Trait { +/// type Balance; +/// type Token; +/// } +/// +/// // For module with instances, DefaultInstance is optionnal +/// decl_event!( +/// pub enum Event where +/// ::Balance, +/// ::Token +/// { +/// Message(Balance, Token), +/// } +/// ); +///# fn main() {} +/// ``` #[macro_export] macro_rules! decl_event { ( $(#[$attr:meta])* - pub enum Event<$evt_generic_param:ident> where + pub enum Event<$evt_generic_param:ident $(, $instance:ident $(: $instantiable:ident)? $( = $event_default_instance:path)? )?> where $( $tt:tt )* ) => { $crate::__decl_generic_event!( $( #[ $attr ] )*; $evt_generic_param; + $($instance $( = $event_default_instance)? )?; { $( $tt )* }; ); }; @@ -111,8 +142,10 @@ macro_rules! decl_event { } ) => { // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. - #[derive(Clone, PartialEq, Eq, $crate::parity_codec_derive::Encode, $crate::parity_codec_derive::Decode)] + #[derive(Clone, PartialEq, Eq, $crate::codec::Encode, $crate::codec::Decode)] #[cfg_attr(feature = "std", derive(Debug))] + /// Events for this module. + /// $(#[$attr])* pub enum Event { $( @@ -139,25 +172,61 @@ macro_rules! __decl_generic_event { ( $(#[$attr:meta])*; $event_generic_param:ident; + $($instance:ident $( = $event_default_instance:path)? )?; { $( $tt:tt )* }; ) => { $crate::__decl_generic_event!(@format_generic $( #[ $attr ] )*; $event_generic_param; + $($instance $( = $event_default_instance)? )?; { $( $tt )* }; {}; ); }; + // Finish formatting on an unnamed one + (@format_generic + $(#[$attr:meta])*; + $event_generic_param:ident; + $($instance:ident $( = $event_default_instance:path)? )?; + { <$generic:ident as $trait:path>::$trait_type:ident $(,)? { $( $events:tt )* } }; + {$( $parsed:tt)*}; + ) => { + $crate::__decl_generic_event!(@generate + $( #[ $attr ] )*; + $event_generic_param; + $($instance $( = $event_default_instance)? )?; + { $($events)* }; + { $($parsed)*, $trait_type = <$generic as $trait>::$trait_type }; + ); + }; + // Finish formatting on a named one + (@format_generic + $(#[$attr:meta])*; + $event_generic_param:ident; + $($instance:ident $( = $event_default_instance:path)? )?; + { $generic_rename:ident = $generic_type:ty $(,)? { $( $events:tt )* } }; + { $($parsed:tt)* }; + ) => { + $crate::__decl_generic_event!(@generate + $(#[$attr])*; + $event_generic_param; + $($instance $( = $event_default_instance)? )?; + { $($events)* }; + { $($parsed)*, $generic_rename = $generic_type }; + ); + }; // Parse named (@format_generic $(#[$attr:meta])*; $event_generic_param:ident; + $($instance:ident $( = $event_default_instance:path)? )?; { $generic_rename:ident = $generic_type:ty, $($rest:tt)* }; {$( $parsed:tt)*}; ) => { $crate::__decl_generic_event!(@format_generic $( #[ $attr ] )*; $event_generic_param; + $( $instance $( = $event_default_instance)? )?; { $($rest)* }; { $($parsed)*, $generic_rename = $generic_type }; ); @@ -166,12 +235,14 @@ macro_rules! __decl_generic_event { (@format_generic $(#[$attr:meta])*; $event_generic_param:ident; + $($instance:ident $( = $event_default_instance:path)? )?; { <$generic:ident as $trait:path>::$trait_type:ident, $($rest:tt)* }; {$($parsed:tt)*}; ) => { $crate::__decl_generic_event!(@format_generic $( #[ $attr ] )*; $event_generic_param; + $($instance $( = $event_default_instance)? )?; { $($rest)* }; { $($parsed)*, $trait_type = <$generic as $trait>::$trait_type }; ); @@ -180,43 +251,17 @@ macro_rules! __decl_generic_event { (@format_generic $(#[$attr:meta])*; $event_generic_param:ident; + $($instance:ident $( = $event_default_instance:path)? )?; { $generic_type:ty, $($rest:tt)* }; - {$($parsed:tt)*}; + { $($parsed:tt)* }; ) => { $crate::__decl_generic_event!(@cannot_parse $generic_type); }; - // Finish formatting on an unnamed one - (@format_generic - $(#[$attr:meta])*; - $event_generic_param:ident; - { <$generic:ident as $trait:path>::$trait_type:ident { $( $events:tt )* } }; - {$( $parsed:tt)*}; - ) => { - $crate::__decl_generic_event!(@generate - $( #[ $attr ] )*; - $event_generic_param; - { $($events)* }; - { $($parsed)*, $trait_type = <$generic as $trait>::$trait_type}; - ); - }; - // Finish formatting on a named one - (@format_generic - $(#[$attr:meta])*; - $event_generic_param:ident; - { $generic_rename:ident = $generic_type:ty { $( $events:tt )* } }; - {$( $parsed:tt)*}; - ) => { - $crate::__decl_generic_event!(@generate - $(#[$attr])*; - $event_generic_param; - { $($events)* }; - { $($parsed)*, $generic_rename = $generic_type}; - ); - }; // Final unnamed type can't be parsed (@format_generic $(#[$attr:meta])*; $event_generic_param:ident; + $($instance:ident $( = $event_default_instance:path)? )?; { $generic_type:ty { $( $events:tt )* } }; {$( $parsed:tt)*}; ) => { @@ -225,23 +270,35 @@ macro_rules! __decl_generic_event { (@generate $(#[$attr:meta])*; $event_generic_param:ident; + $($instance:ident $( = $event_default_instance:path)? )?; { $( $events:tt )* }; { ,$( $generic_param:ident = $generic_type:ty ),* }; ) => { - pub type Event<$event_generic_param> = RawEvent<$( $generic_type ),*>; + /// [`RawEvent`] specialized for the configuration [`Trait`] + /// + /// [`RawEvent`]: enum.RawEvent.html + /// [`Trait`]: trait.Trait.html + pub type Event<$event_generic_param $(, $instance $( = $event_default_instance)? )?> = RawEvent<$( $generic_type ),* $(, $instance)? >; + // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. - #[derive(Clone, PartialEq, Eq, $crate::parity_codec_derive::Encode, $crate::parity_codec_derive::Decode)] + #[derive(Clone, PartialEq, Eq, $crate::codec::Encode, $crate::codec::Decode)] #[cfg_attr(feature = "std", derive(Debug))] + /// Events for this module. + /// $(#[$attr])* - pub enum RawEvent<$( $generic_param ),*> { + pub enum RawEvent<$( $generic_param ),* $(, $instance)? > { $( $events )* + $( + #[doc(hidden)] + PhantomData($crate::rstd::marker::PhantomData<$instance>), + )? } - impl<$( $generic_param ),*> From> for () { - fn from(_: RawEvent<$( $generic_param ),*>) -> () { () } + impl<$( $generic_param ),* $(, $instance)? > From> for () { + fn from(_: RawEvent<$( $generic_param ),* $(, $instance)?>) -> () { () } } - impl<$( $generic_param ),*> RawEvent<$( $generic_param ),*> { + impl<$( $generic_param ),* $(, $instance)?> RawEvent<$( $generic_param ),* $(, $instance)?> { #[allow(dead_code)] pub fn metadata() -> &'static [$crate::event::EventMetadata] { $crate::__events_to_metadata!(; $( $events )* ) @@ -294,7 +351,7 @@ macro_rules! impl_outer_event { ( $(#[$attr:meta])* pub enum $name:ident for $runtime:ident { - $( $rest:tt $( <$t:ident> )*, )* + $( $rest:tt $( <$t:ident $(, $rest_instance:path)? > )*, )* } ) => { $crate::impl_outer_event!( @@ -302,15 +359,14 @@ macro_rules! impl_outer_event { $name; $runtime; system; - Modules { $( $rest $(<$t>)*, )* }; + Modules { $( $rest $(<$t $(, $rest_instance)? >)*, )* }; ; ); }; ( $(#[$attr:meta])* pub enum $name:ident for $runtime:ident where system = $system:ident { - $module:ident, - $( $rest:tt $( <$t:ident> )*, )* + $( $rest:tt $( <$t:ident $(, $rest_instance:path)? > )*, )* } ) => { $crate::impl_outer_event!( @@ -318,24 +374,8 @@ macro_rules! impl_outer_event { $name; $runtime; $system; - Modules { $( $rest $(<$t>)*, )* }; - $module::Event<$runtime>,; - ); - }; - ( - $(#[$attr:meta])* - pub enum $name:ident for $runtime:ident where system = $system:ident { - $module:ident, - $( $rest:tt $( <$t:ident> )*, )* - } - ) => { - $crate::impl_outer_event!( - $( #[$attr] )*; - $name; - $runtime; - $system; - Modules { $( $rest $(<$t>)*, )* }; - $module::Event,; + Modules { $( $rest $(<$t $(, $rest_instance)? >)*, )* }; + ; ); }; ( @@ -344,18 +384,18 @@ macro_rules! impl_outer_event { $runtime:ident; $system:ident; Modules { - $module:ident, - $( $rest:tt $( <$t:ident> )*, )* + $module:ident, + $( $rest:tt $( <$t:ident $(, $rest_instance:path)? > )*, )* }; - $( $module_name:ident::Event $( <$generic_param:ident> )*, )*; + $( $module_name:ident::Event $( <$generic_param:ident $(, $generic_instance:path)? > )*, )*; ) => { $crate::impl_outer_event!( $( #[$attr] )*; $name; $runtime; $system; - Modules { $( $rest $(<$t>)*, )* }; - $( $module_name::Event $( <$generic_param> )*, )* $module::Event<$runtime>,; + Modules { $( $rest $(<$t $(, $rest_instance)? >)*, )* }; + $( $module_name::Event $( <$generic_param $(, $generic_instance)? > )*, )* $module::Event<$runtime $(, $instance)? >,; ); }; ( @@ -365,17 +405,17 @@ macro_rules! impl_outer_event { $system:ident; Modules { $module:ident, - $( $rest:tt, )* + $( $rest:tt )* }; - $( $module_name:ident::Event $( <$generic_param:ident> )*, )*; + $( $module_name:ident::Event $( <$generic_param:ident $(, $generic_instance:path)? > )*, )*; ) => { $crate::impl_outer_event!( $( #[$attr] )*; $name; $runtime; $system; - Modules { $( $rest, )* }; - $( $module_name::Event $( <$generic_param> )*, )* $module::Event,; + Modules { $( $rest )* }; + $( $module_name::Event $( <$generic_param $(, $generic_instance)? > )*, )* $module::Event,; ); }; @@ -387,17 +427,17 @@ macro_rules! impl_outer_event { $runtime:ident; $system:ident; Modules {}; - $( $module_name:ident::Event $( <$generic_param:ident> )*, )*; + $( $module_name:ident::Event $( <$generic_param:ident $(, $generic_instance:path)? > )*, )*; ) => { // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. - #[derive(Clone, PartialEq, Eq, $crate::parity_codec_derive::Encode, $crate::parity_codec_derive::Decode)] + #[derive(Clone, PartialEq, Eq, $crate::codec::Encode, $crate::codec::Decode)] #[cfg_attr(feature = "std", derive(Debug))] $(#[$attr])* #[allow(non_camel_case_types)] pub enum $name { system($system::Event), $( - $module_name( $module_name::Event $( <$generic_param> )* ), + $module_name( $module_name::Event $( <$generic_param $(, $generic_instance)? > )* ), )* } impl From<$system::Event> for $name { @@ -406,8 +446,8 @@ macro_rules! impl_outer_event { } } $( - impl From<$module_name::Event $( <$generic_param> )*> for $name { - fn from(x: $module_name::Event $( <$generic_param> )*) -> Self { + 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) } } @@ -416,7 +456,7 @@ macro_rules! impl_outer_event { $runtime; $name; $system; - $( $module_name::Event $( <$generic_param> )*, )*; + $( $module_name::Event $( <$generic_param $(, $generic_instance)? > )*, )*; ); } } @@ -428,7 +468,7 @@ macro_rules! __impl_outer_event_json_metadata { $runtime:ident; $event_name:ident; $system:ident; - $( $module_name:ident::Event $( <$generic_param:ident> )*, )*; + $( $module_name:ident::Event $( <$generic_param:ident $(, $generic_instance:path)? > )*, )*; ) => { impl $runtime { #[allow(dead_code)] @@ -441,7 +481,7 @@ macro_rules! __impl_outer_event_json_metadata { , ( stringify!($module_name), $crate::event::FnEncode( - $module_name::Event $( ::<$generic_param> )* ::metadata + $module_name::Event $( ::<$generic_param $(, $generic_instance)? > )* ::metadata ) ) )* @@ -456,7 +496,7 @@ macro_rules! __impl_outer_event_json_metadata { #[allow(dead_code)] $crate::paste::item!{ pub fn [< __module_events_ $module_name >] () -> &'static [$crate::event::EventMetadata] { - $module_name::Event $( ::<$generic_param> )* ::metadata() + $module_name::Event $( ::<$generic_param $(, $generic_instance)? > )* ::metadata() } } )* @@ -469,7 +509,7 @@ macro_rules! __impl_outer_event_json_metadata { mod tests { use super::*; use serde_derive::Serialize; - use parity_codec_derive::{Encode, Decode}; + use parity_codec::{Encode, Decode}; mod system { pub trait Trait { @@ -559,6 +599,50 @@ mod tests { ); } + mod event_module4 { + pub trait Trait { + type Origin; + type Balance; + type BlockNumber; + } + + decl_module! { + pub struct Module for enum Call where origin: T::Origin {} + } + + decl_event!( + /// Event finish formatting on an unnamed one with trailling comma + pub enum Event where + ::Balance, + ::Origin, + { + TestEvent(Balance, Origin), + } + ); + } + + mod event_module5 { + pub trait Trait { + type Origin; + type Balance; + type BlockNumber; + } + + decl_module! { + pub struct Module for enum Call where origin: T::Origin {} + } + + decl_event!( + /// Event finish formatting on an named one with trailling comma + pub enum Event where + BalanceRenamed = ::Balance, + OriginRenamed = ::Origin, + { + TestEvent(BalanceRenamed, OriginRenamed), + } + ); + } + #[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, Serialize)] pub struct TestRuntime; diff --git a/srml/support/src/hashable.rs b/srml/support/src/hashable.rs index 3d8b706b89abb4f583b15d52ac50abb8c45ec43b..886c88b23a3e83a360b6f344d03ef1abb8a9590d 100644 --- a/srml/support/src/hashable.rs +++ b/srml/support/src/hashable.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -27,12 +27,12 @@ pub trait Hashable: Sized { impl Hashable for T { fn blake2_256(&self) -> [u8; 32] { - blake2_256(&self.encode()) + self.using_encoded(blake2_256) } fn twox_128(&self) -> [u8; 16] { - twox_128(&self.encode()) + self.using_encoded(twox_128) } fn twox_256(&self) -> [u8; 32] { - twox_256(&self.encode()) + self.using_encoded(twox_256) } } diff --git a/srml/support/src/inherent.rs b/srml/support/src/inherent.rs index 671059ebe1346240e9aa8594950aeb3ee663181d..8a4fb669d15daafacb4cfaf6643374c70d2206cb 100644 --- a/srml/support/src/inherent.rs +++ b/srml/support/src/inherent.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/srml/support/src/lib.rs b/srml/support/src/lib.rs index 5980f5ddadabd8deb48ef68f8c13a7e9e023cc24..cbbdcc7e4c186b0e95d12b9cf1e7fa1b5af0010a 100644 --- a/srml/support/src/lib.rs +++ b/srml/support/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -19,14 +19,15 @@ #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), feature(alloc))] +#[macro_use] +extern crate bitmask; + #[cfg(feature = "std")] pub use serde; #[doc(hidden)] pub use sr_std as rstd; #[doc(hidden)] pub use parity_codec as codec; -#[doc(hidden)] -pub use parity_codec_derive; #[cfg(feature = "std")] #[doc(hidden)] pub use once_cell; @@ -35,6 +36,7 @@ pub use paste; pub use sr_primitives as runtime_primitives; pub use self::storage::generator::Storage as GenericStorage; +pub use self::storage::unhashed::generator::UnhashedStorage as GenericUnhashedStorage; #[macro_use] pub mod dispatch; @@ -54,10 +56,10 @@ pub mod inherent; mod double_map; pub mod traits; -pub use self::storage::{StorageVec, StorageList, StorageValue, StorageMap, EnumerableStorageMap}; +pub use self::storage::{StorageVec, StorageList, StorageValue, StorageMap, EnumerableStorageMap, StorageDoubleMap}; pub use self::hashable::Hashable; pub use self::dispatch::{Parameter, Dispatchable, Callable, IsSubType}; -pub use self::double_map::StorageDoubleMap; +pub use self::double_map::StorageDoubleMapWithHasher; pub use runtime_io::print; #[doc(inline)] @@ -139,6 +141,12 @@ mod tests { use parity_codec::Codec; use runtime_io::{with_externalities, Blake2Hasher}; use runtime_primitives::BuildStorage; + pub use srml_metadata::{ + DecodeDifferent, StorageMetadata, StorageFunctionMetadata, + StorageFunctionType, StorageFunctionModifier, + DefaultByte, DefaultByteGetter, + }; + pub use rstd::marker::PhantomData; pub trait Trait { type BlockNumber: Codec + Default; @@ -163,6 +171,10 @@ mod tests { pub Data get(data) build(|_| vec![(15u32, 42u64)]): linked_map u32 => u64; pub GenericData get(generic_data): linked_map T::BlockNumber => T::BlockNumber; pub GenericData2 get(generic_data2): linked_map T::BlockNumber => Option; + + pub DataDM config(test_config) build(|_| vec![(15u32, 16u32, 42u64)]): double_map u32, blake2_256(u32) => u64; + pub GenericDataDM: double_map T::BlockNumber, twox_128(T::BlockNumber) => T::BlockNumber; + pub GenericData2DM: double_map T::BlockNumber, twox_256(T::BlockNumber) => Option; } } @@ -179,7 +191,7 @@ mod tests { type Map = Data; #[test] - fn basic_insert_remove_should_work() { + fn linked_map_basic_insert_remove_should_work() { with_externalities(&mut new_test_ext(), || { // initialised during genesis assert_eq!(Map::get(&15u32), 42u64); @@ -205,7 +217,7 @@ mod tests { } #[test] - fn enumeration_and_head_should_work() { + fn linked_map_enumeration_and_head_should_work() { with_externalities(&mut new_test_ext(), || { assert_eq!(Map::head(), Some(15)); assert_eq!(Map::enumerate().collect::>(), vec![(15, 42)]); @@ -256,4 +268,128 @@ mod tests { }); } + #[test] + fn double_map_basic_insert_remove_remove_prefix_should_work() { + with_externalities(&mut new_test_ext(), || { + type DoubleMap = DataDM; + // initialised during genesis + assert_eq!(DoubleMap::get(&15u32, &16u32), 42u64); + + // get / insert / take + let key1 = 17u32; + let key2 = 18u32; + assert_eq!(DoubleMap::get(key1, key2), 0u64); + DoubleMap::insert(key1, key2, 4u64); + assert_eq!(DoubleMap::get(key1, key2), 4u64); + assert_eq!(DoubleMap::take(key1, key2), 4u64); + assert_eq!(DoubleMap::get(key1, key2), 0u64); + + // mutate + DoubleMap::mutate(key1, key2, |val| { + *val = 15; + }); + assert_eq!(DoubleMap::get(key1, key2), 15u64); + + // remove + DoubleMap::remove(key1, key2); + assert_eq!(DoubleMap::get(key1, key2), 0u64); + + // remove prefix + DoubleMap::insert(key1, key2, 4u64); + DoubleMap::insert(key1, key2+1, 4u64); + DoubleMap::insert(key1+1, key2, 4u64); + DoubleMap::insert(key1+1, key2+1, 4u64); + DoubleMap::remove_prefix(key1); + assert_eq!(DoubleMap::get(key1, key2), 0u64); + assert_eq!(DoubleMap::get(key1, key2+1), 0u64); + assert_eq!(DoubleMap::get(key1+1, key2), 4u64); + assert_eq!(DoubleMap::get(key1+1, key2+1), 4u64); + }); + } + + const EXPECTED_METADATA: StorageMetadata = StorageMetadata { + functions: DecodeDifferent::Encode(&[ + StorageFunctionMetadata { + name: DecodeDifferent::Encode("Data"), + modifier: StorageFunctionModifier::Default, + ty: StorageFunctionType::Map{ + key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("u64"), is_linked: true + }, + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructData(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageFunctionMetadata { + name: DecodeDifferent::Encode("GenericData"), + modifier: StorageFunctionModifier::Default, + ty: StorageFunctionType::Map{ + key: DecodeDifferent::Encode("T::BlockNumber"), value: DecodeDifferent::Encode("T::BlockNumber"), is_linked: true + }, + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructGenericData(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageFunctionMetadata { + name: DecodeDifferent::Encode("GenericData2"), + modifier: StorageFunctionModifier::Optional, + ty: StorageFunctionType::Map{ + key: DecodeDifferent::Encode("T::BlockNumber"), value: DecodeDifferent::Encode("T::BlockNumber"), is_linked: true + }, + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructGenericData2(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageFunctionMetadata { + name: DecodeDifferent::Encode("DataDM"), + modifier: StorageFunctionModifier::Default, + ty: StorageFunctionType::DoubleMap{ + key1: DecodeDifferent::Encode("u32"), + key2: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("u64"), + key2_hasher: DecodeDifferent::Encode("blake2_256"), + }, + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructDataDM(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageFunctionMetadata { + name: DecodeDifferent::Encode("GenericDataDM"), + modifier: StorageFunctionModifier::Default, + ty: StorageFunctionType::DoubleMap{ + key1: DecodeDifferent::Encode("T::BlockNumber"), + key2: DecodeDifferent::Encode("T::BlockNumber"), + value: DecodeDifferent::Encode("T::BlockNumber"), + key2_hasher: DecodeDifferent::Encode("twox_128"), + }, + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructGenericDataDM(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + StorageFunctionMetadata { + name: DecodeDifferent::Encode("GenericData2DM"), + modifier: StorageFunctionModifier::Optional, + ty: StorageFunctionType::DoubleMap{ + key1: DecodeDifferent::Encode("T::BlockNumber"), + key2: DecodeDifferent::Encode("T::BlockNumber"), + value: DecodeDifferent::Encode("T::BlockNumber"), + key2_hasher: DecodeDifferent::Encode("twox_256"), + }, + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructGenericData2DM(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + ]) + }; + + #[test] + fn store_metadata() { + let metadata = Module::::store_metadata(); + assert_eq!(EXPECTED_METADATA, metadata); + } } diff --git a/srml/support/src/metadata.rs b/srml/support/src/metadata.rs index d9750975ee57eb45847d781b38c4f7d068ce5a47..f7594d27b7c2b79a1cca6ea2bfb5e8135e5a3b9b 100644 --- a/srml/support/src/metadata.rs +++ b/srml/support/src/metadata.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ pub use srml_metadata::{ DecodeDifferent, FnEncode, RuntimeMetadata, - ModuleMetadata, RuntimeMetadataV1, + ModuleMetadata, RuntimeMetadataV3, DefaultByteGetter, RuntimeMetadataPrefixed, }; @@ -36,8 +36,8 @@ macro_rules! impl_runtime_metadata { ) => { impl $runtime { pub fn metadata() -> $crate::metadata::RuntimeMetadataPrefixed { - $crate::metadata::RuntimeMetadata::V1 ( - $crate::metadata::RuntimeMetadataV1 { + $crate::metadata::RuntimeMetadata::V3 ( + $crate::metadata::RuntimeMetadataV3 { modules: $crate::__runtime_modules_to_metadata!($runtime;; $( $rest )*), } ).into() @@ -52,17 +52,17 @@ macro_rules! __runtime_modules_to_metadata { ( $runtime: ident; $( $metadata:expr ),*; - $mod:ident::$module:ident $(with)+ $($kw:ident)*, + $mod:ident::$module:ident $( < $instance:ident > )? $(with)+ $($kw:ident)*, $( $rest:tt )* ) => { $crate::__runtime_modules_to_metadata!( $runtime; $( $metadata, )* $crate::metadata::ModuleMetadata { name: $crate::metadata::DecodeDifferent::Encode(stringify!($mod)), - prefix: $crate::__runtime_modules_to_metadata_calls_storagename!($mod, $module, $runtime, $(with $kw)*), - storage: $crate::__runtime_modules_to_metadata_calls_storage!($mod, $module, $runtime, $(with $kw)*), - calls: $crate::__runtime_modules_to_metadata_calls_call!($mod, $module, $runtime, $(with $kw)*), - event: $crate::__runtime_modules_to_metadata_calls_event!($mod, $module, $runtime, $(with $kw)*), + prefix: $crate::__runtime_modules_to_metadata_calls_storagename!($mod, $module $( <$instance> )?, $runtime, $(with $kw)*), + 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)*), }; $( $rest )* ) @@ -81,7 +81,7 @@ macro_rules! __runtime_modules_to_metadata_calls_call { // skip system ( system, - $skip_module: ident, + $skip_module: ident $( <$instance:ident> )?, $skip_runtime: ident, with Call $(with $kws:ident)* @@ -90,29 +90,29 @@ macro_rules! __runtime_modules_to_metadata_calls_call { }; ( $mod: ident, - $module: ident, + $module: ident $( <$instance:ident> )?, $runtime: ident, with Call $(with $kws:ident)* ) => { Some($crate::metadata::DecodeDifferent::Encode( $crate::metadata::FnEncode( - $mod::$module::<$runtime>::call_functions + $mod::$module::<$runtime $(, $mod::$instance )?>::call_functions ) )) }; ( $mod: ident, - $module: ident, + $module: ident $( <$instance:ident> )?, $runtime: ident, with $_:ident $(with $kws:ident)* ) => { - $crate::__runtime_modules_to_metadata_calls_call!( $mod, $module, $runtime, $(with $kws)* ); + $crate::__runtime_modules_to_metadata_calls_call!( $mod, $module $( <$instance> )?, $runtime, $(with $kws)* ); }; ( $mod: ident, - $module: ident, + $module: ident $( <$instance:ident> )?, $runtime: ident, ) => { None @@ -125,7 +125,7 @@ macro_rules! __runtime_modules_to_metadata_calls_call { macro_rules! __runtime_modules_to_metadata_calls_event { ( $mod: ident, - $module: ident, + $module: ident $( <$instance:ident> )?, $runtime: ident, with Event $(with $kws:ident)* @@ -133,23 +133,23 @@ macro_rules! __runtime_modules_to_metadata_calls_event { Some($crate::metadata::DecodeDifferent::Encode( $crate::metadata::FnEncode( $crate::paste::expr!{ - $runtime:: [< __module_events_ $mod >] + $runtime:: [< __module_events_ $mod $(_ $instance)?>] } ) )) }; ( $mod: ident, - $module: ident, + $module: ident $( <$instance:ident> )?, $runtime: ident, with $_:ident $(with $kws:ident)* ) => { - $crate::__runtime_modules_to_metadata_calls_event!( $mod, $module, $runtime, $(with $kws)* ); + $crate::__runtime_modules_to_metadata_calls_event!( $mod, $module $( <$instance> )?, $runtime, $(with $kws)* ); }; ( $mod: ident, - $module: ident, + $module: ident $( <$instance:ident> )?, $runtime: ident, ) => { None @@ -161,29 +161,29 @@ macro_rules! __runtime_modules_to_metadata_calls_event { macro_rules! __runtime_modules_to_metadata_calls_storagename { ( $mod: ident, - $module: ident, + $module: ident $( <$instance:ident> )?, $runtime: ident, with Storage $(with $kws:ident)* ) => { $crate::metadata::DecodeDifferent::Encode( $crate::metadata::FnEncode( - $mod::$module::<$runtime>::store_metadata_name + $mod::$module::<$runtime $(, $mod::$instance )?>::store_metadata_name ) ) }; ( $mod: ident, - $module: ident, + $module: ident $( <$instance:ident> )?, $runtime: ident, with $_:ident $(with $kws:ident)* ) => { - $crate::__runtime_modules_to_metadata_calls_storagename!( $mod, $module, $runtime, $(with $kws)* ); + $crate::__runtime_modules_to_metadata_calls_storagename!( $mod, $module $( <$instance> )?, $runtime, $(with $kws)* ); }; ( $mod: ident, - $module: ident, + $module: ident $( <$instance:ident> )?, $runtime: ident, ) => { $crate::metadata::DecodeDifferent::Encode( @@ -197,29 +197,29 @@ macro_rules! __runtime_modules_to_metadata_calls_storagename { macro_rules! __runtime_modules_to_metadata_calls_storage { ( $mod: ident, - $module: ident, + $module: ident $( <$instance:ident> )?, $runtime: ident, with Storage $(with $kws:ident)* ) => { Some($crate::metadata::DecodeDifferent::Encode( $crate::metadata::FnEncode( - $mod::$module::<$runtime>::store_metadata_functions + $mod::$module::<$runtime $(, $mod::$instance )?>::store_metadata_functions ) )) }; ( $mod: ident, - $module: ident, + $module: ident $( <$instance:ident> )?, $runtime: ident, with $_:ident $(with $kws:ident)* ) => { - $crate::__runtime_modules_to_metadata_calls_storage!( $mod, $module, $runtime, $(with $kws)* ); + $crate::__runtime_modules_to_metadata_calls_storage!( $mod, $module $( <$instance> )?, $runtime, $(with $kws)* ); }; ( $mod: ident, - $module: ident, + $module: ident $( <$instance:ident> )?, $runtime: ident, ) => { None @@ -239,8 +239,6 @@ mod tests { ModuleMetadata, RuntimeMetadataPrefixed }; use crate::codec::{Encode, Decode}; - use parity_codec_derive::{Decode, Encode}; - mod system { pub trait Trait { @@ -379,8 +377,8 @@ mod tests { event_module2::Module with Event Storage Call, ); - const EXPECTED_METADATA: RuntimeMetadata = RuntimeMetadata::V1( - RuntimeMetadataV1 { + const EXPECTED_METADATA: RuntimeMetadata = RuntimeMetadata::V3( + RuntimeMetadataV3 { modules: DecodeDifferent::Encode(&[ ModuleMetadata { name: DecodeDifferent::Encode("system"), diff --git a/srml/support/src/origin.rs b/srml/support/src/origin.rs index 5832a4f7b8c72f4269544ddbcb75c86d26e0c9c8..2d97f218e095819fb41f8868a7b17929d7a4bcd2 100644 --- a/srml/support/src/origin.rs +++ b/srml/support/src/origin.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -28,34 +28,20 @@ macro_rules! impl_outer_origin { ( $(#[$attr:meta])* pub enum $name:ident for $runtime:ident { - $( $module:ident $( <$generic:ident> )* ),* $(,)* + $( $module:ident $( <$generic:ident $(, $instance:path )? > )? ),* $(,)? } ) => { $crate::impl_outer_origin! { $(#[$attr])* pub enum $name for $runtime where system = system { - $( $module $( <$generic> )*, )* + $( $module $( <$generic $(, $instance )? > )?, )* } } }; - ( - $(#[$attr:meta])* - pub enum $name:ident for $runtime:ident where system = $system:ident {} - ) => { - $crate::impl_outer_origin!( - $( #[$attr] )*; - $name; - $runtime; - $system; - Modules { }; - ; - ); - }; ( $(#[$attr:meta])* pub enum $name:ident for $runtime:ident where system = $system:ident { - $module:ident, - $( $rest_module:ident $( <$rest_generic:ident> )* ),* $(,)* + $( $module:ident $( <$generic:ident $(, $instance:path )?> )? ),* $(,)? } ) => { $crate::impl_outer_origin!( @@ -63,64 +49,30 @@ macro_rules! impl_outer_origin { $name; $runtime; $system; - Modules { $( $rest_module $( <$rest_generic> )*, )* }; - $module; - ); - }; - ( - $(#[$attr:meta])* - pub enum $name:ident for $runtime:ident where system = $system:ident { - $module:ident, - $( $rest_module:ident $( <$rest_generic:ident> )* ),* $(,)* - } - ) => { - $crate::impl_outer_origin!( - $( #[$attr] )*; - $name; - $runtime; - $system; - Modules { $( $rest_module $( <$rest_generic> )*, )* }; - $module<$runtime>; - ); - }; - ( - $(#[$attr:meta])*; - $name:ident; - $runtime:ident; - $system:ident; - Modules { - $module:ident, - $( $rest_module:ident $( <$rest_generic:ident> )*, )* - }; - $( $parsed_module:ident $( <$generic_param:ident> )* ),*; - ) => { - $crate::impl_outer_origin!( - $( #[$attr] )*; - $name; - $runtime; - $system; - Modules { $( $rest_module $( <$rest_generic> )*, )* }; - $( $parsed_module $( <$generic_param> )* ),*, $module; + Modules { $( $module $( <$generic $(, $instance )? > )*, )* }; ); }; + + // Replace generic param with runtime + ( $(#[$attr:meta])*; $name:ident; $runtime:ident; $system:ident; Modules { - $module:ident, - $( $rest_module:ident $( <$rest_generic:ident> )*, )* + $module:ident $( )?, + $( $rest_module:tt )* }; - $( $parsed_module:ident $( <$generic_param:ident> )* ),*; + $( $parsed:tt )* ) => { $crate::impl_outer_origin!( $( #[$attr] )*; $name; $runtime; $system; - Modules { $( $rest_module $( <$rest_generic> )*, )* }; - $( $parsed_module $( <$generic_param> )* ),*, $module<$runtime>; + Modules { $( $rest_module )* }; + $( $parsed )* $module $( <$runtime $(, $instance )? > )?, ); }; @@ -131,8 +83,8 @@ macro_rules! impl_outer_origin { $name:ident; $runtime:ident; $system:ident; - Modules {}; - $( $module:ident $( <$generic_param:ident> )* ),*; + Modules { }; + $( $module:ident $( <$generic_param:ident $(, $generic_instance:path )? > )* ,)* ) => { // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, PartialEq, Eq)] @@ -142,7 +94,7 @@ macro_rules! impl_outer_origin { pub enum $name { system($system::Origin<$runtime>), $( - $module($module::Origin $( <$generic_param> )* ), + $module($module::Origin $( <$generic_param $(, $generic_instance )? > )* ), )* #[allow(dead_code)] Void($crate::Void) @@ -175,13 +127,13 @@ macro_rules! impl_outer_origin { } } $( - impl From<$module::Origin $( <$generic_param> )*> for $name { - fn from(x: $module::Origin $( <$generic_param> )*) -> Self { + impl From<$module::Origin $( <$generic_param $(, $generic_instance )? > )*> for $name { + fn from(x: $module::Origin $( <$generic_param $(, $generic_instance )? > )*) -> Self { $name::$module(x) } } - impl Into )*>> for $name { - fn into(self) -> Option<$module::Origin $( <$generic_param> )*> { + impl Into )*>> for $name { + fn into(self) -> Option<$module::Origin $( <$generic_param $(, $generic_instance )? > )*> { if let $name::$module(l) = self { Some(l) } else { diff --git a/srml/support/src/runtime.rs b/srml/support/src/runtime.rs index a1093dae5b27e381e99e434b29d2d5202a344333..4f402da8d5b545c099a9db7307f0467dc34d6323 100644 --- a/srml/support/src/runtime.rs +++ b/srml/support/src/runtime.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -37,6 +37,10 @@ /// System: system, /// Test: test::{default, Log(Test)}, /// Test2: test_with_long_module::{Module}, +/// +/// // Module with instances +/// Test3_Instance1: test3::::{Module, Call, Storage, Event, Config, Origin}, +/// Test3_DefaultInstance: test3::{Module, Call, Storage, Event, Config, Origin}, /// } /// ) /// ``` @@ -55,13 +59,18 @@ /// - `Module` /// - `Call` /// - `Storage` -/// - `Event` or `Event` (if the event is generic) -/// - `Origin` or `Origin` (if the origin is generic) -/// - `Config` or `Config` (if the config is generic) +/// - `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) /// - `Log( $(IDENT),* )` /// - `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. +/// +/// # Note +/// +/// The population of the genesis storage depends on the order of modules. So, if one of your +/// modules depends on another module. The dependent module need to come before the module depending on it. #[macro_export] macro_rules! construct_runtime { @@ -78,156 +87,61 @@ macro_rules! construct_runtime { $( $rest:tt )* } ) => { - construct_runtime!( - $runtime; - $block; - $node_block; - $uncheckedextrinsic; - $log_internal < $( $log_genarg ),* >; - ; + $crate::construct_runtime!( + { + $runtime; + $block; + $node_block; + $uncheckedextrinsic; + $log_internal < $( $log_genarg ),* >; + }; + {}; $( $rest )* ); }; ( - $runtime:ident; - $block:ident; - $node_block:ty; - $uncheckedextrinsic:ident; - $log_internal:ident <$( $log_genarg:ty ),+>; - $( - $expanded_name:ident: $expanded_module:ident::{ - $( - $expanded_modules:ident - $( <$expanded_modules_generic:ident> )* - $( ( $( $expanded_modules_args:ident ),* ) )* - ),* - } - ),*; + { $( $preset:tt )* }; + { $( $expanded:tt )* }; $name:ident: $module:ident, - $( - $rest_name:ident: $rest_module:ident $( - ::{ - $( - $rest_modules:ident - $( <$rest_modules_generic:ident> )* - $( ( $( $rest_modules_args:ident ),* ) )* - ),* - } - )*, - )* + $( $rest:tt )* ) => { - construct_runtime!( - $runtime; - $block; - $node_block; - $uncheckedextrinsic; - $log_internal < $( $log_genarg ),* >; - $( - $expanded_name: $expanded_module::{ - $( - $expanded_modules - $( <$expanded_modules_generic> )* - $( ( $( $expanded_modules_args ),* ) )* - ),* - }, - )* $name: $module::{Module, Call, Storage, Event, Config}; - $( - $rest_name: $rest_module $( - ::{ - $( - $rest_modules - $( <$rest_modules_generic> )* - $( ( $( $rest_modules_args ),* ) )* - ),* - } - )*, - )* + $crate::construct_runtime!( + { $( $preset )* }; + { $( $expanded )* $name: $module::{Module, Call, Storage, Event, Config}, }; + $( $rest )* ); }; ( - $runtime:ident; - $block:ident; - $node_block:ty; - $uncheckedextrinsic:ident; - $log_internal:ident <$( $log_genarg:ty ),+>; - $( - $expanded_name:ident: $expanded_module:ident::{ - $( - $expanded_modules:ident - $( <$expanded_modules_generic:ident> )* - $( ( $( $expanded_modules_args:ident ),* ) )* - ),* - } - ),*; + { $( $preset:tt )* }; + { $( $expanded:tt )* }; $name:ident: $module:ident::{ default, $( $modules:ident - $( <$modules_generic:ident> )* + $( <$modules_generic:ident $(, $modules_instance:ident)?> )* $( ( $( $modules_args:ident ),* ) )* ),* }, - $( - $rest_name:ident: $rest_module:ident $( - ::{ + $( $rest:tt )* + ) => { + $crate::construct_runtime!( + { $( $preset )* }; + { + $( $expanded )* + $name: $module::{ + Module, Call, Storage, Event, Config, $( - $rest_modules:ident - $( <$rest_modules_generic:ident> )* - $( ( $( $rest_modules_args:ident ),* ) )* - ),* - } - )*, - )* - ) => { - construct_runtime!( - $runtime; - $block; - $node_block; - $uncheckedextrinsic; - $log_internal < $( $log_genarg ),* >; - $( - $expanded_name: $expanded_module::{ - $( - $expanded_modules - $( <$expanded_modules_generic> )* - $( ( $( $expanded_modules_args ),* ) )* + $modules $( <$modules_generic $(, $modules_instance)?> )* + $( ( $( $modules_args ),* ) )* ),* }, - )* - $name: $module::{ - Module, Call, Storage, Event, Config, - $( - $modules $( <$modules_generic> )* $( ( $( $modules_args ),* ) )* - ),* }; - $( - $rest_name: $rest_module $( - ::{ - $( - $rest_modules - $( <$rest_modules_generic> )* - $( ( $( $rest_modules_args ),* ) )* - ),* - } - )*, - )* + $( $rest )* ); }; ( - $runtime:ident; - $block:ident; - $node_block:ty; - $uncheckedextrinsic:ident; - $log_internal:ident <$( $log_genarg:ty ),+>; - $( - $expanded_name:ident: $expanded_module:ident::{ - $( - $expanded_modules:ident - $( <$expanded_modules_generic:ident> )* - $( ( $( $expanded_modules_args:ident ),* ) )* - ),* - } - ),*; + { $( $preset:tt )* }; + { $( $expanded:tt )* }; $name:ident: $module:ident::{ $( $modules:ident @@ -235,69 +149,70 @@ macro_rules! construct_runtime { $( ( $( $modules_args:ident ),* ) )* ),* }, - $( - $rest_name:ident: $rest_module:ident $( - ::{ + $( $rest:tt )* + ) => { + $crate::construct_runtime!( + { $( $preset )* }; + { + $( $expanded )* + $name: $module::{ $( - $rest_modules:ident - $( <$rest_modules_generic:ident> )* - $( ( $( $rest_modules_args:ident ),* ) )* + $modules $( <$modules_generic> )* + $( ( $( $modules_args ),* ) )* ),* - } - )*, - )* - ) => { - construct_runtime!( - $runtime; - $block; - $node_block; - $uncheckedextrinsic; - $log_internal < $( $log_genarg ),* >; + }, + }; + $( $rest )* + ); + }; + ( // Instance module: we indicate the generic instance `I` with the full instance path + { $( $preset:tt )* }; + { $( $expanded:tt )* }; + $name:ident: $module:ident ::< $module_instance:ident >::{ $( - $expanded_name: $expanded_module::{ + $modules:ident + $( <$modules_generic:ident $(, $modules_instance:ident )?> )* + $( ( $( $modules_args:ident ),* ) )* + ),* + }, + $( $rest:tt )* + ) => { + $crate::construct_runtime!( + { $( $preset )* }; + { + $( $expanded )* + $name: $module::<$module_instance>::{ $( - $expanded_modules - $( <$expanded_modules_generic> )* - $( ( $( $expanded_modules_args ),* ) )* + $modules $( <$modules_generic $(, $modules_instance=$module::$module_instance)?> )* + $( ( $( $modules_args ),* ) )* ),* }, - )* - $name: $module::{ - $( - $modules $( <$modules_generic> )* $( ( $( $modules_args ),* ) )* - ),* }; - $( - $rest_name: $rest_module $( - ::{ - $( - $rest_modules - $( <$rest_modules_generic> )* - $( ( $( $rest_modules_args ),* ) )* - ),* - } - )*, - )* + $( $rest )* ); }; // The main macro expansion that actually renders the Runtime code. ( - $runtime:ident; - $block:ident; - $node_block:ty; - $uncheckedextrinsic:ident; - $log_internal:ident <$( $log_genarg:ty ),+>; - $( - $name:ident: $module:ident::{ - $( - $modules:ident - $( <$modules_generic:ident> )* - $( ( $( $modules_args:ident ),* ) )* - ),* - } - ),*; + { + $runtime:ident; + $block:ident; + $node_block:ty; + $uncheckedextrinsic:ident; + $log_internal:ident <$( $log_genarg:ty ),+>; + }; + { + $( + $name:ident: $module:ident :: $( < $module_instance:ident >:: )? { + $( + $modules:ident + $( <$modules_generic:ident $(, I=$modules_instance:path)?> )* + $( ( $( $modules_args:ident ),* ) )* + ),* + }, + )* + }; ) => { #[derive(Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Debug))] @@ -308,54 +223,59 @@ 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::{ $( $modules $( <$modules_generic> )* ),* } + $name: $module:: $( < $module_instance >:: )? { $( $modules $( <$modules_generic $(, $modules_instance)?> )* ),* } ),* ); $crate::__decl_outer_origin!( $runtime; $( - $name: $module::{ $( $modules $( <$modules_generic> )* ),* } + $name: $module:: $( < $module_instance >:: )? { $( $modules $( <$modules_generic $(, $modules_instance)?> )* ),* } ),* ); $crate::__decl_all_modules!( $runtime; ; - ; + {}; $( - $name: $module::{ $( $modules $( <$modules_generic> )* ),* } - ),*; + $name: $module:: $( < $module_instance >:: )? { $( $modules ),* }, + )* ); $crate::__decl_outer_dispatch!( $runtime; ; $( - $name: $module::{ $( $modules $( <$modules_generic> )* ),* } + $name: $module::{ $( $modules ),* } ),*; ); $crate::__decl_runtime_metadata!( $runtime; - ; + {}; $( - $name: $module::{ $( $modules )* } + $name: $module:: $( < $module_instance >:: )? { $( $modules )* } )* ); $crate::__decl_outer_log!( $runtime; $log_internal < $( $log_genarg ),* >; - ; + {}; $( - $name: $module::{ $( $modules $( ( $( $modules_args ),* ) )* ),* } - ),*; + $name: $module:: $( < $module_instance >:: )? { $( $modules $( ( $( $modules_args )* ) )* )* } + )* ); $crate::__decl_outer_config!( $runtime; - ; + {}; $( - $name: $module::{ $( $modules $( <$modules_generic> )* ),* } - ),*; + $name: $module:: $( < $module_instance >:: )? { + $( $modules $( <$modules_generic $(, $modules_instance)?> )* ),* + }, + )* ); $crate::__decl_outer_inherent!( $runtime; @@ -387,121 +307,135 @@ macro_rules! __create_decl_macro { macro_rules! $macro_name { ( $runtime:ident; - $d( $name:ident : $module:ident::{ - $d( $modules:ident $d( <$modules_generic:ident> )* ),* + $d( $name:ident : $module:ident:: $d( < $module_instance:ident >:: )? { + $d( $modules:ident $d( <$modules_generic:ident $d(, $modules_instance:path)?> ),* ),* }),* ) => { $d crate::$macro_name!(@inner $runtime; ; - ; + {}; $d( - $name: $module::{ - $d( $modules $d( <$modules_generic> )* ),* - } - ),*; + $name: $module:: $d( < $module_instance >:: )? { + $d( $modules $d( <$modules_generic $d(, $modules_instance)?> )* ),* + }, + )* ); }; (@inner $runtime:ident; ; // there can not be multiple `System`s - $d( $parsed_modules:ident $d( <$parsed_generic:ident> )* ),*; + { $d( $parsed:tt )* }; System: $module:ident::{ - $ingore:ident $d( <$ignor:ident> )* $d(, $modules:ident $d( <$modules_generic:ident> )* )* - } - $d(, $rest_name:ident : $rest_module:ident::{ - $d( $rest_modules:ident $d( <$rest_modules_generic:ident> )* ),* - })*; + $d( $modules:ident $d( <$modules_generic:ident> )* ),* + }, + $d( $rest:tt )* ) => { $d crate::$macro_name!(@inner $runtime; $module; - $d( $parsed_modules $d( <$parsed_generic> )* ),*; - $d( - $rest_name: $rest_module::{ - $d( $rest_modules $d( <$rest_modules_generic> )* ),* - } - ),*; + { $d( $parsed )* }; + $d( $rest )* ); }; (@inner $runtime:ident; - $d( $system:ident )*; - $d( $parsed_modules:ident $d( <$parsed_generic:ident> )* ),*; - $name:ident: $module:ident::{ - $macro_enum_name $d( <$event_gen:ident> )* $d(, $modules:ident $d( <$modules_generic:ident> )* )* - } - $d(, $rest_name:ident : $rest_module:ident::{ - $d( $rest_modules:ident $d( <$rest_modules_generic:ident> )* ),* - })*; + $d( $system:ident )?; + { $d( $parsed:tt )* }; + $name:ident : $module:ident:: < $module_instance:ident >:: { + $macro_enum_name <$event_generic:ident, $event_instance:path> $d(, $ingore:ident $d( <$ignor:ident $d(, $ignore_instance:path)?> )* )* + }, + $d( $rest:tt )* ) => { $d crate::$macro_name!(@inner $runtime; - $d( $system )*; - $d( - $parsed_modules $d( <$parsed_generic> )* , )* - $module $d( <$event_gen> )*; - $d( - $rest_name: $rest_module::{ - $d( $rest_modules $d( <$rest_modules_generic> )* ),* - } - ),*; + $d( $system )?; + { + $d( $parsed )* + $module $module_instance <$event_generic, $event_instance>, + }; + $d( $rest )* ); }; (@inner $runtime:ident; - $d( $system:ident )*; - $d( $parsed_modules:ident $d( <$parsed_generic:ident> )* ),*; - $name:ident: $module:ident::{ - $ingore:ident $d( <$ignor:ident> )* $d(, $modules:ident $d( <$modules_generic:ident> )* )* - } - $d(, $rest_name:ident : $rest_module:ident::{ - $d( $rest_modules:ident $d( <$rest_modules_generic:ident> )* ),* - })*; + $d( $system:ident )?; + { $d( $parsed:tt )* }; + $name:ident : $module:ident:: < $module_instance:ident >:: { + $macro_enum_name $d( <$event_generic:ident> )* $d(, $ingore: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(, $ingore:ident $d( <$ignor:ident $d(, $ignore_instance:path)?> )* )* + }, + $d( $rest:tt )* ) => { $d crate::$macro_name!(@inner $runtime; - $d( $system )*; - $d( $parsed_modules $d( <$parsed_generic> )* ),*; - $name: $module::{ $d( $modules $d( <$modules_generic> )* ),* } - $d( - , $rest_name: $rest_module::{ - $d( $rest_modules $d( <$rest_modules_generic> )* ),* - } - )*; + $d( $system )?; + { + $d( $parsed )* + $module $d( <$event_generic $d(, $event_instance)?> )*, + }; + $d( $rest )* ); }; (@inner $runtime:ident; - $d( $system:ident )*; - $d( $parsed_modules:ident $d( <$parsed_generic:ident> )* ),*; - $name:ident: $module:ident::{} - $d(, $rest_name:ident : $rest_module:ident::{ - $d( $rest_modules:ident $d( <$rest_modules_generic:ident> )* ),* - })*; + $d( $system:ident )?; + { $d( $parsed:tt )* }; + $name:ident : $module:ident:: $d( < $module_instance:ident >:: )? { + $ingore:ident $d( <$ignor:ident $d(, $ignore_instance:path)?> )* $d(, $modules:ident $d( <$modules_generic:ident $d(, $modules_instance:path)?> )* )* + }, + $d( $rest:tt )* ) => { $d crate::$macro_name!(@inner $runtime; - $d( $system )*; - $d( $parsed_modules $d( <$parsed_generic> )* ),*; - $d( - $rest_name: $rest_module::{ - $d( $rest_modules $d( <$rest_modules_generic> )* ),* - } - ),*; + $d( $system )?; + { $d( $parsed )* }; + $name: $module:: $d( < $module_instance >:: )? { $d( $modules $d( <$modules_generic $d(, $modules_instance)?> )* ),* }, + $d( $rest )* ); }; (@inner $runtime:ident; - $d( $system:ident )+; - $d( $parsed_modules:ident $d( <$parsed_generic:ident> )* ),*; - ; + $d( $system:ident )?; + { $d( $parsed:tt )* }; + $name:ident: $module:ident:: $d( < $module_instance:ident >:: )? {}, + $d( $rest:tt )* ) => { - $d crate::$macro_outer_name! { - pub enum $macro_enum_name for $runtime where system = $d( $system )* { - $d( - $parsed_modules $d( <$parsed_generic> )*, - )* + $d crate::$macro_name!(@inner + $runtime; + $d( $system )?; + { $d( $parsed )* }; + $d( $rest )* + ); + }; + (@inner + $runtime:ident; + $system:ident; + { $d( $parsed_modules:ident $d( $instance:ident )? $d( <$parsed_generic:ident $d(, $parsed_instance_full_path:path)?> )* ,)* }; + ) => { + $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)?> )*, + )* + } } } } @@ -519,99 +453,71 @@ macro_rules! __decl_all_modules { ( $runtime:ident; ; - $( $parsed_modules:ident :: $parsed_name:ident ),*; - System: $module:ident::{ - Module $(, $modules:ident $( <$modules_generic:ident> )* )* - } - $(, $rest_name:ident : $rest_module:ident::{ - $( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),* - })*; + { $( $parsed:tt )* }; + System: $module:ident::{ Module $(, $modules:ident )* }, + $( $rest:tt )* ) => { $crate::__decl_all_modules!( $runtime; $module; - $( $parsed_modules :: $parsed_name ),*; - $( - $rest_name: $rest_module::{ - $( $rest_modules $( <$rest_modules_generic> )* ),* - } - ),*; + { $( $parsed )* }; + $( $rest )* ); }; ( $runtime:ident; - $( $system:ident )*; - $( $parsed_modules:ident :: $parsed_name:ident ),*; - $name:ident: $module:ident::{ - Module $(, $modules:ident $( <$modules_generic:ident> )* )* - } - $(, $rest_name:ident : $rest_module:ident::{ - $( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),* - })*; + $( $system:ident )?; + { $( $parsed:tt )* }; + $name:ident: $module:ident:: $( < $module_instance:ident >:: )? { Module $(, $modules:ident )* }, + $( $rest:tt )* ) => { $crate::__decl_all_modules!( $runtime; - $( $system )*; - $( $parsed_modules :: $parsed_name, )* $module::$name; - $( - $rest_name: $rest_module::{ - $( $rest_modules $( <$rest_modules_generic> )* ),* - } - ),*; + $( $system )?; + { + $( $parsed )* + $module::$name $(<$module_instance>)?, + }; + $( $rest )* ); }; ( $runtime:ident; - $( $system:ident )*; - $( $parsed_modules:ident :: $parsed_name:ident ),*; - $name:ident: $module:ident::{ - $ingore:ident $( <$ignor:ident> )* $(, $modules:ident $( <$modules_generic:ident> )* )* - } - $(, $rest_name:ident : $rest_module:ident::{ - $( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),* - })*; + $( $system:ident )?; + { $( $parsed:tt )* }; + $name:ident: $module:ident:: $( < $module_instance:ident >:: )? { $ingore:ident $(, $modules:ident )* }, + $( $rest:tt )* ) => { $crate::__decl_all_modules!( $runtime; - $( $system )*; - $( $parsed_modules :: $parsed_name ),*; - $name: $module::{ $( $modules $( <$modules_generic> )* ),* } - $( - , $rest_name: $rest_module::{ - $( $rest_modules $( <$rest_modules_generic> )* ),* - } - )*; + $( $system )?; + { $( $parsed )* }; + $name: $module::{ $( $modules ),* }, + $( $rest )* ); }; ( $runtime:ident; - $( $system:ident )*; - $( $parsed_modules:ident :: $parsed_name:ident ),*; - $name:ident: $module:ident::{} - $(, $rest_name:ident : $rest_module:ident::{ - $( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),* - })*; + $( $system:ident )?; + { $( $parsed:tt )* }; + $name:ident: $module:ident:: $( < $module_instance:ident >:: )? {}, + $( $rest:tt )* ) => { $crate::__decl_all_modules!( $runtime; - $( $system )*; - $( $parsed_modules :: $parsed_name ),*; - $( - $rest_name: $rest_module::{ - $( $rest_modules $( <$rest_modules_generic> )* ),* - } - ),*; + $( $system )?; + { $( $parsed )* }; + $( $rest )* ); }; ( $runtime:ident; $system:ident; - $( $parsed_modules:ident :: $parsed_name:ident ),*; - ; + { $( $parsed_module:ident :: $parsed_name:ident $(<$instance:ident>)? ,)*}; ) => { pub type System = system::Module<$runtime>; $( - pub type $parsed_name = $parsed_modules::Module<$runtime>; + pub type $parsed_name = $parsed_module::Module<$runtime $(, $parsed_module::$instance )?>; )* type AllModules = ( $( $parsed_name, )* ); } @@ -721,84 +627,68 @@ macro_rules! __decl_runtime_metadata { // leading is Module : parse ( $runtime:ident; - $( $parsed_modules:ident { $( $withs:ident )* } )*; + { $( $parsed:tt )* }; $( { leading_module: $( $leading_module:ident )* } )? - $name:ident: $module:ident::{ + $name:ident: $module:ident:: $( < $module_instance:ident >:: )? { Module $( $modules:ident )* } - $( $rest_name:ident : $rest_module:ident::{ - $( $rest_modules:ident )* - })* + $( $rest:tt )* ) => { $crate::__decl_runtime_metadata!( $runtime; - $( $parsed_modules { $( $withs )* } )* $module { $( $( $leading_module )* )? $( $modules )* }; - $( - $rest_name: $rest_module::{ - $( $rest_modules )* - } - )* + { + $( $parsed )* + $module $( < $module_instance > )? { $( $( $leading_module )* )? $( $modules )* } + }; + $( $rest )* ); }; // leading isn't Module : put it in leadings ( $runtime:ident; - $( $parsed_modules:ident { $( $withs:ident )* } )*; + { $( $parsed:tt )* }; $( { leading_module: $( $leading_module:ident )* } )? - $name:ident: $module:ident::{ + $name:ident: $module:ident:: $( < $module_instance:ident >:: )? { $other_module:ident $( $modules:ident )* } - $( $rest_name:ident : $rest_module:ident::{ - $( $rest_modules:ident )* - })* + $( $rest:tt )* ) => { $crate::__decl_runtime_metadata!( $runtime; - $( $parsed_modules { $( $withs )* } )*; + { $( $parsed )* }; { leading_module: $( $( $leading_module )* )? $other_module } - $name: $module::{ + $name: $module:: $( < $module_instance >:: )? { $( $modules )* } - $( - $rest_name: $rest_module::{ - $( $rest_modules )* - } - )* + $( $rest )* ); }; // does not contain Module : skip ( $runtime:ident; - $( $parsed_modules:ident { $( $withs:ident )* } )*; + { $( $parsed:tt )* }; $( { leading_module: $( $leading_module:ident )* } )? - $name:ident: $module:ident::{} - $( $rest_name:ident : $rest_module:ident::{ - $( $rest_modules:ident )* - })* + $name:ident: $module:ident:: $( < $module_instance:ident >:: )? {} + $( $rest:tt )* ) => { $crate::__decl_runtime_metadata!( $runtime; - $( $parsed_modules { $( $withs )* } )*; - $( - $rest_name: $rest_module::{ - $( $rest_modules )* - } - )* + { $( $parsed )* }; + $( $rest )* ); }; // end of decl ( $runtime:ident; - $( $parsed_modules:ident { $( $withs:ident )* } )*; + { $( $parsed_modules:ident $( < $module_instance:ident > )? { $( $withs:ident )* } )* }; ) => { $crate::impl_runtime_metadata!( for $runtime with modules - $( $parsed_modules::Module with $( $withs )* , )* + $( $parsed_modules::Module $( < $module_instance > )? with $( $withs )* , )* ); } } - /// A private macro that generates Log enum for the runtime. See impl_outer_log macro. #[macro_export] #[doc(hidden)] @@ -806,80 +696,65 @@ macro_rules! __decl_outer_log { ( $runtime:ident; $log_internal:ident <$( $log_genarg:ty ),+>; - $( $parsed_modules:ident( $( $parsed_args:ident ),* ) ),*; - $name:ident: $module:ident::{ - Log ( $( $args:ident ),* ) $(, $modules:ident $( ( $( $modules_args:ident )* ) )* )* + { $( $parsed:tt )* }; + $name:ident: $module:ident:: $(<$module_instance:ident>::)? { + Log ( $( $args:ident )* ) $( $modules:ident $( ( $( $modules_args:ident )* ) )* )* } - $(, $rest_name:ident : $rest_module:ident::{ - $( $rest_modules:ident $( ( $( $rest_modules_args:ident )* ) )* ),* - })*; + $( $rest:tt )* ) => { $crate::__decl_outer_log!( $runtime; $log_internal < $( $log_genarg ),* >; - $( $parsed_modules ( $( $parsed_args ),* ), )* $module ( $( $args ),* ); - $( - $rest_name: $rest_module::{ - $( $rest_modules $( ( $( $rest_modules_args ),* ) )* ),* - } - ),*; + { $( $parsed )* $module $(<$module_instance>)? ( $( $args )* )}; + $( $rest )* ); }; ( $runtime:ident; $log_internal:ident <$( $log_genarg:ty ),+>; - $( $parsed_modules:ident( $( $parsed_args:ident ),* ) ),*; - $name:ident: $module:ident::{ - $ignore:ident $( ( $( $args_ignore:ident ),* ) )* - $(, $modules:ident $( ( $( $modules_args:ident ),* ) )* )* + { $( $parsed:tt )* }; + $name:ident: $module:ident:: $(<$module_instance:ident>::)? { + $ignore:ident $( ( $( $args_ignore:ident )* ) )* + $( $modules:ident $( ( $( $modules_args:ident )* ) )* )* } - $(, $rest_name:ident : $rest_module:ident::{ - $( $rest_modules:ident $( ( $( $rest_modules_args:ident )* ) )* ),* - })*; + $( $rest:tt )* ) => { $crate::__decl_outer_log!( $runtime; $log_internal < $( $log_genarg ),* >; - $( $parsed_modules ( $( $parsed_args ),* ) ),*; - $name: $module::{ $( $modules $( ( $( $modules_args ),* ) )* ),* } - $( - , $rest_name: $rest_module::{ - $( $rest_modules $( ( $( $rest_modules_args ),* ) )* ),* - } - )*; + { $( $parsed )* }; + $name: $module:: $(<$module_instance>::)? { $( $modules $( ( $( $modules_args )* ) )* )* } + $( $rest )* ); }; ( $runtime:ident; $log_internal:ident <$( $log_genarg:ty ),+>; - $( $parsed_modules:ident( $( $parsed_args:ident ),* ) ),*; - $name:ident: $module:ident::{} - $(, $rest_name:ident : $rest_module:ident::{ - $( $rest_modules:ident $( ( $( $rest_modules_args:ident )* ) )* ),* - })*; + { $( $parsed:tt )* }; + $name:ident: $module:ident:: $(<$module_instance:ident>::)? {} + $( $rest:tt )* ) => { $crate::__decl_outer_log!( $runtime; $log_internal < $( $log_genarg ),* >; - $( $parsed_modules ( $( $parsed_args ),* ) ),*; - $( - $rest_name: $rest_module::{ - $( $rest_modules $( ( $( $rest_modules_args ),* ) )* ),* - } - ),*; + { $( $parsed )* }; + $( $rest )* ); }; ( $runtime:ident; $log_internal:ident <$( $log_genarg:ty ),+>; - $( $parsed_modules:ident( $( $parsed_args:ident ),* ) ),*; - ; + { $( + $parsed_modules:ident $(< $parsed_instance:ident >)? ( $( $parsed_args:ident )* ) + )* }; ) => { - $crate::runtime_primitives::impl_outer_log!( - pub enum Log($log_internal: DigestItem<$( $log_genarg ),*>) for $runtime { - $( $parsed_modules ( $( $parsed_args ),* ) ),* - } - ); + $crate::paste::item! { + $crate::runtime_primitives::impl_outer_log!( + pub enum Log($log_internal: DigestItem<$( $log_genarg ),*>) for $runtime { + $( [< $parsed_modules $(_ $parsed_instance)? >] $(< $parsed_modules::$parsed_instance >)? ( $( $parsed_args ),* ) ),* + } + ); + } }; } @@ -889,93 +764,57 @@ macro_rules! __decl_outer_log { macro_rules! __decl_outer_config { ( $runtime:ident; - $( $parsed_modules:ident :: $parsed_name:ident $( < $parsed_generic:ident > )* ),*; - $name:ident: $module:ident::{ - Config $(, $modules:ident $( <$modules_generic:ident> )* )* - } - $(, $rest_name:ident : $rest_module:ident::{ - $( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),* - })*; - ) => { - $crate::__decl_outer_config!( - $runtime; - $( $parsed_modules :: $parsed_name $( < $parsed_generic > )*, )* $module::$name; - $( - $rest_name: $rest_module::{ - $( $rest_modules $( <$rest_modules_generic> )* ),* - } - ),*; - ); - }; - ( - $runtime:ident; - $( $parsed_modules:ident :: $parsed_name:ident $( < $parsed_generic:ident > )* ),*; - $name:ident: $module:ident::{ - Config $(, $modules:ident $( <$modules_generic:ident> )* )* - } - $(, $rest_name:ident : $rest_module:ident::{ - $( $rest_modules:ident $( <$rest_modules_generic: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)?> )* )* + }, + $( $rest:tt )* ) => { $crate::__decl_outer_config!( $runtime; - $( $parsed_modules :: $parsed_name $( < $parsed_generic > )*, )* $module::$name; - $( - $rest_name: $rest_module::{ - $( $rest_modules $( <$rest_modules_generic> )* ),* - } - ),*; + { + $( $parsed )* + $module::$name $( $module_instance )? $(<$config_generic $(, $config_instance)?>)?, + }; + $( $rest )* ); }; ( $runtime:ident; - $( $parsed_modules:ident :: $parsed_name:ident $( < $parsed_generic:ident > )* ),*; - $name:ident: $module:ident::{ - $ingore:ident $( <$ignor:ident> )* $(, $modules:ident $( <$modules_generic:ident> )* )* - } - $(, $rest_name:ident : $rest_module:ident::{ - $( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),* - })*; + { $( $parsed:tt )* }; + $name:ident: $module:ident:: $( < $module_instance:ident >:: )? { + $ingore:ident $( <$ignor:ident $(, $ignore_instance:path)?> )* $(, $modules:ident $( <$modules_generic:ident $(, $modules_instance:path)?> )* )* + }, + $( $rest:tt )* ) => { $crate::__decl_outer_config!( $runtime; - $( $parsed_modules :: $parsed_name $( < $parsed_generic > )*),*; - $name: $module::{ $( $modules $( <$modules_generic> )* ),* } - $( - , $rest_name: $rest_module::{ - $( $rest_modules $( <$rest_modules_generic> )* ),* - } - )*; + { $( $parsed )* }; + $name: $module:: $( < $module_instance >:: )? { $( $modules $( <$modules_generic $(, $modules_instance)?> )* ),* }, + $( $rest )* ); }; ( $runtime:ident; - $( $parsed_modules:ident :: $parsed_name:ident $( < $parsed_generic:ident > )* ),*; - $name:ident: $module:ident::{} - $(, $rest_name:ident : $rest_module:ident::{ - $( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),* - })*; + { $( $parsed:tt )* }; + $name:ident: $module:ident:: $( < $module_instance:ident >:: )? {}, + $( $rest:tt )* ) => { $crate::__decl_outer_config!( $runtime; - $( $parsed_modules :: $parsed_name $( < $parsed_generic > )*),*; - $( - $rest_name: $rest_module::{ - $( $rest_modules $( <$rest_modules_generic> )* ),* - } - ),*; + { $( $parsed )* }; + $( $rest )* ); }; ( $runtime:ident; - $( $parsed_modules:ident :: $parsed_name:ident $( < $parsed_generic:ident > )* ),*; - ; + {$( $parsed_modules:ident :: $parsed_name:ident $( $parsed_instance:ident )? $( < $parsed_generic:ident $(, $parsed_instance_full_path:path)? > )* ,)* }; ) => { $crate::paste::item! { $crate::runtime_primitives::impl_outer_config!( pub struct GenesisConfig for $runtime { $( - [< $parsed_name Config >] => $parsed_modules $( < $parsed_generic > )*, + [< $parsed_name Config >] => [< $parsed_modules $( _ $parsed_instance)? >] $( < $parsed_generic $(, $parsed_instance_full_path)? > )*, )* } ); @@ -1097,3 +936,14 @@ macro_rules! __decl_outer_inherent { ); }; } + +#[macro_export] +#[doc(hidden)] +// Those imports are used by event, config, origin and log macros to get access to its inner type +macro_rules! __decl_instance_import { + ( $( $module:ident <$instance:ident> )* ) => { + $crate::paste::item! { + $(use $module as [< $module _ $instance >];)* + } + }; +} diff --git a/srml/support/src/storage/generator.rs b/srml/support/src/storage/generator.rs index e9c38e872c1f1fddd7a7210ccf61275bbc8f5bf0..18bc769d829da24e1787854d69d8b4a329c0b812 100644 --- a/srml/support/src/storage/generator.rs +++ b/srml/support/src/storage/generator.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -48,6 +48,8 @@ use crate::codec; use crate::rstd::vec::Vec; +#[cfg(feature = "std")] +use crate::storage::unhashed::generator::UnhashedStorage; #[doc(hidden)] pub use crate::rstd::borrow::Borrow; #[doc(hidden)] @@ -101,20 +103,19 @@ pub trait Storage { #[cfg(feature = "std")] impl Storage for (crate::rstd::cell::RefCell<&mut sr_primitives::StorageOverlay>, PhantomData) { fn exists(&self, key: &[u8]) -> bool { - self.0.borrow().contains_key(S::hash(key).as_ref()) + UnhashedStorage::exists(self, &S::hash(key)) } fn get(&self, key: &[u8]) -> Option { - self.0.borrow().get(S::hash(key).as_ref()) - .map(|x| codec::Decode::decode(&mut x.as_slice()).expect("Unable to decode expected type.")) + UnhashedStorage::get(self, &S::hash(key)) } fn put(&self, key: &[u8], val: &T) { - self.0.borrow_mut().insert(S::hash(key).to_vec(), codec::Encode::encode(val)); + UnhashedStorage::put(self, &S::hash(key), val) } fn kill(&self, key: &[u8]) { - self.0.borrow_mut().remove(S::hash(key).as_ref()); + UnhashedStorage::kill(self, &S::hash(key)) } } @@ -667,6 +668,12 @@ mod tests { GETMAPU32MYDEF get(map_u32_getter_mydef): map u32 => String = "map".into(); pub PUBGETMAPU32MYDEF get(pub_map_u32_getter_mydef): map u32 => String = "pubmap".into(); + // linked map + LINKEDMAPU32 : linked_map u32 => Option; + pub PUBLINKEDMAPU32MYDEF : linked_map u32 => Option = Some("hello".into()); + GETLINKEDMAPU32 get(linked_map_u32_getter): linked_map u32 => String; + pub PUBGETLINKEDMAPU32MYDEF get(pub_linked_map_u32_getter_mydef): linked_map u32 => String = "pubmap".into(); + COMPLEXTYPE1: ::std::vec::Vec<::Origin>; COMPLEXTYPE2: (Vec)>>, u32); COMPLEXTYPE3: ([u32;25]); @@ -806,8 +813,10 @@ mod tests { StorageFunctionMetadata { name: DecodeDifferent::Encode("MAPU32"), modifier: StorageFunctionModifier::Optional, - ty: StorageFunctionType::Map{ - key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("String") + ty: StorageFunctionType::Map { + key: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("String"), + is_linked: false, }, default: DecodeDifferent::Encode( DefaultByteGetter(&__GetByteStructMAPU32(PhantomData::)) @@ -817,8 +826,10 @@ mod tests { StorageFunctionMetadata { name: DecodeDifferent::Encode("PUBMAPU32"), modifier: StorageFunctionModifier::Optional, - ty: StorageFunctionType::Map{ - key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("String") + ty: StorageFunctionType::Map { + key: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("String"), + is_linked: false, }, default: DecodeDifferent::Encode( DefaultByteGetter(&__GetByteStructPUBMAPU32(PhantomData::)) @@ -828,8 +839,10 @@ mod tests { StorageFunctionMetadata { name: DecodeDifferent::Encode("MAPU32MYDEF"), modifier: StorageFunctionModifier::Optional, - ty: StorageFunctionType::Map{ - key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("String") + ty: StorageFunctionType::Map { + key: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("String"), + is_linked: false, }, default: DecodeDifferent::Encode( DefaultByteGetter(&__GetByteStructMAPU32MYDEF(PhantomData::)) @@ -839,8 +852,10 @@ mod tests { StorageFunctionMetadata { name: DecodeDifferent::Encode("PUBMAPU32MYDEF"), modifier: StorageFunctionModifier::Optional, - ty: StorageFunctionType::Map{ - key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("String") + ty: StorageFunctionType::Map { + key: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("String"), + is_linked: false, }, default: DecodeDifferent::Encode( DefaultByteGetter(&__GetByteStructPUBMAPU32MYDEF(PhantomData::)) @@ -850,8 +865,10 @@ mod tests { StorageFunctionMetadata { name: DecodeDifferent::Encode("GETMAPU32"), modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Map{ - key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("String") + ty: StorageFunctionType::Map { + key: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("String"), + is_linked: false, }, default: DecodeDifferent::Encode( DefaultByteGetter(&__GetByteStructGETMAPU32(PhantomData::)) @@ -861,8 +878,10 @@ mod tests { StorageFunctionMetadata { name: DecodeDifferent::Encode("PUBGETMAPU32"), modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Map{ - key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("String") + ty: StorageFunctionType::Map { + key: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("String"), + is_linked: false, }, default: DecodeDifferent::Encode( DefaultByteGetter(&__GetByteStructPUBGETMAPU32(PhantomData::)) @@ -872,8 +891,10 @@ mod tests { StorageFunctionMetadata { name: DecodeDifferent::Encode("GETMAPU32MYDEF"), modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Map{ - key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("String") + ty: StorageFunctionType::Map { + key: DecodeDifferent::Encode("u32"), + value: DecodeDifferent::Encode("String"), + is_linked: false, }, default: DecodeDifferent::Encode( DefaultByteGetter(&__GetByteStructGETMAPU32MYDEF(PhantomData::)) @@ -883,14 +904,68 @@ mod tests { StorageFunctionMetadata { name: DecodeDifferent::Encode("PUBGETMAPU32MYDEF"), modifier: StorageFunctionModifier::Default, - ty: StorageFunctionType::Map{ - key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("String") + ty: StorageFunctionType::Map { + 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 { + 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 { + 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 { + 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 { + 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, diff --git a/srml/support/src/storage/mod.rs b/srml/support/src/storage/mod.rs index 6b6e68be19aae2d810a51d213f5d61d4d23217d6..b1b8766b9028a466f30d6b7440be20b01a3b84af 100644 --- a/srml/support/src/storage/mod.rs +++ b/srml/support/src/storage/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -23,6 +23,7 @@ use crate::codec::{Codec, Encode, Decode, KeyedVec, Input}; #[macro_use] pub mod generator; +pub mod unhashed; struct IncrementalInput<'a> { key: &'a [u8], @@ -38,86 +39,91 @@ impl<'a> Input for IncrementalInput<'a> { } } - /// Return the value of the item in storage under `key`, or `None` if there is no explicit entry. +struct IncrementalChildInput<'a> { + storage_key: &'a [u8], + key: &'a [u8], + pos: usize, +} + +impl<'a> Input for IncrementalChildInput<'a> { + fn read(&mut self, into: &mut [u8]) -> usize { + let len = runtime_io::read_child_storage(self.storage_key, self.key, into, self.pos).unwrap_or(0); + let read = crate::rstd::cmp::min(len, into.len()); + self.pos += read; + read + } +} + + +/// Return the value of the item in storage under `key`, or `None` if there is no explicit entry. pub fn get(key: &[u8]) -> Option { - let key = twox_128(key); - runtime_io::read_storage(&key[..], &mut [0; 0][..], 0).map(|_| { - let mut input = IncrementalInput { - key: &key[..], - pos: 0, - }; - Decode::decode(&mut input).expect("storage is not null, therefore must be a valid type") - }) + unhashed::get(&twox_128(key)) } /// Return the value of the item in storage under `key`, or the type's default if there is no /// explicit entry. pub fn get_or_default(key: &[u8]) -> T { - get(key).unwrap_or_else(Default::default) + unhashed::get_or_default(&twox_128(key)) } /// Return the value of the item in storage under `key`, or `default_value` if there is no /// explicit entry. pub fn get_or(key: &[u8], default_value: T) -> T { - get(key).unwrap_or(default_value) + unhashed::get_or(&twox_128(key), default_value) } /// Return the value of the item in storage under `key`, or `default_value()` if there is no /// explicit entry. pub fn get_or_else T>(key: &[u8], default_value: F) -> T { - get(key).unwrap_or_else(default_value) + unhashed::get_or_else(&twox_128(key), default_value) } /// Put `value` in storage under `key`. pub fn put(key: &[u8], value: &T) { - value.using_encoded(|slice| runtime_io::set_storage(&twox_128(key)[..], slice)); + unhashed::put(&twox_128(key), value) } /// Remove `key` from storage, returning its value if it had an explicit entry or `None` otherwise. pub fn take(key: &[u8]) -> Option { - let r = get(key); - if r.is_some() { - kill(key); - } - r + unhashed::take(&twox_128(key)) } /// Remove `key` from storage, returning its value, or, if there was no explicit entry in storage, /// the default for its type. pub fn take_or_default(key: &[u8]) -> T { - take(key).unwrap_or_else(Default::default) + unhashed::take_or_default(&twox_128(key)) } /// Return the value of the item in storage under `key`, or `default_value` if there is no /// explicit entry. Ensure there is no explicit entry on return. pub fn take_or(key: &[u8], default_value: T) -> T { - take(key).unwrap_or(default_value) + unhashed::take_or(&twox_128(key), default_value) } /// Return the value of the item in storage under `key`, or `default_value()` if there is no /// explicit entry. Ensure there is no explicit entry on return. pub fn take_or_else T>(key: &[u8], default_value: F) -> T { - take(key).unwrap_or_else(default_value) + unhashed::take_or_else(&twox_128(key), default_value) } /// Check to see if `key` has an explicit entry in storage. pub fn exists(key: &[u8]) -> bool { - runtime_io::exists_storage(&twox_128(key)[..]) + unhashed::exists(&twox_128(key)) } /// Ensure `key` has no explicit entry in storage. pub fn kill(key: &[u8]) { - runtime_io::clear_storage(&twox_128(key)[..]); + unhashed::kill(&twox_128(key)) } /// Get a Vec of bytes from storage. pub fn get_raw(key: &[u8]) -> Option> { - runtime_io::storage(&twox_128(key)[..]) + unhashed::get_raw(&twox_128(key)) } /// Put a raw byte slice into storage. pub fn put_raw(key: &[u8], value: &[u8]) { - runtime_io::set_storage(&twox_128(key)[..], value) + unhashed::put_raw(&twox_128(key), value) } /// The underlying runtime storage. @@ -125,27 +131,58 @@ pub struct RuntimeStorage; impl crate::GenericStorage for RuntimeStorage { fn exists(&self, key: &[u8]) -> bool { - super::storage::exists(key) + exists(key) } /// Load the bytes of a key from storage. Can panic if the type is incorrect. fn get(&self, key: &[u8]) -> Option { - super::storage::get(key) + get(key) } /// Put a value in under a key. fn put(&self, key: &[u8], val: &T) { - super::storage::put(key, val) + put(key, val) } /// Remove the bytes of a key from storage. fn kill(&self, key: &[u8]) { - super::storage::kill(key) + kill(key) } /// Take a value from storage, deleting it after reading. fn take(&self, key: &[u8]) -> Option { - super::storage::take(key) + take(key) + } +} + +impl crate::GenericUnhashedStorage for RuntimeStorage { + fn exists(&self, key: &[u8]) -> bool { + unhashed::exists(key) + } + + /// Load the bytes of a key from storage. Can panic if the type is incorrect. + fn get(&self, key: &[u8]) -> Option { + unhashed::get(key) + } + + /// Put a value in under a key. + fn put(&self, key: &[u8], val: &T) { + unhashed::put(key, val) + } + + /// Remove the bytes of a key from storage. + fn kill(&self, key: &[u8]) { + unhashed::kill(key) + } + + /// Remove the bytes of a key from storage. + fn kill_prefix(&self, prefix: &[u8]) { + unhashed::kill_prefix(prefix) + } + + /// Take a value from storage, deleting it after reading. + fn take(&self, key: &[u8]) -> Option { + unhashed::take(key) } } @@ -358,6 +395,109 @@ impl EnumerableStorageMap for U where U: generator: } } +/// An implementation of a map with a two keys. +/// +/// It provides an important ability to efficiently remove all entries +/// that have a common first key. +/// +/// # Mapping of keys to a storage path +/// +/// The storage key (i.e. the key under which the `Value` will be stored) is created from two parts. +/// The first part is a hash of a concatenation of the `PREFIX` and `Key1`. And the second part +/// is a hash of a `Key2`. +/// +/// /!\ be careful while choosing the Hash, indeed malicious could craft second keys to lower the trie. +pub trait StorageDoubleMap { + /// The type that get/take returns. + type Query; + + /// Get the prefix key in storage. + fn prefix() -> &'static [u8]; + + /// Get the storage key used to fetch a value corresponding to a specific key. + fn key_for, KArg2: Borrow>(k1: KArg1, k2: KArg2) -> Vec; + + /// Get the storage prefix used to fetch keys corresponding to a specific key1. + fn prefix_for>(k1: KArg1) -> Vec; + + /// true if the value is defined in storage. + fn exists, KArg2: Borrow>(k1: KArg1, k2: KArg2) -> bool; + + /// Load the value associated with the given key from the map. + fn get, KArg2: Borrow>(k1: KArg1, k2: KArg2) -> Self::Query; + + /// Take the value under a key. + fn take, KArg2: Borrow>(k1: KArg1, k2: KArg2) -> Self::Query; + + /// Store a value to be associated with the given key from the map. + fn insert, KArg2: Borrow, VArg: Borrow>(k1: KArg1, k2: KArg2, val: VArg); + + /// Remove the value under a key. + fn remove, KArg2: Borrow>(k1: KArg1, k2: KArg2); + + /// Removes all entries that shares the `k1` as the first key. + fn remove_prefix>(k1: KArg1); + + /// Mutate the value under a key. + fn mutate(k1: KArg1, k2: KArg2, f: F) -> R + where + KArg1: Borrow, + KArg2: Borrow, + F: FnOnce(&mut Self::Query) -> R; +} + +impl StorageDoubleMap for U +where + U: unhashed::generator::StorageDoubleMap +{ + type Query = U::Query; + + fn prefix() -> &'static [u8] { + >::prefix() + } + + fn key_for, KArg2: Borrow>(k1: KArg1, k2: KArg2) -> Vec { + >::key_for(k1.borrow(), k2.borrow()) + } + + fn prefix_for>(k1: KArg1) -> Vec { + >::prefix_for(k1.borrow()) + } + + fn exists, KArg2: Borrow>(k1: KArg1, k2: KArg2) -> bool { + U::exists(k1.borrow(), k2.borrow(), &RuntimeStorage) + } + + fn get, KArg2: Borrow>(k1: KArg1, k2: KArg2) -> Self::Query { + U::get(k1.borrow(), k2.borrow(), &RuntimeStorage) + } + + fn take, KArg2: Borrow>(k1: KArg1, k2: KArg2) -> Self::Query { + U::take(k1.borrow(), k2.borrow(), &RuntimeStorage) + } + + fn insert, KArg2: Borrow, VArg: Borrow>(k1: KArg1, k2: KArg2, val: VArg) { + U::insert(k1.borrow(), k2.borrow(), val.borrow(), &RuntimeStorage) + } + + fn remove, KArg2: Borrow>(k1: KArg1, k2: KArg2) { + U::remove(k1.borrow(), k2.borrow(), &RuntimeStorage) + } + + fn remove_prefix>(k1: KArg1) { + U::remove_prefix(k1.borrow(), &RuntimeStorage) + } + + fn mutate(k1: KArg1, k2: KArg2, f: F) -> R + where + KArg1: Borrow, + KArg2: Borrow, + F: FnOnce(&mut Self::Query) -> R + { + U::mutate(k1.borrow(), k2.borrow(), f, &RuntimeStorage) + } +} + /// A trait to conveniently store a vector of storable data. pub trait StorageVec { type Item: Default + Sized + Codec; @@ -417,14 +557,19 @@ pub trait StorageVec { } } -pub mod unhashed { - use crate::rstd::borrow::Borrow; - use super::{runtime_io, Codec, Decode, KeyedVec, Vec, IncrementalInput}; +/// child storage NOTE could replace unhashed by having only one kind of storage (root being null storage +/// key (storage_key can become Option<&[u8]>). +/// This module is a currently only a variant of unhashed with additional `storage_key`. +/// Note that `storage_key` must be unique and strong (strong in the sense of being long enough to +/// avoid collision from a resistant hash function (which unique implies)). +pub mod child { + use super::{runtime_io, Codec, Decode, Vec, IncrementalChildInput}; /// Return the value of the item in storage under `key`, or `None` if there is no explicit entry. - pub fn get(key: &[u8]) -> Option { - runtime_io::read_storage(key, &mut [0; 0][..], 0).map(|_| { - let mut input = IncrementalInput { + pub fn get(storage_key: &[u8], key: &[u8]) -> Option { + runtime_io::read_child_storage(storage_key, key, &mut [0; 0][..], 0).map(|_| { + let mut input = IncrementalChildInput { + storage_key, key, pos: 0, }; @@ -434,130 +579,80 @@ pub mod unhashed { /// Return the value of the item in storage under `key`, or the type's default if there is no /// explicit entry. - pub fn get_or_default(key: &[u8]) -> T { - get(key).unwrap_or_else(Default::default) + pub fn get_or_default(storage_key: &[u8], key: &[u8]) -> T { + get(storage_key, key).unwrap_or_else(Default::default) } /// Return the value of the item in storage under `key`, or `default_value` if there is no /// explicit entry. - pub fn get_or(key: &[u8], default_value: T) -> T { - get(key).unwrap_or(default_value) + pub fn get_or(storage_key: &[u8], key: &[u8], default_value: T) -> T { + get(storage_key, key).unwrap_or(default_value) } /// Return the value of the item in storage under `key`, or `default_value()` if there is no /// explicit entry. - pub fn get_or_else T>(key: &[u8], default_value: F) -> T { - get(key).unwrap_or_else(default_value) + pub fn get_or_else T>(storage_key: &[u8], key: &[u8], default_value: F) -> T { + get(storage_key, key).unwrap_or_else(default_value) } /// Put `value` in storage under `key`. - pub fn put(key: &[u8], value: &T) { - value.using_encoded(|slice| runtime_io::set_storage(key, slice)); + pub fn put(storage_key: &[u8], key: &[u8], value: &T) { + value.using_encoded(|slice| runtime_io::set_child_storage(storage_key, key, slice)); } /// Remove `key` from storage, returning its value if it had an explicit entry or `None` otherwise. - pub fn take(key: &[u8]) -> Option { - let r = get(key); + pub fn take(storage_key: &[u8], key: &[u8]) -> Option { + let r = get(storage_key, key); if r.is_some() { - kill(key); + kill(storage_key, key); } r } /// Remove `key` from storage, returning its value, or, if there was no explicit entry in storage, /// the default for its type. - pub fn take_or_default(key: &[u8]) -> T { - take(key).unwrap_or_else(Default::default) + pub fn take_or_default(storage_key: &[u8], key: &[u8]) -> T { + take(storage_key, key).unwrap_or_else(Default::default) } /// Return the value of the item in storage under `key`, or `default_value` if there is no /// explicit entry. Ensure there is no explicit entry on return. - pub fn take_or(key: &[u8], default_value: T) -> T { - take(key).unwrap_or(default_value) + pub fn take_or(storage_key: &[u8],key: &[u8], default_value: T) -> T { + take(storage_key, key).unwrap_or(default_value) } /// Return the value of the item in storage under `key`, or `default_value()` if there is no /// explicit entry. Ensure there is no explicit entry on return. - pub fn take_or_else T>(key: &[u8], default_value: F) -> T { - take(key).unwrap_or_else(default_value) + pub fn take_or_else T>(storage_key: &[u8], key: &[u8], default_value: F) -> T { + take(storage_key, key).unwrap_or_else(default_value) } /// Check to see if `key` has an explicit entry in storage. - pub fn exists(key: &[u8]) -> bool { - runtime_io::read_storage(key, &mut [0;0][..], 0).is_some() + pub fn exists(storage_key: &[u8], key: &[u8]) -> bool { + runtime_io::read_child_storage(storage_key, key, &mut [0;0][..], 0).is_some() } - /// Ensure `key` has no explicit entry in storage. - pub fn kill(key: &[u8]) { - runtime_io::clear_storage(key); + /// Remove all `storage_key` key/values + pub fn kill_storage(storage_key: &[u8]) { + runtime_io::kill_child_storage(storage_key) } - /// Ensure keys with the given `prefix` have no entries in storage. - pub fn kill_prefix(prefix: &[u8]) { - runtime_io::clear_prefix(prefix); + /// Ensure `key` has no explicit entry in storage. + pub fn kill(storage_key: &[u8], key: &[u8]) { + runtime_io::clear_child_storage(storage_key, key); } /// Get a Vec of bytes from storage. - pub fn get_raw(key: &[u8]) -> Option> { - runtime_io::storage(key) + pub fn get_raw(storage_key: &[u8], key: &[u8]) -> Option> { + runtime_io::child_storage(storage_key, key) } /// Put a raw byte slice into storage. - pub fn put_raw(key: &[u8], value: &[u8]) { - runtime_io::set_storage(key, value) + pub fn put_raw(storage_key: &[u8], key: &[u8], value: &[u8]) { + runtime_io::set_child_storage(storage_key, key, value) } - /// A trait to conveniently store a vector of storable data. - pub trait StorageVec { - type Item: Default + Sized + Codec; - const PREFIX: &'static [u8]; - - /// Get the current set of items. - fn items() -> Vec { - (0..Self::count()).into_iter().map(Self::item).collect() - } - - /// Set the current set of items. - fn set_items(items: I) - where - I: IntoIterator, - T: Borrow, - { - let mut count: u32 = 0; - - for i in items.into_iter() { - put(&count.to_keyed_vec(Self::PREFIX), i.borrow()); - count = count.checked_add(1).expect("exceeded runtime storage capacity"); - } - - Self::set_count(count); - } - - fn set_item(index: u32, item: &Self::Item) { - if index < Self::count() { - put(&index.to_keyed_vec(Self::PREFIX), item); - } - } - - fn clear_item(index: u32) { - if index < Self::count() { - kill(&index.to_keyed_vec(Self::PREFIX)); - } - } - - fn item(index: u32) -> Self::Item { - get_or_default(&index.to_keyed_vec(Self::PREFIX)) - } - - fn set_count(count: u32) { - (count..Self::count()).for_each(Self::clear_item); - put(&b"len".to_keyed_vec(Self::PREFIX), &count); - } - - fn count() -> u32 { - get_or_default(&b"len".to_keyed_vec(Self::PREFIX)) - } - } + pub use super::unhashed::StorageVec; } #[cfg(test)] diff --git a/srml/support/src/storage/unhashed/generator.rs b/srml/support/src/storage/unhashed/generator.rs new file mode 100644 index 0000000000000000000000000000000000000000..2b046013bb9445da68348ca10cd0de2cdfe6419c --- /dev/null +++ b/srml/support/src/storage/unhashed/generator.rs @@ -0,0 +1,144 @@ +// 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 crate::codec; +use runtime_io::twox_128; +use crate::rstd::vec::Vec; + +/// Abstraction around storage with unhashed access. +pub trait UnhashedStorage { + /// true if the key exists in storage. + fn exists(&self, key: &[u8]) -> bool; + + /// Load the bytes of a key from storage. Can panic if the type is incorrect. + fn get(&self, key: &[u8]) -> Option; + + /// Load the bytes of a key from storage. Can panic if the type is incorrect. Will panic if + /// it's not there. + fn require(&self, key: &[u8]) -> T { self.get(key).expect("Required values must be in storage") } + + /// Load the bytes of a key from storage. Can panic if the type is incorrect. The type's + /// default is returned if it's not there. + fn get_or_default(&self, key: &[u8]) -> T { self.get(key).unwrap_or_default() } + + /// Put a value in under a key. + fn put(&self, key: &[u8], val: &T); + + /// Remove the bytes of a key from storage. + fn kill(&self, key: &[u8]); + + /// Remove the bytes of a key from storage. + fn kill_prefix(&self, prefix: &[u8]); + + /// Take a value from storage, deleting it after reading. + fn take(&self, key: &[u8]) -> Option { + let value = self.get(key); + self.kill(key); + value + } + + /// Take a value from storage, deleting it after reading. + fn take_or_panic(&self, key: &[u8]) -> T { self.take(key).expect("Required values must be in storage") } + + /// Take a value from storage, deleting it after reading. + fn take_or_default(&self, key: &[u8]) -> T { self.take(key).unwrap_or_default() } +} + +// We use a construct like this during when genesis storage is being built. +#[cfg(feature = "std")] +impl UnhashedStorage for (crate::rstd::cell::RefCell<&mut sr_primitives::StorageOverlay>, H) { + fn exists(&self, key: &[u8]) -> bool { + self.0.borrow().contains_key(key) + } + + fn get(&self, key: &[u8]) -> Option { + self.0.borrow().get(key) + .map(|x| codec::Decode::decode(&mut x.as_slice()).expect("Unable to decode expected type.")) + } + + fn put(&self, key: &[u8], val: &T) { + self.0.borrow_mut().insert(key.to_vec(), codec::Encode::encode(val)); + } + + fn kill(&self, key: &[u8]) { + self.0.borrow_mut().remove(key); + } + + fn kill_prefix(&self, prefix: &[u8]) { + self.0.borrow_mut().retain(|key, _| { + !key.starts_with(prefix) + }) + } +} + +/// An implementation of a map with a two keys. +/// +/// It provides an important ability to efficiently remove all entries +/// that have a common first key. +/// +/// # Mapping of keys to a storage path +/// +/// The storage key (i.e. the key under which the `Value` will be stored) is created from two parts. +/// The first part is a hash of a concatenation of the `PREFIX` and `Key1`. And the second part +/// is a hash of a `Key2`. +/// +/// /!\ be careful while choosing the Hash, indeed malicious could craft second keys to lower the trie. +pub trait StorageDoubleMap { + /// The type that get/take returns. + type Query; + + /// Get the prefix key in storage. + fn prefix() -> &'static [u8]; + + /// Get the storage key used to fetch a value corresponding to a specific key. + fn key_for(k1: &K1, k2: &K2) -> Vec; + + /// Get the storage prefix used to fetch keys corresponding to a specific key1. + fn prefix_for(k1: &K1) -> Vec { + let mut key = Self::prefix().to_vec(); + codec::Encode::encode_to(k1, &mut key); + twox_128(&key).to_vec() + } + + /// true if the value is defined in storage. + fn exists(k1: &K1, k2: &K2, storage: &S) -> bool { + storage.exists(&Self::key_for(k1, k2)) + } + + /// Load the value associated with the given key from the map. + fn get(k1: &K1, k2: &K2, storage: &S) -> Self::Query; + + /// Take the value under a key. + fn take(k1: &K1, k2: &K2, storage: &S) -> Self::Query; + + /// Store a value to be associated with the given key from the map. + fn insert(k1: &K1, k2: &K2, val: &V, storage: &S) { + storage.put(&Self::key_for(k1, k2), val); + } + + /// Remove the value under a key. + fn remove(k1: &K1, k2: &K2, storage: &S) { + storage.kill(&Self::key_for(k1, k2)); + } + + /// Removes all entries that shares the `k1` as the first key. + fn remove_prefix(k1: &K1, storage: &S) { + storage.kill_prefix(&Self::prefix_for(k1)); + } + + /// Mutate the value under a key. + fn mutate R, S: UnhashedStorage>(k1: &K1, k2: &K2, f: F, storage: &S) -> R; +} diff --git a/srml/support/src/storage/unhashed/mod.rs b/srml/support/src/storage/unhashed/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..225c6756b80de3788fa7faeda73533a78899e41b --- /dev/null +++ b/srml/support/src/storage/unhashed/mod.rs @@ -0,0 +1,160 @@ +// 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 . + +//! Operation on unhashed runtime storage + +use crate::rstd::borrow::Borrow; +use super::{runtime_io, Codec, Encode, Decode, KeyedVec, Vec, IncrementalInput}; + +pub mod generator; + +/// Return the value of the item in storage under `key`, or `None` if there is no explicit entry. +pub fn get(key: &[u8]) -> Option { + runtime_io::read_storage(key, &mut [0; 0][..], 0).map(|_| { + let mut input = IncrementalInput { + key, + pos: 0, + }; + Decode::decode(&mut input).expect("storage is not null, therefore must be a valid type") + }) +} + +/// Return the value of the item in storage under `key`, or the type's default if there is no +/// explicit entry. +pub fn get_or_default(key: &[u8]) -> T { + get(key).unwrap_or_else(Default::default) +} + +/// Return the value of the item in storage under `key`, or `default_value` if there is no +/// explicit entry. +pub fn get_or(key: &[u8], default_value: T) -> T { + get(key).unwrap_or(default_value) +} + +/// Return the value of the item in storage under `key`, or `default_value()` if there is no +/// explicit entry. +pub fn get_or_else T>(key: &[u8], default_value: F) -> T { + get(key).unwrap_or_else(default_value) +} + +/// Put `value` in storage under `key`. +pub fn put(key: &[u8], value: &T) { + value.using_encoded(|slice| runtime_io::set_storage(key, slice)); +} + +/// Remove `key` from storage, returning its value if it had an explicit entry or `None` otherwise. +pub fn take(key: &[u8]) -> Option { + let r = get(key); + if r.is_some() { + kill(key); + } + r +} + +/// Remove `key` from storage, returning its value, or, if there was no explicit entry in storage, +/// the default for its type. +pub fn take_or_default(key: &[u8]) -> T { + take(key).unwrap_or_else(Default::default) +} + +/// Return the value of the item in storage under `key`, or `default_value` if there is no +/// explicit entry. Ensure there is no explicit entry on return. +pub fn take_or(key: &[u8], default_value: T) -> T { + take(key).unwrap_or(default_value) +} + +/// Return the value of the item in storage under `key`, or `default_value()` if there is no +/// explicit entry. Ensure there is no explicit entry on return. +pub fn take_or_else T>(key: &[u8], default_value: F) -> T { + take(key).unwrap_or_else(default_value) +} + +/// Check to see if `key` has an explicit entry in storage. +pub fn exists(key: &[u8]) -> bool { + runtime_io::read_storage(key, &mut [0;0][..], 0).is_some() +} + +/// Ensure `key` has no explicit entry in storage. +pub fn kill(key: &[u8]) { + runtime_io::clear_storage(key); +} + +/// Ensure keys with the given `prefix` have no entries in storage. +pub fn kill_prefix(prefix: &[u8]) { + runtime_io::clear_prefix(prefix); +} + +/// Get a Vec of bytes from storage. +pub fn get_raw(key: &[u8]) -> Option> { + runtime_io::storage(key) +} + +/// Put a raw byte slice into storage. +pub fn put_raw(key: &[u8], value: &[u8]) { + runtime_io::set_storage(key, value) +} + +/// A trait to conveniently store a vector of storable data. +pub trait StorageVec { + type Item: Default + Sized + Codec; + const PREFIX: &'static [u8]; + + /// Get the current set of items. + fn items() -> Vec { + (0..Self::count()).into_iter().map(Self::item).collect() + } + + /// Set the current set of items. + fn set_items(items: I) + where + I: IntoIterator, + T: Borrow, + { + let mut count: u32 = 0; + + for i in items.into_iter() { + put(&count.to_keyed_vec(Self::PREFIX), i.borrow()); + count = count.checked_add(1).expect("exceeded runtime storage capacity"); + } + + Self::set_count(count); + } + + fn set_item(index: u32, item: &Self::Item) { + if index < Self::count() { + put(&index.to_keyed_vec(Self::PREFIX), item); + } + } + + fn clear_item(index: u32) { + if index < Self::count() { + kill(&index.to_keyed_vec(Self::PREFIX)); + } + } + + fn item(index: u32) -> Self::Item { + get_or_default(&index.to_keyed_vec(Self::PREFIX)) + } + + fn set_count(count: u32) { + (count..Self::count()).for_each(Self::clear_item); + put(&b"len".to_keyed_vec(Self::PREFIX), &count); + } + + fn count() -> u32 { + get_or_default(&b"len".to_keyed_vec(Self::PREFIX)) + } +} diff --git a/srml/support/src/traits.rs b/srml/support/src/traits.rs index 873f61e9611b715b4ce507e2abd18efe108a3430..6f0435a77a01d36160fa9ace1e4156bb8765e373 100644 --- a/srml/support/src/traits.rs +++ b/srml/support/src/traits.rs @@ -17,8 +17,10 @@ //! Traits for SRML use crate::rstd::result; -use crate::codec::Codec; -use crate::runtime_primitives::traits::{MaybeSerializeDebug, SimpleArithmetic, As}; +use crate::codec::{Codec, Encode, Decode}; +use crate::runtime_primitives::traits::{ + MaybeSerializeDebug, SimpleArithmetic, As +}; /// The account with the given id was killed. pub trait OnFreeBalanceZero { @@ -51,137 +53,422 @@ impl OnDilution for () { fn on_dilution(_minted: Balance, _portion: Balance) {} } -/// Determinator for whether a given account is able to transfer balance. -pub trait EnsureAccountLiquid { - /// Returns `Ok` iff the account is able to transfer funds normally. `Err(...)` - /// with the reason why not otherwise. - fn ensure_account_liquid(who: &AccountId) -> result::Result<(), &'static str>; -} -impl< - AccountId, - X: EnsureAccountLiquid, - Y: EnsureAccountLiquid, -> EnsureAccountLiquid for (X, Y) { - fn ensure_account_liquid(who: &AccountId) -> result::Result<(), &'static str> { - X::ensure_account_liquid(who)?; - Y::ensure_account_liquid(who) - } -} -impl EnsureAccountLiquid for () { - fn ensure_account_liquid(_who: &AccountId) -> result::Result<(), &'static str> { Ok(()) } -} - /// Outcome of a balance update. pub enum UpdateBalanceOutcome { /// Account balance was simply updated. Updated, - /// The update has led to killing of the account. + /// The update led to killing the account. AccountKilled, } -pub trait ArithmeticType { - type Type: SimpleArithmetic + As + As + Codec + Copy + MaybeSerializeDebug + Default; +/// Simple trait designed for hooking into a transaction payment. +/// +/// It operates over a single generic `AccountId` type. +pub trait MakePayment { + /// Make transaction payment from `who` for an extrinsic of encoded length + /// `encoded_len` bytes. Return `Ok` iff the payment was successful. + fn make_payment(who: &AccountId, encoded_len: usize) -> Result<(), &'static str>; +} + +impl MakePayment for () { + fn make_payment(_: &T, _: usize) -> Result<(), &'static str> { Ok(()) } +} + +/// Handler for when some currency "account" decreased in balance for +/// some reason. +/// +/// The only reason at present for an increase would be for validator rewards, but +/// there may be other reasons in the future or for other chains. +/// +/// Reasons for decreases include: +/// +/// - Someone got slashed. +/// - Someone paid for a transaction to be included. +pub trait OnUnbalanced { + /// Handler for some imbalance. Infallible. + fn on_unbalanced(amount: Imbalance); +} + +impl OnUnbalanced for () { + fn on_unbalanced(amount: Imbalance) { drop(amount); } +} + +/// Simple boolean for whether an account needs to be kept in existence. +#[derive(Copy, Clone, Eq, PartialEq)] +pub enum ExistenceRequirement { + /// Operation must not result in the account going out of existence. + KeepAlive, + /// Operation may result in account going out of existence. + AllowDeath, +} + +/// A trait for a not-quite Linear Type that tracks an imbalance. +/// +/// Functions that alter account balances return an object of this trait to +/// express how much account balances have been altered in aggregate. If +/// dropped, the currency system will take some default steps to deal with +/// the imbalance (`balances` module simply reduces or increases its +/// total issuance). Your module should generally handle it in some way, +/// good practice is to do so in a configurable manner using an +/// `OnUnbalanced` type for each situation in which your module needs to +/// handle an imbalance. +/// +/// Imbalances can either be Positive (funds were added somewhere without +/// being subtracted elsewhere - e.g. a reward) or Negative (funds deducted +/// somewhere without an equal and opposite addition - e.g. a slash or +/// system fee payment). +/// +/// Since they are unsigned, the actual type is always Positive or Negative. +/// The trait makes no distinction except to define the `Opposite` type. +/// +/// New instances of zero value can be created (`zero`) and destroyed +/// (`drop_zero`). +/// +/// Existing instances can be `split` and merged either consuming `self` with +/// `merge` or mutating `self` with `subsume`. If the target is an `Option`, +/// then `maybe_merge` and `maybe_subsume` might work better. Instances can +/// also be `offset` with an `Opposite` that is less than or equal to in value. +/// +/// You can always retrieve the raw balance value using `peek`. +#[must_use] +pub trait Imbalance: Sized { + /// The oppositely imbalanced type. They come in pairs. + type Opposite: Imbalance; + + /// The zero imbalance. Can be destroyed with `drop_zero`. + fn zero() -> Self; + + /// Drop an instance cleanly. Only works if its `value()` is zero. + fn drop_zero(self) -> Result<(), Self>; + + /// Consume `self` and return two independent instances; the first + /// is guaranteed to be at most `amount` and the second will be the remainder. + fn split(self, amount: Balance) -> (Self, Self); + + /// Consume `self` and an `other` to return a new instance that combines + /// both. + fn merge(self, other: Self) -> Self; + + /// Consume `self` and maybe an `other` to return a new instance that combines + /// both. + fn maybe_merge(self, other: Option) -> Self { + if let Some(o) = other { + self.merge(o) + } else { + self + } + } + + /// Consume an `other` to mutate `self` into a new instance that combines + /// both. + fn subsume(&mut self, other: Self); + + /// Maybe consume an `other` to mutate `self` into a new instance that combines + /// both. + fn maybe_subsume(&mut self, other: Option) { + if let Some(o) = other { + self.subsume(o) + } + } + + /// Consume self and along with an opposite counterpart to return + /// a combined result. + /// + /// Returns `Ok` along with a new instance of `Self` if this instance has a + /// greater value than the `other`. Otherwise returns `Err` with an instance of + /// the `Opposite`. In both cases the value represents the combination of `self` + /// and `other`. + fn offset(self, other: Self::Opposite) -> Result; + + /// The raw value of self. + fn peek(&self) -> Balance; +} + +/// Either a positive or a negative imbalance. +pub enum SignedImbalance>{ + /// A positive imbalance (funds have been created but none destroyed). + Positive(P), + /// A negative imbalance (funds have been destroyed but none created). + Negative(P::Opposite), +} + +impl< + P: Imbalance, + N: Imbalance, + B: SimpleArithmetic + As + As + Codec + Copy + MaybeSerializeDebug + Default, +> SignedImbalance { + pub fn zero() -> Self { + SignedImbalance::Positive(P::zero()) + } + + pub fn drop_zero(self) -> Result<(), Self> { + match self { + SignedImbalance::Positive(x) => x.drop_zero().map_err(SignedImbalance::Positive), + SignedImbalance::Negative(x) => x.drop_zero().map_err(SignedImbalance::Negative), + } + } + + /// Consume `self` and an `other` to return a new instance that combines + /// both. + pub fn merge(self, other: Self) -> Self { + match (self, other) { + (SignedImbalance::Positive(one), SignedImbalance::Positive(other)) => + SignedImbalance::Positive(one.merge(other)), + (SignedImbalance::Negative(one), SignedImbalance::Negative(other)) => + SignedImbalance::Negative(one.merge(other)), + (SignedImbalance::Positive(one), SignedImbalance::Negative(other)) => + if one.peek() > other.peek() { + SignedImbalance::Positive(one.offset(other).ok().unwrap_or_else(P::zero)) + } else { + SignedImbalance::Negative(other.offset(one).ok().unwrap_or_else(N::zero)) + }, + (one, other) => other.merge(one), + } + } } /// Abstraction over a fungible assets system. pub trait Currency { /// The balance of an account. - type Balance; + type Balance: SimpleArithmetic + As + As + Codec + Copy + MaybeSerializeDebug + Default; + + /// The opaque token type for an imbalance. This is returned by unbalanced operations + /// and must be dealt with. It may be dropped but cannot be cloned. + type PositiveImbalance: Imbalance; + + /// The opaque token type for an imbalance. This is returned by unbalanced operations + /// and must be dealt with. It may be dropped but cannot be cloned. + type NegativeImbalance: Imbalance; // PUBLIC IMMUTABLES /// The combined balance of `who`. fn total_balance(who: &AccountId) -> Self::Balance; - /// Some result as `slash(who, value)` (but without the side-effects) assuming there are no + /// Same result as `slash(who, value)` (but without the side-effects) assuming there are no /// balance changes in the meantime and only the reserved balance is not taken into account. fn can_slash(who: &AccountId, value: Self::Balance) -> bool; - /// Same result as `reserve(who, value)` (but without the side-effects) assuming there - /// are no balance changes in the meantime. - fn can_reserve(who: &AccountId, value: Self::Balance) -> bool; + /// The total amount of issuance in the system. + fn total_issuance() -> Self::Balance; - /// The total amount of stake on the system. - fn total_issuance() -> Self:: Balance; + /// The minimum balance any single account may have. This is equivalent to the `Balances` module's + /// `ExistentialDeposit`. + fn minimum_balance() -> Self::Balance; /// The 'free' balance of a given account. /// - /// This is the only balance that matters in terms of most operations on tokens. It is - /// alone used to determine the balance when in the contract execution environment. When this + /// This is the only balance that matters in terms of most operations on tokens. It alone + /// is used to determine the balance when in the contract execution environment. When this /// balance falls below the value of `ExistentialDeposit`, then the 'current account' is - /// deleted: specifically `FreeBalance`. Furthermore, `OnFreeBalanceZero` callback - /// is invoked, giving a chance to external modules to cleanup data associated with + /// deleted: specifically `FreeBalance`. Further, the `OnFreeBalanceZero` callback + /// is invoked, giving a chance to external modules to clean up data associated with /// the deleted account. /// /// `system::AccountNonce` is also deleted if `ReservedBalance` is also zero (it also gets /// collapsed to zero if it ever becomes less than `ExistentialDeposit`. fn free_balance(who: &AccountId) -> Self::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. + /// Returns `Ok` iff the account is able to make a withdrawal of the given amount + /// for the given reason. Basically, it's just a dry-run of `withdraw`. /// - /// This balance is a 'reserve' balance that other subsystems use in order to set aside tokens - /// that are still 'owned' by the account holder, but which are suspendable. (This is different - /// and wholly unrelated to the `Bondage` system used in the staking module.) - /// - /// When this balance falls below the value of `ExistentialDeposit`, then this 'reserve account' - /// is deleted: specifically, `ReservedBalance`. - /// - /// `system::AccountNonce` is also deleted if `FreeBalance` is also zero (it also gets - /// collapsed to zero if it ever becomes less than `ExistentialDeposit`. - fn reserved_balance(who: &AccountId) -> Self::Balance; + /// `Err(...)` with the reason why not otherwise. + fn ensure_can_withdraw( + who: &AccountId, + _amount: Self::Balance, + reason: WithdrawReason, + new_balance: Self::Balance, + ) -> result::Result<(), &'static str>; // PUBLIC MUTABLES (DANGEROUS) + /// Transfer some liquid free balance to another staker. + /// + /// This is a very high-level function. It will ensure all appropriate fees are paid + /// and no imbalance in the system remains. + fn transfer( + source: &AccountId, + dest: &AccountId, + value: Self::Balance, + ) -> result::Result<(), &'static str>; + /// Deducts up to `value` from the combined balance of `who`, preferring to deduct from the /// free balance. This function cannot fail. /// + /// The resulting imbalance is the first item of the tuple returned. + /// /// As much funds up to `value` will be deducted as possible. If this is less than `value`, - /// then `Some(remaining)` will be returned. Full completion is given by `None`. - fn slash(who: &AccountId, value: Self::Balance) -> Option; + /// then a non-zero second item will be returned. + fn slash( + who: &AccountId, + value: Self::Balance + ) -> (Self::NegativeImbalance, Self::Balance); - /// Adds up to `value` to the free balance of `who`. + /// Mints `value` to the free balance of `who`. /// /// If `who` doesn't exist, nothing is done and an Err returned. - fn reward(who: &AccountId, value: Self::Balance) -> result::Result<(), &'static str>; + fn deposit_into_existing( + who: &AccountId, + value: Self::Balance + ) -> result::Result; - /// Adds up to `value` to the free balance of `who`. + /// Removes some free balance from `who` account for `reason` if possible. If `liveness` is `KeepAlive`, + /// then no less than `ExistentialDeposit` must be left remaining. /// - /// If `who` doesn't exist, it is created + /// This checks any locks, vesting, and liquidity requirements. If the removal is not possible, then it + /// returns `Err`. + fn withdraw( + who: &AccountId, + value: Self::Balance, + reason: WithdrawReason, + liveness: ExistenceRequirement, + ) -> result::Result; + + /// Adds up to `value` to the free balance of `who`. If `who` doesn't exist, it is created. + /// + /// Infallible. + fn deposit_creating( + who: &AccountId, + value: Self::Balance, + ) -> Self::PositiveImbalance; + + /// Ensure an account's free balance equals some value; this will create the account + /// if needed. /// - /// Returns if the account was successfully updated or update has led to killing of the account. + /// Returns a signed imbalance and status to indicate if the account was successfully updated or update + /// has led to killing of the account. + fn make_free_balance_be( + who: &AccountId, + balance: Self::Balance, + ) -> ( + SignedImbalance, + UpdateBalanceOutcome, + ); +} + +/// A currency where funds can be reserved from the user. +pub trait ReservableCurrency: Currency { + /// Same result as `reserve(who, value)` (but without the side-effects) assuming there + /// are no balance changes in the meantime. + fn can_reserve(who: &AccountId, value: Self::Balance) -> bool; + + /// Deducts up to `value` from reserved balance of `who`. This function cannot fail. /// - /// NOTE: This assumes that the total stake remains unchanged after this operation. - fn increase_free_balance_creating(who: &AccountId, value: Self::Balance) -> UpdateBalanceOutcome; + /// As much funds up to `value` will be deducted as possible. If the reserve balance of `who` + /// is less than `value`, then a non-zero second item will be returned. + fn slash_reserved( + who: &AccountId, + value: Self::Balance + ) -> (Self::NegativeImbalance, Self::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. + /// + /// This balance is a 'reserve' balance that other subsystems use in order to set aside tokens + /// that are still 'owned' by the account holder, but which are suspendable. + /// + /// When this balance falls below the value of `ExistentialDeposit`, then this 'reserve account' + /// is deleted: specifically, `ReservedBalance`. + /// + /// `system::AccountNonce` is also deleted if `FreeBalance` is also zero (it also gets + /// collapsed to zero if it ever becomes less than `ExistentialDeposit`. + fn reserved_balance(who: &AccountId) -> Self::Balance; + /// Moves `value` from balance to reserved balance. /// /// If the free balance is lower than `value`, then no funds will be moved and an `Err` will - /// be returned to notify of this. This is different behaviour to `unreserve`. + /// be returned to notify of this. This is different behavior than `unreserve`. fn reserve(who: &AccountId, value: Self::Balance) -> result::Result<(), &'static str>; - /// Moves up to `value` from reserved balance to balance. This function cannot fail. + /// Moves up to `value` from reserved balance to free balance. This function cannot fail. /// - /// As much funds up to `value` will be deducted as possible. If this is less than `value`, - /// then `Some(remaining)` will be returned. Full completion is given by `None`. - /// NOTE: This is different to `reserve`. - fn unreserve(who: &AccountId, value: Self::Balance) -> Option; - - /// Deducts up to `value` from reserved balance of `who`. This function cannot fail. + /// As much funds up to `value` will be moved as possible. If the reserve balance of `who` + /// is less than `value`, then the remaining amount will be returned. /// - /// As much funds up to `value` will be deducted as possible. If this is less than `value`, - /// then `Some(remaining)` will be returned. Full completion is given by `None`. - fn slash_reserved(who: &AccountId, value: Self::Balance) -> Option; + /// # NOTES + /// + /// - This is different from `reserve`. + /// - If the remaining reserved balance is less than `ExistentialDeposit`, it will + /// invoke `on_reserved_too_low` and could reap the account. + fn unreserve(who: &AccountId, value: Self::Balance) -> Self::Balance; /// Moves up to `value` from reserved balance of account `slashed` to free balance of account /// `beneficiary`. `beneficiary` must exist for this to succeed. If it does not, `Err` will be /// returned. /// - /// As much funds up to `value` will be moved as possible. If this is less than `value`, then - /// `Ok(Some(remaining))` will be returned. Full completion is given by `Ok(None)`. + /// As much funds up to `value` will be deducted as possible. If this is less than `value`, + /// then `Ok(non_zero)` will be returned. fn repatriate_reserved( slashed: &AccountId, beneficiary: &AccountId, value: Self::Balance - ) -> result::Result, &'static str>; + ) -> result::Result; } + +/// An identifier for a lock. Used for disambiguating different locks so that +/// they can be individually replaced or removed. +pub type LockIdentifier = [u8; 8]; + +/// A currency whose accounts can have liquidity restrictions. +pub trait LockableCurrency: Currency { + /// The quantity used to denote time; usually just a `BlockNumber`. + type Moment; + + /// Create a new balance lock on account `who`. + /// + /// If the new lock is valid (i.e. not already expired), it will push the struct to + /// the `Locks` vec in storage. Note that you can lock more funds than a user has. + /// + /// If the lock `id` already exists, this will update it. + fn set_lock( + id: LockIdentifier, + who: &AccountId, + amount: Self::Balance, + until: Self::Moment, + reasons: WithdrawReasons, + ); + + /// Changes a balance lock (selected by `id`) so that it becomes less liquid in all + /// parameters or creates a new one if it does not exist. + /// + /// Calling `extend_lock` on an existing lock `id` differs from `set_lock` in that it + /// applies the most severe constraints of the two, while `set_lock` replaces the lock + /// with the new parameters. As in, `extend_lock` will set: + /// - maximum `amount` + /// - farthest duration (`until`) + /// - bitwise mask of all `reasons` + fn extend_lock( + id: LockIdentifier, + who: &AccountId, + amount: Self::Balance, + until: Self::Moment, + reasons: WithdrawReasons, + ); + + /// Remove an existing lock. + fn remove_lock( + id: LockIdentifier, + who: &AccountId, + ); +} + +bitmask! { + /// Reasons for moving funds out of an account. + #[derive(Encode, Decode)] + pub mask WithdrawReasons: i8 where + + /// Reason for moving funds out of an account. + #[derive(Encode, Decode)] + flags WithdrawReason { + /// In order to pay for (system) transaction costs. + TransactionPayment = 0b00000001, + /// In order to transfer ownership. + Transfer = 0b00000010, + /// In order to reserve some funds for a later return or repatriation + Reserve = 0b00000100, + /// In order to pay some other (higher-level) fees. + Fee = 0b00001000, + } +} + diff --git a/srml/support/test/Cargo.toml b/srml/support/test/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..e1113eb46851f3a82a5848c42ab3441b934e6fb6 --- /dev/null +++ b/srml/support/test/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "srml-support-test" +version = "0.1.0" +authors = ["thiolliere "] +edition = "2018" + +[dev-dependencies] +serde = { version = "1.0", default-features = false } +serde_derive = { version = "1.0" } +parity-codec = { version = "3.2", default-features = false, features = ["derive"] } +runtime_io = { package = "sr-io", path = "../../../core/sr-io", default-features = false } +srml-support = { path = "../", default-features = false } +inherents = { package = "substrate-inherents", path = "../../../core/inherents", default-features = false } +primitives = { package = "substrate-primitives", path = "../../../core/primitives", default-features = false } + +[features] +default = ["std"] +std = [ + "serde/std", + "parity-codec/std", + "runtime_io/std", + "srml-support/std", + "inherents/std", + "primitives/std", +] diff --git a/srml/support/test/src/lib.rs b/srml/support/test/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/srml/support/test/tests/instance.rs b/srml/support/test/tests/instance.rs new file mode 100644 index 0000000000000000000000000000000000000000..28ad3ee0063056a217bf99fef01f0674ef849306 --- /dev/null +++ b/srml/support/test/tests/instance.rs @@ -0,0 +1,498 @@ +// 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 . + +#![recursion_limit="128"] + +#[cfg(feature = "std")] +use serde_derive::Serialize; +use runtime_io::{with_externalities, Blake2Hasher}; +use srml_support::rstd::prelude::*; +use srml_support::rstd as rstd; +use srml_support::codec::{Encode, Decode}; +use srml_support::runtime_primitives::{generic, BuildStorage}; +use srml_support::runtime_primitives::traits::{BlakeTwo256, Block as _, Verify, Digest}; +use srml_support::Parameter; +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>> + From>; + type BlockNumber; + type Digest: Digest; + type Hash; + type AccountId; + type Event: From; + type Log: From> + Into>; + } + + pub type DigestItemOf = <::Digest as Digest>::Item; + + 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: ::Item) { + 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), + Inherent, + } + + impl From> for RawOrigin { + fn from(s: Option) -> RawOrigin { + match s { + Some(who) => RawOrigin::Signed(who), + None => RawOrigin::Inherent, + } + } + } + + pub type Origin = RawOrigin<::AccountId>; + + pub type Log = RawLog< + ::Hash, + >; + + #[cfg_attr(feature = "std", derive(Serialize, Debug))] + #[derive(Encode, Decode, PartialEq, Eq, Clone)] + pub enum RawLog { + ChangesTrieRoot(H), + } + + pub fn ensure_root(o: OuterOrigin) -> Result<(), &'static str> + where OuterOrigin: Into>> + { + match o.into() { + Some(RawOrigin::Root) => Ok(()), + _ => Err("bad origin: expected to be a root origin"), + } + } +} + +// Test for: +// * No default instance +// * Custom InstantiableTrait +// * Origin, Inherent, Log, Event +mod module1 { + use super::*; + + pub trait Trait: system::Trait { + type Event: From> + Into<::Event>; + type Origin: From>; + type Log: From> + Into>; + } + + srml_support::decl_module! { + pub struct Module, I: InstantiableThing> for enum Call where origin: ::Origin { + fn deposit_event() = default; + + fn one() { + Self::deposit_event(RawEvent::AnotherVariant(3)); + Self::deposit_log(RawLog::AmountChange(3)); + } + } + } + + impl, I: InstantiableThing> Module { + /// Deposit one of this module's logs. + fn deposit_log(log: Log) { + >::deposit_log(>::Log::from(log).into()); + } + } + + srml_support::decl_storage! { + trait Store for Module, I: InstantiableThing> as Module1 { + pub Value config(value): u64; + pub Map: map u32 => u64; + pub LinkedMap: linked_map u32 => u64; + } + } + + srml_support::decl_event! { + pub enum Event where Phantom = rstd::marker::PhantomData { + _Phantom(Phantom), + AnotherVariant(u32), + } + } + + #[derive(PartialEq, Eq, Clone)] + #[cfg_attr(feature = "std", derive(Debug))] + pub enum Origin, I> { + Members(u32), + _Phantom(rstd::marker::PhantomData<(T, I)>), + } + + pub type Log = RawLog< + T, + I, + >; + + /// A logs in this module. + #[cfg_attr(feature = "std", derive(serde_derive::Serialize, Debug))] + #[derive(parity_codec::Encode, parity_codec::Decode, PartialEq, Eq, Clone)] + pub enum RawLog { + _Phantom(rstd::marker::PhantomData<(T, I)>), + AmountChange(u32), + } + + pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"12345678"; + + impl, I: InstantiableThing> ProvideInherent for Module { + type Call = Call; + type Error = MakeFatalError; + const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; + + fn create_inherent(_data: &InherentData) -> Option { + unimplemented!(); + } + + fn check_inherent(_call: &Self::Call, _data: &InherentData) -> rstd::result::Result<(), Self::Error> { + unimplemented!(); + } + } +} + +// Test for: +// * default instance +// * use of no_genesis_config_phantom_data +mod module2 { + use super::*; + + pub trait Trait: system::Trait { + type Amount: Parameter + Default; + type Event: From> + Into<::Event>; + type Origin: From>; + type Log: From> + Into>; + } + + impl, I: Instance> Currency for Module {} + + srml_support::decl_module! { + pub struct Module, I: Instance=DefaultInstance> for enum Call where origin: ::Origin { + fn deposit_event() = default; + } + } + + srml_support::decl_storage! { + trait Store for Module, I: Instance=DefaultInstance> as Module2 { + pub Value config(value): T::Amount; + pub Map config(map): map u64 => u64; + 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! { + pub enum Event where Amount = >::Amount { + Variant(Amount), + } + } + + #[derive(PartialEq, Eq, Clone)] + #[cfg_attr(feature = "std", derive(Debug))] + pub enum Origin, I=DefaultInstance> { + Members(u32), + _Phantom(rstd::marker::PhantomData<(T, I)>), + } + + pub type Log = RawLog< + T, + I, + >; + + /// A logs in this module. + #[cfg_attr(feature = "std", derive(serde_derive::Serialize, Debug))] + #[derive(parity_codec::Encode, parity_codec::Decode, PartialEq, Eq, Clone)] + pub enum RawLog { + _Phantom(rstd::marker::PhantomData<(T, I)>), + AmountChange(u32), + } + + pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"12345678"; + + impl, I: Instance> ProvideInherent for Module { + type Call = Call; + type Error = MakeFatalError; + const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; + + fn create_inherent(_data: &InherentData) -> Option { + unimplemented!(); + } + + fn check_inherent(_call: &Self::Call, _data: &InherentData) -> rstd::result::Result<(), Self::Error> { + unimplemented!(); + } + } +} + +// Test for: +// * Depends on multiple instances of a module with instances +mod module3 { + use super::*; + + pub trait Trait: module2::Trait + module2::Trait + system::Trait { + type Currency: Currency; + type Currency2: Currency; + } + + srml_support::decl_module! { + pub struct Module for enum Call where origin: ::Origin { + } + } +} + +impl module1::Trait for Runtime { + type Event = Event; + type Origin = Origin; + type Log = Log; +} +impl module1::Trait for Runtime { + type Event = Event; + type Origin = Origin; + type Log = Log; +} +impl module2::Trait for Runtime { + type Amount = u16; + type Event = Event; + type Origin = Origin; + type Log = Log; +} +impl module2::Trait for Runtime { + type Amount = u32; + type Event = Event; + type Origin = Origin; + type Log = Log; +} +impl module2::Trait for Runtime { + type Amount = u32; + type Event = Event; + type Origin = Origin; + type Log = Log; +} +impl module2::Trait for Runtime { + type Amount = u64; + type Event = Event; + type Origin = Origin; + type Log = Log; +} +impl module3::Trait for Runtime { + type Currency = Module2_2; + type Currency2 = Module2_3; +} + +pub type Signature = sr25519::Signature; +pub type AccountId = ::Signer; +pub type BlockNumber = u64; +pub type Index = u64; + +impl system::Trait for Runtime { + type Hash = H256; + type Origin = Origin; + type BlockNumber = BlockNumber; + type Digest = generic::Digest; + type AccountId = AccountId; + type Event = Event; + type Log = Log; +} + +srml_support::construct_runtime!( + pub enum Runtime with Log(InternalLog: DigestItem) where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: system::{Module, Call, Event, Log(ChangesTrieRoot)}, + Module1_1: module1::::{Module, Call, Storage, Event, Config, Origin, Log(), Inherent}, + Module1_2: module1::::{Module, Call, Storage, Event, Config, Origin, Log(), Inherent}, + Module2: module2::{Module, Call, Storage, Event, Config, Origin, Log(), Inherent}, + Module2_1: module2::::{Module, Call, Storage, Event, Config, Origin, Log(), Inherent}, + Module2_2: module2::::{Module, Call, Storage, Event, Config, Origin, Log(), Inherent}, + Module2_3: module2::::{Module, Call, Storage, Event, Config, Origin, Log(), Inherent}, + Module3: module3::{Module, Call}, + } +); + +pub type Header = generic::Header; +pub type Block = generic::Block; +pub type UncheckedExtrinsic = generic::UncheckedMortalCompactExtrinsic; + +fn new_test_ext() -> runtime_io::TestExternalities { + GenesisConfig{ + module1_Instance1: Some(module1::GenesisConfig { + value: 3, + .. Default::default() + }), + module1_Instance2: Some(module1::GenesisConfig { + value: 4, + _genesis_phantom_data: Default::default(), + }), + module2: Some(module2::GenesisConfig { + value: 4, + map: vec![(0, 0)], + linked_map: vec![(0, 0)], + double_map: vec![(0, 0, 0)], + }), + module2_Instance1: Some(module2::GenesisConfig { + value: 4, + map: vec![(0, 0)], + linked_map: vec![(0, 0)], + double_map: vec![(0, 0, 0)], + }), + module2_Instance2: None, + module2_Instance3: None, + }.build_storage().unwrap().0.into() +} + +#[test] +fn storage_instance_independance() { + with_externalities(&mut new_test_ext(), || { + let mut map = rstd::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(), + ].iter() { + assert!(map.insert(key, ()).is_none()) + } + }); +} + +// TODO TODO: check configuration doublemapstorage in instances + +#[test] +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; + + assert_eq!(Value::exists(), true); + assert_eq!(Value::get(), 4); + Value::put(1); + assert_eq!(Value::get(), 1); + assert_eq!(Value::take(), 1); + assert_eq!(Value::get(), 0); + Value::mutate(|a| *a=2); + assert_eq!(Value::get(), 2); + Value::kill(); + assert_eq!(Value::exists(), false); + assert_eq!(Value::get(), 0); + + let key = 1; + assert_eq!(Map::exists(0), true); + assert_eq!(Map::exists(key), false); + Map::insert(key, 1); + assert_eq!(Map::get(key), 1); + assert_eq!(Map::take(key), 1); + assert_eq!(Map::get(key), 0); + Map::mutate(key, |a| *a=2); + assert_eq!(Map::get(key), 2); + Map::remove(key); + assert_eq!(Map::exists(key), false); + assert_eq!(Map::get(key), 0); + + assert_eq!(LinkedMap::exists(0), true); + assert_eq!(LinkedMap::exists(key), false); + LinkedMap::insert(key, 1); + assert_eq!(LinkedMap::get(key), 1); + assert_eq!(LinkedMap::take(key), 1); + assert_eq!(LinkedMap::get(key), 0); + LinkedMap::mutate(key, |a| *a=2); + assert_eq!(LinkedMap::get(key), 2); + LinkedMap::remove(key); + assert_eq!(LinkedMap::exists(key), false); + assert_eq!(LinkedMap::get(key), 0); + + let key1 = 1; + let key2 = 1; + assert_eq!(DoubleMap::exists(0, 0), true); + assert_eq!(DoubleMap::exists(key1, key2), false); + DoubleMap::insert(key1, key2, 1); + assert_eq!(DoubleMap::get(key1, key2), 1); + assert_eq!(DoubleMap::take(key1, key2), 1); + assert_eq!(DoubleMap::get(key1, key2), 0); + DoubleMap::mutate(key1, key2, |a| *a=2); + assert_eq!(DoubleMap::get(key1, key2), 2); + DoubleMap::remove(key1, key2); + assert_eq!(DoubleMap::get(key1, key2), 0); + }); +} diff --git a/srml/system/Cargo.toml b/srml/system/Cargo.toml index a45f4e7aeac9a14d0104735ec718179b3e958c85..bd199b97f902a300b2a3d387203262a9712a3a62 100644 --- a/srml/system/Cargo.toml +++ b/srml/system/Cargo.toml @@ -6,11 +6,10 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false} -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", 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 } @@ -20,11 +19,10 @@ srml-support = { path = "../support", default-features = false } [features] default = ["std"] std = [ - "serde/std", + "serde", "serde_derive", "safe-mix/std", "parity-codec/std", - "parity-codec-derive/std", "substrate-primitives/std", "rstd/std", "runtime_io/std", diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index 8f3fd1df8cbafc290695dbeae7d6e4f6e9eed2a8..cf4dedbca63adc2edf3b8ca1ba2af4eeef7c6d09 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-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,59 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! System manager: Handles lowest level stuff like depositing logs, basic set up and take down of -//! temporary storage entries, access to old block hashes. +//! # System module +//! +//! The system module provides low-level access to core types and cross-cutting utilities. +//! It acts as the base layer for other SRML modules to interact with the Substrate framework components. +//! To use it in your module, you should ensure your module's trait implies the system [`Trait`]. +//! +//! ## Overview +//! +//! The system module defines the core data types used in a Substrate runtime. +//! It also provides several utility functions (see [`Module`]) for other runtime modules. +//! +//! In addition, it manages the storage items for extrinsics data, indexes, event record and digest items, +//! among other things that support the execution of the current block. +//! +//! It also handles low level tasks like depositing logs, basic set up and take down of +//! temporary storage entries and access to previous block hashes. +//! +//! ## Interface +//! +//! ### Dispatchable functions +//! +//! The system module does not implement any dispatchable functions. +//! +//! ### Public functions +//! +//! All public functions are available as part of the [`Module`] type. +//! +//! ## Usage +//! +//! ### Prerequisites +//! +//! Import the system module and derive your module's configuration trait from the system trait. +//! +//! ### Example - Get random seed and extrinsic count for the current block +//! +//! ``` +//! use srml_support::{decl_module, dispatch::Result}; +//! use srml_system::{self as system, ensure_signed}; +//! +//! pub trait Trait: system::Trait {} +//! +//! decl_module! { +//! pub struct Module for enum Call where origin: T::Origin { +//! pub fn system_module_example(origin) -> Result { +//! let _sender = ensure_signed(origin)?; +//! let _random_seed = >::random_seed(); +//! let _extrinsic_count = >::extrinsic_count(); +//! Ok(()) +//! } +//! } +//! } +//! # fn main() { } +//! ``` #![cfg_attr(not(feature = "std"), no_std)] @@ -30,10 +81,7 @@ use primitives::traits::{self, CheckEqual, SimpleArithmetic, SimpleBitOps, Zero, use substrate_primitives::storage::well_known_keys; use srml_support::{storage, StorageValue, StorageMap, Parameter, decl_module, decl_event, decl_storage}; use safe_mix::TripletMix; -use parity_codec_derive::{Encode, Decode}; - -#[cfg(any(feature = "std", test))] -use parity_codec::Encode; +use parity_codec::{Encode, Decode}; #[cfg(any(feature = "std", test))] use runtime_io::{twox_128, TestExternalities, Blake2Hasher}; @@ -63,32 +111,64 @@ impl IsDeadAccount for () { } } -/// Compute the extrinsics root of a list of extrinsics. +/// Compute the trie root of a list of extrinsics. pub fn extrinsics_root(extrinsics: &[E]) -> H::Output { extrinsics_data_root::(extrinsics.iter().map(parity_codec::Encode::encode).collect()) } -/// Compute the extrinsics root of a list of extrinsics. +/// Compute the trie root of a list of extrinsics. pub fn extrinsics_data_root(xts: Vec>) -> H::Output { let xts = xts.iter().map(Vec::as_slice).collect::>(); H::enumerated_trie_root(&xts) } pub trait Trait: 'static + Eq + Clone { + /// The aggregated `Origin` type used by dispatchable calls. type Origin: Into>> + From>; - type Index: Parameter + Member + MaybeSerializeDebugButNotDeserialize + Default + MaybeDisplay + SimpleArithmetic + Copy; - type BlockNumber: Parameter + Member + MaybeSerializeDebug + MaybeDisplay + SimpleArithmetic + Default + Bounded + Copy + rstd::hash::Hash; - type Hash: Parameter + Member + MaybeSerializeDebug + MaybeDisplay + SimpleBitOps + Default + Copy + CheckEqual + rstd::hash::Hash + AsRef<[u8]> + AsMut<[u8]>; + + /// Account index (aka nonce) type. This stores the number of previous transactions associated with a sender + /// account. + type Index: + Parameter + Member + MaybeSerializeDebugButNotDeserialize + Default + MaybeDisplay + SimpleArithmetic + Copy; + + /// The block number type used by the runtime. + type BlockNumber: + Parameter + Member + MaybeSerializeDebug + MaybeDisplay + SimpleArithmetic + Default + Bounded + Copy + + rstd::hash::Hash; + + /// The output of the `Hashing` function. + type Hash: + Parameter + Member + MaybeSerializeDebug + MaybeDisplay + SimpleBitOps + Default + Copy + CheckEqual + + rstd::hash::Hash + AsRef<[u8]> + AsMut<[u8]>; + + /// The hashing system (algorithm) being used in the runtime (e.g. Blake2). type Hashing: Hash; - type Digest: Parameter + Member + MaybeSerializeDebugButNotDeserialize + Default + traits::Digest; + + /// Collection of (light-client-relevant) logs for a block to be included verbatim in the block header. + type Digest: + Parameter + Member + MaybeSerializeDebugButNotDeserialize + Default + traits::Digest; + + /// The user account identifier type for the runtime. type AccountId: Parameter + Member + MaybeSerializeDebug + MaybeDisplay + Ord + Default; + + /// Converting trait to take a source type and convert to `AccountId`. + /// + /// Used to define the type and conversion mechanism for referencing accounts in transactions. It's perfectly + /// reasonable for this to be an identity conversion (with the source type being `AccountId`), but other modules + /// (e.g. Indices module) may provide more functional/efficient alternatives. type Lookup: StaticLookup; + + /// The block header. type Header: Parameter + traits::Header< Number = Self::BlockNumber, Hash = Self::Hash, Digest = Self::Digest >; + + /// The aggregated event type of the runtime. type Event: Parameter + Member + From; + + /// A piece of information which can be part of the digest (as a digest item). type Log: From> + Into>; } @@ -127,8 +207,8 @@ pub struct EventRecord { pub event: E, } -/// Event for the system module. decl_event!( + /// Event for the system module. pub enum Event { /// An extrinsic completed successfully. ExtrinsicSuccess, @@ -193,22 +273,38 @@ impl From> for primitives::testing::DigestIte } } +// Create a Hash with 69 for each byte, +// only used to build genesis config. +#[cfg(feature = "std")] +fn hash69 + Default>() -> T { + let mut h = T::default(); + h.as_mut().iter_mut().for_each(|byte| *byte = 69); + h +} + decl_storage! { trait Store for Module as System { - + /// Extrinsics nonce for accounts. pub AccountNonce get(account_nonce): map T::AccountId => T::Index; - + /// Total extrinsics count for the current block. ExtrinsicCount: Option; + /// Total length in bytes for all extrinsics put together, for the current block. AllExtrinsicsLen: Option; - pub BlockHash get(block_hash) build(|_| vec![(T::BlockNumber::zero(), [69u8; 32])]): map T::BlockNumber => T::Hash; + /// Map of block numbers to block hashes. + pub BlockHash get(block_hash) build(|_| vec![(T::BlockNumber::zero(), hash69())]): map T::BlockNumber => T::Hash; + /// Extrinsics data for the current block (maps extrinsic's index to its data). ExtrinsicData get(extrinsic_data): map u32 => Vec; - RandomSeed get(random_seed) build(|_| [0u8; 32]): T::Hash; + /// Random seed of the current block. + RandomSeed get(random_seed) build(|_| T::Hash::default()): T::Hash; /// The current block number being processed. Set by `execute_block`. - Number get(block_number) build(|_| 1u64): T::BlockNumber; - ParentHash get(parent_hash) build(|_| [69u8; 32]): T::Hash; + Number get(block_number) build(|_| T::BlockNumber::sa(1u64)): T::BlockNumber; + /// Hash of the previous block. + ParentHash get(parent_hash) build(|_| hash69()): T::Hash; + /// Extrinsics root of the current block, also part of the block header. ExtrinsicsRoot get(extrinsics_root): T::Hash; + /// Digest of the current block, also part of the block header. Digest get(digest): T::Digest; - + /// Events deposited for the current block. Events get(events): Vec>; } add_extra_genesis { @@ -318,8 +414,7 @@ impl Module { // > stays to be inspected by the client. - ::new(number, extrinsics_root, storage_root, - parent_hash, digest) + ::new(number, extrinsics_root, storage_root, parent_hash, digest) } /// Deposits a log and ensures it matches the blocks log data. @@ -476,7 +571,7 @@ mod tests { type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = u16; type Log = DigestItem; diff --git a/srml/timestamp/Cargo.toml b/srml/timestamp/Cargo.toml index 8de7fd4bbf5a685461f0e27f9d8c03795a9a2ddb..30c3779f31c6435e39383cd86d789b87de5f1138 100644 --- a/srml/timestamp/Cargo.toml +++ b/srml/timestamp/Cargo.toml @@ -6,15 +6,13 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +serde = { version = "1.0", optional = true } +parity-codec = { version = "3.2", 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 } srml-support = { path = "../support", default-features = false } system = { package = "srml-system", path = "../system", default-features = false } -consensus = { package = "srml-consensus", path = "../consensus", default-features = false } [dev-dependencies] runtime_io = { package = "sr-io", path = "../../core/sr-io" } @@ -23,13 +21,11 @@ substrate-primitives = { path = "../../core/primitives" } [features] default = ["std"] std = [ + "inherents/std", + "parity-codec/std", "rstd/std", - "srml-support/std", "runtime_primitives/std", - "consensus/std", - "serde/std", - "parity-codec/std", - "parity-codec-derive/std", + "srml-support/std", + "serde", "system/std", - "inherents/std", ] diff --git a/srml/timestamp/src/lib.rs b/srml/timestamp/src/lib.rs index d1d1f9f54e86fcdcac22f534d96f8eaa706a6db1..7511d5bf2fc0d585a3d5d23bce09100debac2b19 100644 --- a/srml/timestamp/src/lib.rs +++ b/srml/timestamp/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -14,35 +14,84 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! Timestamp manager: provides means to find out the current time. +//! # Timestamp Module +//! +//! The timestamp module provides functionality to get and set the on-chain time. +//! To use it in your module, you need to implement the timestamp [`Trait`]. +//! The supported dispatchable functions are documented as part of the [`Call`] enum. +//! +//! ## Overview +//! +//! The timestamp module allows the validators to set and validate a timestamp with each block. //! -//! It is expected that the timestamp is set by the validator in the -//! beginning of each block, typically one of the first extrinsics. The timestamp -//! can be set only once per block and must be set each block. +//! It uses inherents for timestamp data, which is provided by the block author and validated/verified by other validators. +//! The timestamp can be set only once per block and must be set each block. There could be a constraint on how much time must pass before setting the new timestamp. +//! +//! **NOTE:** The timestamp module is the recommended way to query the on-chain time instead of using an approach based on block numbers. +//! The block numbers based time measurement can cause issues because of cummulative calculation errors and hence it should be avoided. +//! +//! ## Interface +//! +//! ### Dispatchable functions ([`Call`]) +//! +//! * `set` - Sets the current time. +//! +//! ### Public functions ([`Module`]) +//! +//! * `get` - Gets the current time for the current block. If this function is called prior the setting to timestamp, it will return the timestamp of the previous block. +//! +//! * `minimum_period` - Gets the minimum (and advised) period between blocks for the chain. +//! +//! ## Usage +//! +//! The following example shows how to use the timestamp module in your custom module to query the current timestamp. +//! +//! ### Prerequisites +//! +//! Import the `timestamp` module in your custom module and derive the module configuration trait from the `timestamp` trait. +//! +//! ### Get current timestamp +//! +//! ```ignore +//! use support::{decl_module, dispatch::Result}; +//! use system::ensure_signed; +//! +//! pub trait Trait: timestamp::Trait {} +//! +//! decl_module! { +//! pub struct Module for enum Call where origin: T::Origin { +//! pub fn get_time(origin) -> Result { +//! let _sender = ensure_signed(origin)?; +//! let _now = >::get(); +//! Ok(()) +//! } +//! } +//! } +//! ``` +//! +//! ### Example from SRML +//! +//! The [`Session` module](https://github.com/paritytech/substrate/blob/master/srml/session/src/lib.rs) uses the `timestamp` module for session management. +//! +//! ## Related Modules +//! +//! * [`System`](https://crates.parity.io/srml_system/index.html) +//! * [`Session`](https://crates.parity.io/srml_session/index.html) //! -//! Note, that there might be a constraint on how much time must pass -//! before setting the new timestamp, specified by the `tim:block_period` -//! storage entry. -//! -//! # Interaction with the system -//! -//! ## Finalization -//! -//! This module should be hooked up to the finalization routine. #![cfg_attr(not(feature = "std"), no_std)] +use parity_codec::Encode; +#[cfg(feature = "std")] +use parity_codec::Decode; #[cfg(feature = "std")] -use parity_codec_derive::Decode; -use parity_codec_derive::Encode; +use inherents::ProvideInherentData; use srml_support::{StorageValue, Parameter, decl_storage, decl_module}; use srml_support::for_each_tuple; use runtime_primitives::traits::{As, SimpleArithmetic, Zero}; use system::ensure_inherent; use rstd::{result, ops::{Mul, Div}, cmp}; use inherents::{RuntimeString, InherentIdentifier, ProvideInherent, IsFatalError, InherentData}; -#[cfg(feature = "std")] -use inherents::ProvideInherentData; /// The identifier for the `timestamp` inherent. pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"timstap0"; @@ -144,11 +193,13 @@ macro_rules! impl_timestamp_set { for_each_tuple!(impl_timestamp_set); -pub trait Trait: consensus::Trait + system::Trait { +/// The module configuration trait +pub trait Trait: system::Trait { /// Type used for expressing timestamp. type Moment: Parameter + Default + SimpleArithmetic + Mul + Div; + /// Something which can be notified when the timestamp is set. Set this to `()` if not needed. type OnTimestampSet: OnTimestampSet; } @@ -157,18 +208,18 @@ decl_module! { pub struct Module for enum Call where origin: T::Origin { /// Set the current time. /// - /// Extrinsic with this call should be placed at the specific position in the each block - /// (specified by the Trait::TIMESTAMP_SET_POSITION) typically at the start of the each block. /// 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 `block_period`. + /// The timestamp should be greater than the previous one by the amount specified by `minimum_period`. + /// + /// The dispatch origin for this call must be `Inherent`. fn set(origin, #[compact] now: T::Moment) { ensure_inherent(origin)?; assert!(!::DidUpdate::exists(), "Timestamp must be updated only once in the block"); assert!( - Self::now().is_zero() || now >= Self::now() + Self::block_period(), - "Timestamp must increment by at least between sequential blocks" + Self::now().is_zero() || now >= Self::now() + >::get(), + "Timestamp must increment by at least between sequential blocks" ); ::Now::put(now.clone()); ::DidUpdate::put(true); @@ -176,6 +227,16 @@ decl_module! { >::on_timestamp_set(now); } + // Manage upgrade. Remove after all networks upgraded. + // TODO: #2133 + fn on_initialise() { + if let Some(period) = >::take() { + if !>::exists() { + >::put(period) + } + } + } + fn on_finalise() { assert!(::DidUpdate::take(), "Timestamp must be updated once in the block"); } @@ -186,8 +247,16 @@ decl_storage! { trait Store for Module as Timestamp { /// Current time for the current block. pub Now get(now) build(|_| T::Moment::sa(0)): T::Moment; - /// The minimum (and advised) period between blocks. - pub BlockPeriod get(block_period) config(period): T::Moment = T::Moment::sa(5); + + /// 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 = T::Moment::sa(3); /// Did the timestamp get updated in this block? DidUpdate: bool; @@ -195,10 +264,9 @@ decl_storage! { } impl Module { - /// Get the current time for the current block. /// - /// NOTE: if this function is called prior the setting the timestamp, + /// NOTE: if this function is called prior to setting the timestamp, /// it will return the timestamp of the previous block. pub fn get() -> T::Moment { Self::now() @@ -225,7 +293,7 @@ impl ProvideInherent for Module { fn create_inherent(data: &InherentData) -> Option { let data = extract_inherent_data(data).expect("Gets and decodes timestamp inherent data"); - let next_time = cmp::max(As::sa(data), Self::now() + Self::block_period()); + let next_time = cmp::max(As::sa(data), Self::now() + >::get()); Some(Call::set(next_time.into())) } @@ -239,7 +307,7 @@ impl ProvideInherent for Module { let data = extract_inherent_data(data).map_err(|e| InherentError::Other(e))?; - let minimum = (Self::now() + Self::block_period()).as_(); + let minimum = (Self::now() + >::get()).as_(); if t > data + MAX_TIMESTAMP_DRIFT { Err(InherentError::Other("Timestamp too far in future to accept".into())) } else if t < minimum { @@ -259,7 +327,7 @@ mod tests { use substrate_primitives::H256; use runtime_primitives::BuildStorage; use runtime_primitives::traits::{BlakeTwo256, IdentityLookup}; - use runtime_primitives::testing::{Digest, DigestItem, Header, UintAuthorityId}; + use runtime_primitives::testing::{Digest, DigestItem, Header}; impl_outer_origin! { pub enum Origin for Test {} @@ -275,16 +343,11 @@ mod tests { type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; } - impl consensus::Trait for Test { - type Log = DigestItem; - type SessionKey = UintAuthorityId; - type InherentOfflineReport = (); - } impl Trait for Test { type Moment = u64; type OnTimestampSet = (); @@ -295,7 +358,7 @@ mod tests { fn timestamp_works() { let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; t.extend(GenesisConfig:: { - period: 5, + minimum_period: 5, }.build_storage().unwrap().0); with_externalities(&mut TestExternalities::new(t), || { @@ -310,7 +373,7 @@ mod tests { fn double_timestamp_should_fail() { let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; t.extend(GenesisConfig:: { - period: 5, + minimum_period: 5, }.build_storage().unwrap().0); with_externalities(&mut TestExternalities::new(t), || { @@ -321,11 +384,11 @@ mod tests { } #[test] - #[should_panic(expected = "Timestamp must increment by at least between sequential blocks")] - fn block_period_is_enforced() { + #[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:: { - period: 5, + minimum_period: 5, }.build_storage().unwrap().0); with_externalities(&mut TestExternalities::new(t), || { diff --git a/srml/treasury/Cargo.toml b/srml/treasury/Cargo.toml index caffc0caaf249578edc94192e130d17762d166c9..825fc73532cbc35fdbf519c8b67bac94bb05f070 100644 --- a/srml/treasury/Cargo.toml +++ b/srml/treasury/Cargo.toml @@ -6,10 +6,9 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } -parity-codec = { version = "3.0", default-features = false } -parity-codec-derive = { version = "3.0", default-features = false } +parity-codec = { version = "3.2", 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 } @@ -23,10 +22,9 @@ substrate-primitives = { path = "../../core/primitives" } [features] default = ["std"] std = [ - "serde/std", + "serde", "serde_derive", "parity-codec/std", - "parity-codec-derive/std", "rstd/std", "runtime_primitives/std", "srml-support/std", diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index 4a8913bc4d9bb7b77897721e8c6aa5deb1b6a95f..6cb257f0344e3c9d9be999709393845d328bbed6 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -22,21 +22,18 @@ use serde_derive::{Serialize, Deserialize}; use rstd::prelude::*; use srml_support::{StorageValue, StorageMap, decl_module, decl_storage, decl_event, ensure}; -use srml_support::traits::{Currency, OnDilution, ArithmeticType}; +use srml_support::traits::{Currency, ReservableCurrency, OnDilution, OnUnbalanced, Imbalance}; use runtime_primitives::{Permill, traits::{Zero, EnsureOrigin, StaticLookup}}; -use parity_codec_derive::{Encode, Decode}; +use parity_codec::{Encode, Decode}; use system::ensure_signed; -type BalanceOf = <::Currency as ArithmeticType>::Type; +type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +type PositiveImbalanceOf = <::Currency as Currency<::AccountId>>::PositiveImbalance; +type NegativeImbalanceOf = <::Currency as Currency<::AccountId>>::NegativeImbalance; -/// Our module's configuration trait. All our types and consts go in here. If the -/// module is dependent on specific other modules, then their configuration traits -/// should be added to our implied traits list. -/// -/// `system::Trait` should always be included in our implied traits. pub trait Trait: system::Trait { /// The staking balance. - type Currency: ArithmeticType + Currency>; + type Currency: Currency + ReservableCurrency; /// Origin from which approvals must come. type ApproveOrigin: EnsureOrigin; @@ -46,14 +43,17 @@ pub trait Trait: system::Trait { /// The overarching event type. type Event: From> + Into<::Event>; + + /// Handler for the unbalanced increase when minting cash from the "Pot". + type MintedForSpending: OnUnbalanced>; + + /// Handler for the unbalanced decrease when slashing for a rejected proposal. + type ProposalRejection: OnUnbalanced>; } type ProposalIndex = u32; -// The module declaration. This states the entry points that we handle. The -// macro takes care of the marshalling of arguments and dispatch. decl_module! { - // Simple declaration of the `Module` type. Lets the macro know what its working on. pub struct Module for enum Call where origin: T::Origin { fn deposit_event() = default; /// Put forward a suggestion for spending. A deposit proportional to the value @@ -103,7 +103,8 @@ decl_module! { let proposal = >::take(proposal_id).ok_or("No proposal at that index")?; let value = proposal.bond; - let _ = T::Currency::slash_reserved(&proposal.proposer, value); + let imbalance = T::Currency::slash_reserved(&proposal.proposer, value).0; + T::ProposalRejection::on_unbalanced(imbalance); } /// Approve a proposal. At a later time, the proposal will be allocated to the beneficiary @@ -168,7 +169,6 @@ decl_storage! { } } -/// An event in this module. decl_event!( pub enum Event where @@ -202,6 +202,7 @@ impl Module { Self::deposit_event(RawEvent::Spending(budget_remaining)); let mut missed_any = false; + let mut imbalance = >::zero(); >::mutate(|v| { v.retain(|&index| { // Should always be true, but shouldn't panic if false or we're screwed. @@ -214,7 +215,7 @@ impl Module { let _ = T::Currency::unreserve(&p.proposer, p.bond); // provide the allocation. - T::Currency::increase_free_balance_creating(&p.beneficiary, p.value); + imbalance.subsume(T::Currency::deposit_creating(&p.beneficiary, p.value)); Self::deposit_event(RawEvent::Awarded(index, p.value, p.beneficiary)); false @@ -228,6 +229,8 @@ 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); @@ -278,7 +281,7 @@ mod tests { type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; @@ -287,14 +290,18 @@ mod tests { type Balance = u64; type OnNewAccount = (); type OnFreeBalanceZero = (); - type EnsureAccountLiquid = (); type Event = (); + type TransactionPayment = (); + type TransferPayment = (); + type DustRemoval = (); } impl Trait for Test { type Currency = balances::Module; type ApproveOrigin = system::EnsureRoot; type RejectOrigin = system::EnsureRoot; type Event = (); + type MintedForSpending = (); + type ProposalRejection = (); } type Balances = balances::Module; type Treasury = Module; @@ -303,6 +310,8 @@ mod tests { 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, diff --git a/srml/upgrade-key/Cargo.toml b/srml/upgrade-key/Cargo.toml deleted file mode 100644 index 07320bb9b9f59a0c785165bd3f1522e9e5452a50..0000000000000000000000000000000000000000 --- a/srml/upgrade-key/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "srml-upgrade-key" -version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2018" - -[dependencies] -serde = { version = "1.0", default-features = false } -parity-codec = { version = "3.0", default-features = false } -sr-std = { path = "../../core/sr-std", default-features = false } -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 } -consensus = { package = "srml-consensus", path = "../consensus", default-features = false } - -[features] -default = ["std"] -std = [ - "serde/std", - "parity-codec/std", - "sr-std/std", - "sr-primitives/std", - "srml-support/std", - "system/std", - "consensus/std", -] diff --git a/srml/upgrade-key/src/lib.rs b/srml/upgrade-key/src/lib.rs deleted file mode 100644 index a55251186b355421e0638fba76d08aba9e8d7538..0000000000000000000000000000000000000000 --- a/srml/upgrade-key/src/lib.rs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2017-2018 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 . - -//! The Example: A simple example of a runtime module demonstrating -//! concepts, APIs and structures common to most runtime modules. - -#![cfg_attr(not(feature = "std"), no_std)] - -use sr_std::prelude::*; -use sr_primitives::traits::StaticLookup; -use srml_support::{StorageValue, decl_module, decl_event, decl_storage, ensure}; -use system::ensure_signed; - -pub trait Trait: consensus::Trait + system::Trait { - /// The overarching event type. - type Event: From> + Into<::Event>; -} - -decl_module! { - // Simple declaration of the `Module` type. Lets the macro know what its working on. - pub struct Module for enum Call where origin: T::Origin { - fn deposit_event() = default; - fn upgrade(origin, new: Vec) { - // This is a public call, so we ensure that the origin is some signed account. - let _sender = ensure_signed(origin)?; - ensure!(_sender == Self::key(), "only the current upgrade key can use the upgrade_key module"); - - >::set_code(new)?; - Self::deposit_event(RawEvent::Upgraded); - } - - fn set_key(origin, new: ::Source) { - // This is a public call, so we ensure that the origin is some signed account. - let _sender = ensure_signed(origin)?; - ensure!(_sender == Self::key(), "only the current upgrade key can use the upgrade_key module"); - let new = T::Lookup::lookup(new)?; - - Self::deposit_event(RawEvent::KeyChanged(Self::key())); - >::put(new); - } - } -} - -/// An event in this module. -decl_event!( - pub enum Event where AccountId = ::AccountId { - /// An upgrade just happened. - Upgraded, - /// An upgrade just happened; old key is supplied as an argument. - KeyChanged(AccountId), - } -); - -decl_storage! { - trait Store for Module as UpgradeKey { - Key get(key) config(): T::AccountId; - } -} diff --git a/subkey/Cargo.toml b/subkey/Cargo.toml index 868ab3f74478dcdb9399ec0be30908f4da14e1c6..984820a1238467637dee26bf22322a03f8cb496f 100644 --- a/subkey/Cargo.toml +++ b/subkey/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "subkey" -version = "0.1.0" +version = "0.2.0" authors = ["Parity Technologies "] edition = "2018" @@ -8,6 +8,11 @@ edition = "2018" substrate-primitives = { version = "*", path = "../core/primitives" } 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" +hex = "0.3" [features] bench = [] diff --git a/subkey/README.adoc b/subkey/README.adoc index e895ab07adae8ae7c20a8aa43242f43bd7cf6a4c..7fe194eb82b701e0821391eacb465f89454f8add 100644 --- a/subkey/README.adoc +++ b/subkey/README.adoc @@ -1,22 +1,55 @@ = Subkey -A key generation utility with vanity address support. +Subkey is a commandline utility included with Substrate that generates or restores Substrate keys. -Usage: +`subkey` will use the http://wiki.polkadot.network/en/latest/polkadot/learn/cryptography/#keypairs-and-signing[sr25519] cryptography by default. If you need to use the older ed25519 cryptography to generate or restore your key pass the `--ed25519` flag to any of the commands. - subkey +== Usage -Sample use: +=== Generate a random account - $ subkey -or - $ subkey polka -or - $ subkey polka 3 +```bash +subkey generate +``` +Will output a mnemonic phrase and give you the seed, public key, and address of a new account. DO NOT SHARE your mnemonic or seed with ANYONE it will give them access to your funds. If someone is making a transfer to you they will only need your **Address**. -Result: +=== Inspecting a key - 5CxS39ykKsmPetYQjTqW6aJXkSChnuvPdziA8uphuPaCyRZ1: 406ac59ccbb8358f7c95b726d3ccb039afe35e2dd62045189d1abae8d7805b8a (54%) - 5CujMhFmChyq3AMUwMasfbqSpZYpbFfZS5UQ7zUn2d63CGBo: 5b6ac59ccbb8358f7c95b726d3ccb039afe35e2dd62045189d1abae8d7805b8a (69%) - 5EfdN3zChABKsXT9bEg33zqPsBu4YCu1h7yoovvjtsUMqyFU: c46ac59ccbb8358f7c95b726d3ccb039afe35e2dd62045189d1abae8d7805b8a (69%) +You can inspect a given URI (mnemonic, seed, public key, or address) and recover the public key and the address. + +```bash +subkey inspect + +OUTPUT: + Public key (hex): 0x461edcf1ba99e43f50dec4bdeb3d1a2cf521ad7c3cd0eeee5cd3314e50fd424c + Address (SS58): 5DeeNqcAcaHDSed2HYnqMDK7JHcvxZ5QUE9EKmjc5snvU6wF +``` + +=== Signing + +`subkey` expects a message to come in on STDIN, one way to sign a message would look like this: + +```bash +echo | subkey sign + +OUTPUT: +a69da4a6ccbf81dbbbfad235fa12cf8528c18012b991ae89214de8d20d29c1280576ced6eb38b7406d1b7e03231df6dd4a5257546ddad13259356e1c3adfb509 +``` + +=== Verifying a signature + +```bash +echo | subkey verify
+ +OUTPUT: +Signature verifies correctly. +``` + +=== Using the vanity generator + +You can use the included vanity generator to find a seed that provides an address which includes the desired pattern. Be warned, depending on your hardware this may take a while. + +```bash +subkey vanity 1337 +``` diff --git a/subkey/src/cli.yml b/subkey/src/cli.yml index 57cf98bdf2e5024c1364ce1f3e9d3f52a90bcbae..cc131703eb8df23b4d7599b258c5f0971cb71f7a 100644 --- a/subkey/src/cli.yml +++ b/subkey/src/cli.yml @@ -1,20 +1,63 @@ name: subkey author: "Parity Team " -about: A substrate key utility +about: Utility for generating and restoring with Substrate keys +args: + - ed25519: + short: e + long: ed25519 + help: Use Ed25519/BIP39 cryptography + takes_value: false + - sr25519: + short: s + long: sr25519 + help: Use Schnorr/Ristretto x25519/BIP39 cryptography + takes_value: false + - password: + short: p + long: password + takes_value: true + required: false + help: The password for the key subcommands: - generate: about: Generate a random account - - restore: - about: Gets a public key and a SS58 address from the provided seed phrase + - inspect: + about: Gets a public key and a SS58 address from the provided Secret URI args: - - seed: + - uri: index: 1 required: true - help: 32 bytes long seed phrase used to restore the public key. If the provided seed is shorter than that, then - it will be right-padded with 0x20 bytes (ASCII space). If the provided seed is longer than - 32 bytes then seed will be truncated. + help: A Key URI to be inspected. May be a secret seed, secret URI (with derivation paths and password), SS58 or public URI. + - sign: + about: Sign a message, provided on STDIN, with a given (secret) key + args: + - suri: + index: 1 + required: true + help: The secret key URI. + - hex: + short: h + long: hex + help: The message on STDIN is hex-encoded data + takes_value: false + - verify: + about: Verify a signature for a message, provided on STDIN, with a given (public or secret) key + args: + - sig: + index: 1 + required: true + help: Signature, hex-encoded. + - uri: + index: 2 + required: true + help: The public or secret key URI. + - hex: + short: h + long: hex + help: The message on STDIN is hex-encoded data + takes_value: false - vanity: - about: Generate vanity address + about: Generate a seed that provides a vanity address args: - pattern: index: 1 diff --git a/subkey/src/main.rs b/subkey/src/main.rs index 48fb7ad1227028412716f1f634aa11c4a5c5192a..5caf58d45ba14cda8e06f133ce4bd3744e46755c 100644 --- a/subkey/src/main.rs +++ b/subkey/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -18,61 +18,203 @@ #[cfg(feature = "bench")] extern crate test; +extern crate substrate_bip39; +extern crate rustc_hex; + +use std::io::{stdin, Read}; use clap::load_yaml; use rand::{RngCore, rngs::OsRng}; -use substrate_primitives::{ed25519::Pair, hexdisplay::HexDisplay}; +use substrate_bip39::mini_secret_from_entropy; +use bip39::{Mnemonic, Language, MnemonicType}; +use substrate_primitives::{ed25519, sr25519, hexdisplay::HexDisplay, Pair, crypto::Ss58Codec}; +use schnorrkel::keys::MiniSecretKey; mod vanity; -fn print_account(seed: &[u8; 32]) { - let pair = Pair::from_seed(seed); - println!("Seed 0x{} is account:\n Public key (hex): 0x{}\n Address (SS58): {}", - HexDisplay::from(seed), - HexDisplay::from(&pair.public().0), - pair.public().to_ss58check() - ); +trait Crypto { + type Seed: AsRef<[u8]> + AsMut<[u8]> + Sized + Default; + type Pair: Pair; + fn generate_phrase() -> String { + Mnemonic::new(MnemonicType::Words12, Language::English).phrase().to_owned() + } + fn generate_seed() -> Self::Seed { + let mut seed: Self::Seed = Default::default(); + OsRng::new().unwrap().fill_bytes(seed.as_mut()); + seed + } + fn seed_from_phrase(phrase: &str, password: Option<&str>) -> Self::Seed; + fn pair_from_seed(seed: &Self::Seed) -> Self::Pair; + fn pair_from_suri(phrase: &str, password: Option<&str>) -> Self::Pair { + Self::pair_from_seed(&Self::seed_from_phrase(phrase, password)) + } + fn ss58_from_pair(pair: &Self::Pair) -> String; + fn public_from_pair(pair: &Self::Pair) -> Vec; + fn seed_from_pair(_pair: &Self::Pair) -> Option<&Self::Seed> { None } + fn print_from_seed(seed: &Self::Seed) { + let pair = Self::pair_from_seed(seed); + println!("Seed 0x{} is account:\n Public key (hex): 0x{}\n Address (SS58): {}", + HexDisplay::from(&seed.as_ref()), + HexDisplay::from(&Self::public_from_pair(&pair)), + Self::ss58_from_pair(&pair) + ); + } + fn print_from_phrase(phrase: &str, password: Option<&str>) { + let seed = Self::seed_from_phrase(phrase, password); + let pair = Self::pair_from_seed(&seed); + println!("Phrase `{}` is account:\n Seed: 0x{}\n Public key (hex): 0x{}\n Address (SS58): {}", + phrase, + HexDisplay::from(&seed.as_ref()), + HexDisplay::from(&Self::public_from_pair(&pair)), + Self::ss58_from_pair(&pair) + ); + } + fn print_from_uri(uri: &str, password: Option<&str>) where ::Public: Sized + Ss58Codec + AsRef<[u8]> { + if let Ok(pair) = Self::Pair::from_string(uri, password) { + let seed_text = Self::seed_from_pair(&pair) + .map_or_else(Default::default, |s| format!("\n Seed: 0x{}", HexDisplay::from(&s.as_ref()))); + println!("Secret Key URI `{}` is account:{}\n Public key (hex): 0x{}\n Address (SS58): {}", + uri, + seed_text, + HexDisplay::from(&Self::public_from_pair(&pair)), + Self::ss58_from_pair(&pair) + ); + } + if let Ok(public) = ::Public::from_string(uri) { + println!("Public Key URI `{}` is account:\n Public key (hex): 0x{}\n Address (SS58): {}", + uri, + HexDisplay::from(&public.as_ref()), + public.to_ss58check() + ); + } + } } -fn main() { - let yaml = load_yaml!("cli.yml"); - let matches = clap::App::from_yaml(yaml).get_matches(); +struct Ed25519; + +impl Crypto for Ed25519 { + type Seed = [u8; 32]; + type Pair = ed25519::Pair; + + fn seed_from_phrase(phrase: &str, password: Option<&str>) -> Self::Seed { + Sr25519::seed_from_phrase(phrase, password) + } + fn pair_from_suri(suri: &str, password_override: Option<&str>) -> Self::Pair { + ed25519::Pair::from_legacy_string(suri, password_override) + } + fn pair_from_seed(seed: &Self::Seed) -> Self::Pair { ed25519::Pair::from_seed(seed.clone()) } + fn ss58_from_pair(pair: &Self::Pair) -> String { pair.public().to_ss58check() } + fn public_from_pair(pair: &Self::Pair) -> Vec { (&pair.public().0[..]).to_owned() } + fn seed_from_pair(pair: &Self::Pair) -> Option<&Self::Seed> { Some(pair.seed()) } +} + +struct Sr25519; + +impl Crypto for Sr25519 { + type Seed = [u8; 32]; + type Pair = sr25519::Pair; + + fn seed_from_phrase(phrase: &str, password: Option<&str>) -> Self::Seed { + mini_secret_from_entropy( + Mnemonic::from_phrase(phrase, Language::English) + .unwrap_or_else(|_| + panic!("Phrase is not a valid BIP-39 phrase: \n {}", phrase) + ) + .entropy(), + password.unwrap_or("") + ) + .expect("32 bytes can always build a key; qed") + .to_bytes() + } + + fn pair_from_suri(suri: &str, password: Option<&str>) -> Self::Pair { + sr25519::Pair::from_string(suri, password).expect("Invalid phrase") + } + fn pair_from_seed(seed: &Self::Seed) -> Self::Pair { + MiniSecretKey::from_bytes(seed) + .expect("32 bytes can always build a key; qed") + .into() + } + fn ss58_from_pair(pair: &Self::Pair) -> String { pair.public().to_ss58check() } + fn public_from_pair(pair: &Self::Pair) -> Vec { (&pair.public().0[..]).to_owned() } +} + +fn execute>(matches: clap::ArgMatches) where + <::Pair as Pair>::Signature: AsRef<[u8]> + AsMut<[u8]> + Default, + <::Pair as Pair>::Public: Sized + AsRef<[u8]> + Ss58Codec + AsRef<<::Pair as Pair>::Public>, +{ + let password = matches.value_of("password"); match matches.subcommand() { ("generate", Some(_matches)) => { - let mut seed = [0u8; 32]; - OsRng::new().unwrap().fill_bytes(&mut seed[..]); - print_account(&seed); - } + // create a new randomly generated mnemonic phrase + let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English); + C::print_from_phrase(mnemonic.phrase(), password); + }, ("vanity", Some(matches)) => { let desired: String = matches.value_of("pattern").map(str::to_string).unwrap_or_default(); - let key = vanity::generate_key(&desired).expect("Key generation failed"); - println!("Found account with score {}%", key.score); - print_account(&key.seed); + let key = vanity::generate_key::(&desired).expect("Key generation failed"); + C::print_from_seed(&key.seed); } - ("restore", Some(matches)) => { - // This subcommand is probably obsolete, see - // https://github.com/paritytech/substrate/issues/1063 - - let mut raw_seed = matches.value_of("seed") - .map(str::as_bytes) - .expect("seed parameter is required; thus it can't be None; qed"); - - if raw_seed.len() > 32 { - raw_seed = &raw_seed[..32]; - println!("seed is too long and will be truncated to: {}", HexDisplay::from(&raw_seed)); - } - - // Copy the raw_seed into a buffer that already contains ' ' 0x20. - // This will effectively get us padding for seeds shorter than 32. - let mut seed = [' ' as u8; 32]; - let len = raw_seed.len().min(32); - seed[..len].copy_from_slice(&raw_seed[..len]); - print_account(&seed); + ("inspect", Some(matches)) => { + // TODO: Accept public key with derivation path. + let uri = matches.value_of("uri") + .expect("URI parameter is required; thus it can't be None; qed"); + C::print_from_uri(uri, password); }, + ("sign", Some(matches)) => { + let suri = matches.value_of("suri") + .expect("secret URI parameter is required; thus it can't be None; qed"); + let pair = C::pair_from_suri(suri, password); + let mut message = vec![]; + stdin().lock().read_to_end(&mut message).expect("Error reading from stdin"); + if matches.is_present("hex") { + message = hex::decode(&message).expect("Invalid hex in message"); + } + let sig = pair.sign(&message); + println!("{}", hex::encode(&sig)); + } + ("verify", Some(matches)) => { + let sig_data = matches.value_of("sig") + .expect("signature parameter is required; thus it can't be None; qed"); + let mut sig = <::Pair as Pair>::Signature::default(); + let sig_data = hex::decode(sig_data).expect("signature is invalid hex"); + if sig_data.len() != sig.as_ref().len() { + panic!("signature is an invalid length. {} bytes is not the expected value of {} bytes", sig_data.len(), sig.as_ref().len()); + } + sig.as_mut().copy_from_slice(&sig_data); + let uri = matches.value_of("uri") + .expect("public uri parameter is required; thus it can't be None; qed"); + let pubkey = <::Pair as Pair>::Public::from_string(uri).ok().or_else(|| + ::Pair::from_string(uri, password).ok().map(|p| p.public()) + ).expect("Invalid URI; expecting either a secret URI or a public URI."); + let mut message = vec![]; + stdin().lock().read_to_end(&mut message).expect("Error reading from stdin"); + if matches.is_present("hex") { + message = hex::decode(&message).expect("Invalid hex in message"); + } + if <::Pair as Pair>::verify(&sig, &message, &pubkey) { + println!("Signature verifies correctly.") + } else { + println!("Signature invalid.") + } + } _ => print_usage(&matches), } } +fn main() { + let yaml = load_yaml!("cli.yml"); + let matches = clap::App::from_yaml(yaml) + .version(env!("CARGO_PKG_VERSION")) + .get_matches(); + + if matches.is_present("ed25519") { + execute::(matches) + } else { + execute::(matches) + } +} + fn print_usage(matches: &clap::ArgMatches) { println!("{}", matches.usage()); } diff --git a/subkey/src/vanity.rs b/subkey/src/vanity.rs index a621ccd0ef0c9c0d45eea5d9e88b01d03e01f94f..785eb95aa5b203ac5c53e62abea30b6c090259ae 100644 --- a/subkey/src/vanity.rs +++ b/subkey/src/vanity.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2018-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ // along with Substrate. If not, see . use rand::{rngs::OsRng, RngCore}; -use substrate_primitives::ed25519::Pair; +use super::Crypto; fn good_waypoint(done: u64) -> u64 { match done { @@ -38,9 +38,9 @@ fn next_seed(mut seed: [u8; 32]) -> [u8; 32] { /// A structure used to carry both Pair and seed. /// This should usually NOT been used. If unsure, use Pair. -pub struct KeyPair { - pub pair: Pair, - pub seed: [u8; 32], +pub(super) struct KeyPair { + pub pair: C::Pair, + pub seed: C::Seed, pub score: usize, } @@ -57,7 +57,7 @@ fn calculate_score(_desired: &str, key: &str) -> usize { 0 } -pub fn generate_key(desired: &str) -> Result { +pub(super) fn generate_key>(desired: &str) -> Result, &str> { if desired.is_empty() { return Err("Pattern must not be empty"); } @@ -77,8 +77,8 @@ pub fn generate_key(desired: &str) -> Result { OsRng::new().unwrap().fill_bytes(&mut seed[..]); } - let p = Pair::from_seed(&seed); - let ss58 = p.public().to_ss58check(); + let p = C::pair_from_seed(&seed); + let ss58 = C::ss58_from_pair(&p); let score = calculate_score(&desired, &ss58); if score > best || desired.len() < 2 { best = score; @@ -104,12 +104,14 @@ pub fn generate_key(desired: &str) -> Result { #[cfg(test)] mod tests { use super::*; + use super::super::Ed25519; + use substrate_primitives::Pair; #[cfg(feature = "bench")] use test::Bencher; #[test] fn test_generation_with_single_char() { - assert!(generate_key("j").unwrap().pair.public().to_ss58check().contains("j")); + assert!(generate_key::("j").unwrap().pair.public().to_ss58check().contains("j")); } #[test] diff --git a/test-utils/chain-spec-builder/Cargo.lock b/test-utils/chain-spec-builder/Cargo.lock index feccfa14ef41cbdf554d413701c37bbe1349cfb1..2d5311d502037e719be355a1c66e4a8b247e7b73 100644 --- a/test-utils/chain-spec-builder/Cargo.lock +++ b/test-utils/chain-spec-builder/Cargo.lock @@ -1781,7 +1781,6 @@ dependencies = [ "srml-system 0.1.0", "srml-timestamp 0.1.0", "srml-treasury 0.1.0", - "srml-upgrade-key 0.1.0", "substrate-client 0.1.0", "substrate-consensus-aura-primitives 0.1.0", "substrate-keyring 0.1.0", @@ -3006,24 +3005,6 @@ dependencies = [ "substrate-primitives 0.1.0", ] -[[package]] -name = "srml-upgrade-key" -version = "0.1.0" -dependencies = [ - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 0.1.0", - "sr-primitives 0.1.0", - "sr-std 0.1.0", - "srml-consensus 0.1.0", - "srml-support 0.1.0", - "srml-support-procedural 0.1.0", - "srml-system 0.1.0", - "substrate-primitives 0.1.0", -] - [[package]] name = "stable_deref_trait" version = "1.1.1" diff --git a/test-utils/chain-spec-builder/src/cli.yml b/test-utils/chain-spec-builder/src/cli.yml index 08c0233c31090ae4d6a5091651324b25a8c14fcb..f4b1cb7e2eaaab0e5d2df01a6801d36a3de527b8 100644 --- a/test-utils/chain-spec-builder/src/cli.yml +++ b/test-utils/chain-spec-builder/src/cli.yml @@ -16,9 +16,9 @@ args: takes_value: true multiple: true required: true -- upgrade_key_seed: +- sudo_key_seed: short: u - value_name: UPGRADE_KEY_SEED - help: Upgrade key seed + value_name: SUDO_KEY_SEED + help: Sudo key seed takes_value: true required: true diff --git a/test-utils/chain-spec-builder/src/main.rs b/test-utils/chain-spec-builder/src/main.rs index b899f9c1fcab73f863eeb4b4df799dbc8db723e9..c7b4dd99d8ab28c760f37c543be55b0bc245ce52 100644 --- a/test-utils/chain-spec-builder/src/main.rs +++ b/test-utils/chain-spec-builder/src/main.rs @@ -16,11 +16,11 @@ fn genesis_constructor() -> chain_spec::GenesisConfig { .map(chain_spec::get_authority_id_from_seed) .collect(); - let upgrade_key_seed = matches.value_of("upgrade_key_seed").unwrap(); - let upgrade_key = chain_spec::get_authority_id_from_seed(upgrade_key_seed); + let sudo_key_seed = matches.value_of("sudo_key_seed").unwrap(); + let sudo_key = chain_spec::get_authority_id_from_seed(sudo_key_seed); chain_spec::testnet_genesis( authorities, - upgrade_key.into(), + sudo_key.into(), Some(endowed_accounts), ) }