Преглед изворни кода

Merge remote-tracking branch 'origin/fix/issue_1367' into issue_1358

iorveth пре 4 година
родитељ
комит
e8e7f59344
89 измењених фајлова са 12483 додато и 3954 уклоњено
  1. 1 1
      .dockerignore
  2. 57 0
      .env
  3. 10 6
      .github/workflows/run-network-tests.yml
  4. 121 73
      Cargo.lock
  5. 1 0
      Cargo.toml
  6. 1 3
      README.md
  7. 8698 0
      _Cargo.lock
  8. 1 3
      apps.Dockerfile
  9. 55 0
      build.sh
  10. 5 1
      cli/package.json
  11. 5 1
      content-directory-schemas/package.json
  12. 0 39
      docker-compose-with-storage.yml
  13. 141 8
      docker-compose.yml
  14. 8 1
      joystream-node.Dockerfile
  15. 3 57
      node/src/chain_spec/mod.rs
  16. 0 17
      node/src/chain_spec/proposals_config.rs
  17. 6 0
      package.json
  18. 3 0
      pioneer/package.json
  19. 2 0
      query-node/.env
  20. 0 91
      query-node/docker-compose.yml
  21. 10 6
      query-node/package.json
  22. 10 5
      query-node/run-tests.sh
  23. 0 21
      runtime-modules/common/src/origin.rs
  24. 29 0
      runtime-modules/constitution/Cargo.toml
  25. 73 0
      runtime-modules/constitution/src/lib.rs
  26. 78 0
      runtime-modules/constitution/src/tests/mocks.rs
  27. 109 0
      runtime-modules/constitution/src/tests/mod.rs
  28. 0 3
      runtime-modules/forum/src/lib.rs
  29. 2 1
      runtime-modules/membership/Cargo.toml
  30. 1 0
      runtime-modules/membership/src/lib.rs
  31. 41 0
      runtime-modules/membership/src/staking_handler.rs
  32. 3 1
      runtime-modules/proposals/codex/Cargo.toml
  33. 246 423
      runtime-modules/proposals/codex/src/lib.rs
  34. 5 163
      runtime-modules/proposals/codex/src/proposal_types/mod.rs
  35. 0 184
      runtime-modules/proposals/codex/src/proposal_types/parameters.rs
  36. 41 9
      runtime-modules/proposals/codex/src/tests/mock/mod.rs
  37. 98 0
      runtime-modules/proposals/codex/src/tests/mock/staking_handler.rs
  38. 88 507
      runtime-modules/proposals/codex/src/tests/mod.rs
  39. 3 1
      runtime-modules/proposals/discussion/Cargo.toml
  40. 222 0
      runtime-modules/proposals/discussion/src/benchmarking.rs
  41. 115 122
      runtime-modules/proposals/discussion/src/lib.rs
  42. 28 8
      runtime-modules/proposals/discussion/src/tests/mock.rs
  43. 213 78
      runtime-modules/proposals/discussion/src/tests/mod.rs
  44. 17 73
      runtime-modules/proposals/discussion/src/types.rs
  45. 3 5
      runtime-modules/proposals/engine/Cargo.toml
  46. 302 351
      runtime-modules/proposals/engine/src/lib.rs
  47. 0 33
      runtime-modules/proposals/engine/src/tests/mock/balance_manager.rs
  48. 10 15
      runtime-modules/proposals/engine/src/tests/mock/mod.rs
  49. 0 66
      runtime-modules/proposals/engine/src/tests/mock/stakes.rs
  50. 98 0
      runtime-modules/proposals/engine/src/tests/mock/staking_handler.rs
  51. 300 322
      runtime-modules/proposals/engine/src/tests/mod.rs
  52. 157 529
      runtime-modules/proposals/engine/src/types/mod.rs
  53. 71 149
      runtime-modules/proposals/engine/src/types/proposal_statuses.rs
  54. 0 248
      runtime-modules/proposals/engine/src/types/stakes.rs
  55. 2 4
      runtime-modules/working-group/src/lib.rs
  56. 7 0
      runtime/Cargo.toml
  57. 1 0
      runtime/src/integration/mod.rs
  58. 2 1
      runtime/src/integration/proposals/council_elected_handler.rs
  59. 0 2
      runtime/src/integration/proposals/mod.rs
  60. 3 0
      runtime/src/integration/proposals/proposal_encoder.rs
  61. 0 50
      runtime/src/integration/proposals/staking_events_handler.rs
  62. 105 0
      runtime/src/integration/staking_handler.rs
  63. 47 24
      runtime/src/lib.rs
  64. 189 0
      runtime/src/proposals_configuration/defaults.rs
  65. 269 0
      runtime/src/proposals_configuration/mod.rs
  66. 25 0
      runtime/src/proposals_configuration/sample_proposal_parameters.json
  67. 20 0
      runtime/src/proposals_configuration/tests.rs
  68. 48 0
      runtime/src/runtime_api.rs
  69. 116 93
      runtime/src/tests/proposals_integration/mod.rs
  70. 24 9
      runtime/src/tests/proposals_integration/working_group_proposals.rs
  71. 0 8
      rust-builder.Dockerfile
  72. 7 8
      scripts/runtime-code-shasum.sh
  73. 18 13
      setup.sh
  74. 39 0
      start.sh
  75. 1 0
      storage-node/README.md
  76. 0 29
      storage-node/docker-compose.yaml
  77. 3 0
      storage-node/package.json
  78. 3 0
      storage-node/packages/cli/package.json
  79. 3 0
      storage-node/packages/colossus/package.json
  80. 3 0
      storage-node/packages/helios/package.json
  81. 0 38
      storage-node/start-dev.sh
  82. 0 5
      storage-node/stop-dev.sh
  83. 1 1
      tests/network-tests/.env
  84. 3 0
      tests/network-tests/package.json
  85. 5 1
      types/package.json
  86. 3 0
      utils/api-scripts/package.json
  87. 1 1
      utils/api-scripts/src/dev-set-runtime-code.ts
  88. 2 9
      utils/chain-spec-builder/src/main.rs
  89. 42 34
      yarn.lock

+ 1 - 1
.dockerignore

@@ -1,4 +1,4 @@
-**target*
+target/
 **node_modules*
 .tmp/
 .vscode/

+ 57 - 0
.env

@@ -0,0 +1,57 @@
+COMPOSE_PROJECT_NAME=joystream
+
+###########################
+#     Common settings     #
+###########################
+
+# The env variables below are by default used by all services and should be
+# overriden in local env files (e.g. ./generated/indexer) if needed
+# DB config
+DB_NAME=query_node
+DB_USER=postgres
+DB_PASS=postgres
+DB_HOST=localhost
+DB_PORT=5432
+DEBUG=index-builder:*
+TYPEORM_LOGGING=error
+
+###########################
+#    Indexer options      #
+###########################
+
+# Substrate endpoint to source events from
+WS_PROVIDER_ENDPOINT_URI=ws://joystream-node:9944/
+# Block height to start indexing from.
+# Note, that if there are already some indexed events, this setting is ignored
+BLOCK_HEIGHT=0
+
+# Custom types to register for Substrate API
+# TYPE_REGISTER_PACKAGE_NAME=
+# TYPE_REGISTER_PACKAGE_VERSION=
+# TYPE_REGISTER_FUNCTION=
+
+# Redis cache server
+REDIS_URI=redis://localhost:6379/0
+
+###########################
+#    Processor options    #
+###########################
+
+# Where the mapping scripts are located, relative to ./generated/indexer
+TYPES_JSON=../../typedefs.json
+
+# Indexer GraphQL API endpoint to fetch indexed events
+INDEXER_ENDPOINT_URL=http://localhost:4100/graphql
+
+# Block height from which the processor starts. Note that if
+# there are already processed events in the database, this setting is ignored
+BLOCK_HEIGHT=0
+
+###############################
+#    Processor GraphQL API    #
+###############################
+
+GRAPHQL_SERVER_PORT=4002
+GRAPHQL_SERVER_HOST=localhost
+WARTHOG_APP_PORT=4002
+WARTHOG_APP_HOST=localhost

+ 10 - 6
.github/workflows/run-network-tests.yml

@@ -100,7 +100,7 @@ jobs:
       - name: Ensure tests are runnable
         run: yarn workspace network-tests build
       - name: Execute network tests
-        run: RUNTIME=alexandria tests/network-tests/run-tests.sh full
+        run: RUNTIME=babylon tests/network-tests/run-tests.sh full
 
   basic_runtime:
     name: Integration Tests (New Chain)
@@ -148,7 +148,7 @@ jobs:
       - name: Ensure tests are runnable
         run: yarn workspace cd-schemas checks --quiet
       - name: Start chain
-        run: docker-compose up -d
+        run: docker-compose up -d joystream-node
       - name: Initialize the content directory
         run: yarn workspace cd-schemas initialize:dev
 
@@ -202,10 +202,14 @@ jobs:
       - name: Build storage node
         run: yarn workspace storage-node build
       - name: Start Services
-        run: docker-compose --file docker-compose-with-storage.yml up -d
-      - name: Add development storage node and initialize content directory
-        run: DEBUG=* yarn storage-cli dev-init
-      - name: Try uploading
+        run: |
+          docker-compose up -d ipfs
+          docker-compose up -d joystream-node
+      - name: Configure and start development storage node
+        run: |
+          DEBUG=* yarn storage-cli dev-init
+          docker-compose up -d colossus
+      - name: Test uploading
         run: |
           WAIT_TIME=90
           export DEBUG=joystream:*

+ 121 - 73
Cargo.lock

@@ -220,7 +220,7 @@ dependencies = [
  "concurrent-queue",
  "fastrand",
  "futures-lite",
- "once_cell 1.4.1",
+ "once_cell 1.5.2",
  "vec-arena",
 ]
 
@@ -234,7 +234,7 @@ dependencies = [
  "async-io",
  "futures-lite",
  "num_cpus",
- "once_cell 1.4.1",
+ "once_cell 1.5.2",
 ]
 
 [[package]]
@@ -249,7 +249,7 @@ dependencies = [
  "libc",
  "log",
  "nb-connect",
- "once_cell 1.4.1",
+ "once_cell 1.5.2",
  "parking",
  "polling",
  "vec-arena",
@@ -286,7 +286,7 @@ dependencies = [
  "log",
  "memchr",
  "num_cpus",
- "once_cell 1.4.1",
+ "once_cell 1.5.2",
  "pin-project-lite",
  "pin-utils",
  "slab",
@@ -550,7 +550,7 @@ dependencies = [
  "atomic-waker",
  "fastrand",
  "futures-lite",
- "once_cell 1.4.1",
+ "once_cell 1.5.2",
 ]
 
 [[package]]
@@ -1423,11 +1423,11 @@ dependencies = [
  "frame-support-procedural",
  "impl-trait-for-tuples",
  "log",
- "once_cell 1.4.1",
+ "once_cell 1.5.2",
  "parity-scale-codec",
  "paste",
  "serde",
- "smallvec 1.4.2",
+ "smallvec 1.5.0",
  "sp-arithmetic",
  "sp-core",
  "sp-inherents",
@@ -1679,7 +1679,7 @@ version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7c554eb5bf48b2426c4771ab68c6b14468b6e76cc90996f528c3338d761a4d0d"
 dependencies = [
- "once_cell 1.4.1",
+ "once_cell 1.5.2",
 ]
 
 [[package]]
@@ -1905,7 +1905,7 @@ dependencies = [
  "http 0.2.1",
  "indexmap",
  "slab",
- "tokio 0.2.22",
+ "tokio 0.2.23",
  "tokio-util",
  "tracing",
  "tracing-futures",
@@ -2135,7 +2135,7 @@ dependencies = [
  "itoa",
  "pin-project 1.0.1",
  "socket2",
- "tokio 0.2.22",
+ "tokio 0.2.23",
  "tower-service",
  "tracing",
  "want 0.3.0",
@@ -2154,7 +2154,7 @@ dependencies = [
  "log",
  "rustls",
  "rustls-native-certs",
- "tokio 0.2.22",
+ "tokio 0.2.23",
  "tokio-rustls",
  "webpki",
 ]
@@ -2364,11 +2364,15 @@ dependencies = [
  "frame-system",
  "frame-system-benchmarking",
  "frame-system-rpc-runtime-api",
+ "hex-literal",
+ "lazy_static",
+ "lite-json",
  "pallet-authority-discovery",
  "pallet-authorship",
  "pallet-babe",
  "pallet-balances",
  "pallet-common",
+ "pallet-constitution",
  "pallet-content-directory",
  "pallet-content-working-group",
  "pallet-finality-tracker",
@@ -2586,7 +2590,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0315ef2f688e33844400b31f11c263f2b3dc21d8b9355c6891c5f185fae43f9a"
 dependencies = [
  "parity-util-mem",
- "smallvec 1.4.2",
+ "smallvec 1.5.0",
 ]
 
 [[package]]
@@ -2615,7 +2619,7 @@ dependencies = [
  "parking_lot 0.10.2",
  "regex",
  "rocksdb",
- "smallvec 1.4.2",
+ "smallvec 1.5.0",
 ]
 
 [[package]]
@@ -2640,6 +2644,9 @@ name = "lazy_static"
 version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+dependencies = [
+ "spin",
+]
 
 [[package]]
 name = "lazycell"
@@ -2704,7 +2711,7 @@ dependencies = [
  "parity-multiaddr",
  "parking_lot 0.10.2",
  "pin-project 0.4.27",
- "smallvec 1.4.2",
+ "smallvec 1.5.0",
  "wasm-timer",
 ]
 
@@ -2735,7 +2742,7 @@ dependencies = [
  "ring",
  "rw-stream-sink",
  "sha2 0.8.2",
- "smallvec 1.4.2",
+ "smallvec 1.5.0",
  "thiserror",
  "unsigned-varint 0.4.0",
  "void",
@@ -2788,7 +2795,7 @@ dependencies = [
  "prost",
  "prost-build",
  "rand 0.7.3",
- "smallvec 1.4.2",
+ "smallvec 1.5.0",
 ]
 
 [[package]]
@@ -2812,7 +2819,7 @@ dependencies = [
  "prost-build",
  "rand 0.7.3",
  "sha2 0.8.2",
- "smallvec 1.4.2",
+ "smallvec 1.5.0",
  "unsigned-varint 0.4.0",
  "wasm-timer",
 ]
@@ -2829,7 +2836,7 @@ dependencies = [
  "log",
  "prost",
  "prost-build",
- "smallvec 1.4.2",
+ "smallvec 1.5.0",
  "wasm-timer",
 ]
 
@@ -2853,7 +2860,7 @@ dependencies = [
  "prost-build",
  "rand 0.7.3",
  "sha2 0.8.2",
- "smallvec 1.4.2",
+ "smallvec 1.5.0",
  "uint",
  "unsigned-varint 0.4.0",
  "void",
@@ -2877,7 +2884,7 @@ dependencies = [
  "log",
  "net2",
  "rand 0.7.3",
- "smallvec 1.4.2",
+ "smallvec 1.5.0",
  "void",
  "wasm-timer",
 ]
@@ -2982,7 +2989,7 @@ dependencies = [
  "lru 0.6.1",
  "minicbor",
  "rand 0.7.3",
- "smallvec 1.4.2",
+ "smallvec 1.5.0",
  "unsigned-varint 0.5.1",
  "wasm-timer",
 ]
@@ -2998,7 +3005,7 @@ dependencies = [
  "libp2p-core",
  "log",
  "rand 0.7.3",
- "smallvec 1.4.2",
+ "smallvec 1.5.0",
  "void",
  "wasm-timer",
 ]
@@ -3073,7 +3080,7 @@ checksum = "781d9b9f043dcdabc40640807125368596b849fd4d96cdca2dcf052fdf6f33fd"
 dependencies = [
  "futures 0.3.8",
  "libp2p-core",
- "parking_lot 0.11.0",
+ "parking_lot 0.11.1",
  "thiserror",
  "yamux",
 ]
@@ -3143,6 +3150,24 @@ dependencies = [
  "statrs",
 ]
 
+[[package]]
+name = "lite-json"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0460d985423a026b4d9b828a7c6eed1bcf606f476322f3f9b507529686a61715"
+dependencies = [
+ "lite-parser",
+]
+
+[[package]]
+name = "lite-parser"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c50092e40e0ccd1bf2015a10333fde0502ff95b832b0895dc1ca0d7ac6c52f6"
+dependencies = [
+ "paste",
+]
+
 [[package]]
 name = "lock_api"
 version = "0.1.5"
@@ -3163,9 +3188,9 @@ dependencies = [
 
 [[package]]
 name = "lock_api"
-version = "0.4.1"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c"
+checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312"
 dependencies = [
  "scopeguard 1.1.0",
 ]
@@ -3369,7 +3394,7 @@ checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656"
 dependencies = [
  "log",
  "mio",
- "miow 0.3.5",
+ "miow 0.3.6",
  "winapi 0.3.9",
 ]
 
@@ -3398,9 +3423,9 @@ dependencies = [
 
 [[package]]
 name = "miow"
-version = "0.3.5"
+version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e"
+checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897"
 dependencies = [
  "socket2",
  "winapi 0.3.9",
@@ -3464,7 +3489,7 @@ dependencies = [
  "futures 0.3.8",
  "log",
  "pin-project 1.0.1",
- "smallvec 1.4.2",
+ "smallvec 1.5.0",
  "unsigned-varint 0.5.1",
 ]
 
@@ -3653,11 +3678,11 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.4.1"
+version = "1.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad"
+checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
 dependencies = [
- "parking_lot 0.11.0",
+ "parking_lot 0.11.1",
 ]
 
 [[package]]
@@ -3771,6 +3796,20 @@ dependencies = [
  "strum_macros 0.19.4",
 ]
 
+[[package]]
+name = "pallet-constitution"
+version = "1.0.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "parity-scale-codec",
+ "serde",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
 [[package]]
 name = "pallet-content-directory"
 version = "3.1.0"
@@ -3993,12 +4032,13 @@ dependencies = [
 
 [[package]]
 name = "pallet-proposals-codex"
-version = "3.1.0"
+version = "4.0.0"
 dependencies = [
  "frame-support",
  "frame-system",
  "pallet-balances",
  "pallet-common",
+ "pallet-constitution",
  "pallet-governance",
  "pallet-hiring",
  "pallet-membership",
@@ -4024,8 +4064,9 @@ dependencies = [
 
 [[package]]
 name = "pallet-proposals-discussion"
-version = "3.1.0"
+version = "4.0.0"
 dependencies = [
+ "frame-benchmarking",
  "frame-support",
  "frame-system",
  "pallet-balances",
@@ -4042,15 +4083,13 @@ dependencies = [
 
 [[package]]
 name = "pallet-proposals-engine"
-version = "3.1.0"
+version = "4.0.0"
 dependencies = [
  "frame-support",
  "frame-system",
- "mockall",
  "pallet-balances",
  "pallet-common",
  "pallet-membership",
- "pallet-stake",
  "pallet-timestamp",
  "parity-scale-codec",
  "serde",
@@ -4277,7 +4316,7 @@ dependencies = [
  "pallet-transaction-payment-rpc-runtime-api",
  "parity-scale-codec",
  "serde",
- "smallvec 1.4.2",
+ "smallvec 1.5.0",
  "sp-core",
  "sp-io",
  "sp-runtime",
@@ -4404,9 +4443,9 @@ dependencies = [
 
 [[package]]
 name = "parity-multiaddr"
-version = "0.9.4"
+version = "0.9.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22fe99b938abd57507e37f8d4ef30cd74b33c71face2809b37b8beb71bab15ab"
+checksum = "43244a26dc1ddd3097216bb12eaa6cf8a07b060c72718d9ebd60fd297d6401df"
 dependencies = [
  "arrayref",
  "bs58 0.4.0",
@@ -4462,7 +4501,7 @@ dependencies = [
  "libc",
  "log",
  "mio-named-pipes",
- "miow 0.3.5",
+ "miow 0.3.6",
  "rand 0.7.3",
  "tokio 0.1.22",
  "tokio-named-pipes",
@@ -4482,7 +4521,7 @@ dependencies = [
  "parity-util-mem-derive",
  "parking_lot 0.10.2",
  "primitive-types",
- "smallvec 1.4.2",
+ "smallvec 1.5.0",
  "winapi 0.3.9",
 ]
 
@@ -4560,12 +4599,12 @@ dependencies = [
 
 [[package]]
 name = "parking_lot"
-version = "0.11.0"
+version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4893845fa2ca272e647da5d0e46660a314ead9c2fdd9a883aabc32e481a8733"
+checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
 dependencies = [
  "instant",
- "lock_api 0.4.1",
+ "lock_api 0.4.2",
  "parking_lot_core 0.8.0",
 ]
 
@@ -4607,7 +4646,7 @@ dependencies = [
  "cloudabi 0.0.3",
  "libc",
  "redox_syscall",
- "smallvec 1.4.2",
+ "smallvec 1.5.0",
  "winapi 0.3.9",
 ]
 
@@ -4622,7 +4661,7 @@ dependencies = [
  "instant",
  "libc",
  "redox_syscall",
- "smallvec 1.4.2",
+ "smallvec 1.5.0",
  "winapi 0.3.9",
 ]
 
@@ -4823,9 +4862,9 @@ dependencies = [
 
 [[package]]
 name = "primitive-types"
-version = "0.7.2"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c55c21c64d0eaa4d7ed885d959ef2d62d9e488c27c0e02d9aa5ce6c877b7d5f8"
+checksum = "7dd39dcacf71411ba488570da7bbc89b717225e46478b30ba99b92db6b149809"
 dependencies = [
  "fixed-hash",
  "impl-codec",
@@ -4896,7 +4935,7 @@ dependencies = [
  "cfg-if 0.1.10",
  "fnv",
  "lazy_static",
- "parking_lot 0.11.0",
+ "parking_lot 0.11.1",
  "regex",
  "thiserror",
 ]
@@ -5300,13 +5339,13 @@ checksum = "e005d658ad26eacc2b6c506dfde519f4e277e328d0eb3379ca61647d70a8f531"
 
 [[package]]
 name = "ring"
-version = "0.16.15"
+version = "0.16.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "952cd6b98c85bbc30efa1ba5783b8abf12fec8b3287ffa52605b9432313e34e4"
+checksum = "b72b84d47e8ec5a4f2872e8262b8f8256c5be1c938a7d6d3a867a3ba8f722f74"
 dependencies = [
  "cc",
  "libc",
- "once_cell 1.4.1",
+ "once_cell 1.5.2",
  "spin",
  "untrusted",
  "web-sys",
@@ -5572,7 +5611,7 @@ dependencies = [
  "structopt",
  "substrate-prometheus-endpoint",
  "time",
- "tokio 0.2.22",
+ "tokio 0.2.23",
  "tracing",
  "tracing-log",
  "tracing-subscriber",
@@ -6649,9 +6688,9 @@ dependencies = [
 
 [[package]]
 name = "smallvec"
-version = "1.4.2"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252"
+checksum = "7acad6f34eb9e8a259d3283d1e8c1d34d7415943d4895f65cc73813c7396fc85"
 
 [[package]]
 name = "snow"
@@ -7194,7 +7233,7 @@ dependencies = [
  "parity-scale-codec",
  "parking_lot 0.10.2",
  "rand 0.7.3",
- "smallvec 1.4.2",
+ "smallvec 1.5.0",
  "sp-core",
  "sp-externalities",
  "sp-panic-handler",
@@ -7509,7 +7548,7 @@ dependencies = [
  "hyper 0.13.9",
  "log",
  "prometheus",
- "tokio 0.2.22",
+ "tokio 0.2.23",
 ]
 
 [[package]]
@@ -7736,7 +7775,7 @@ checksum = "b0165e045cc2ae1660270ca65e1676dbaab60feb0f91b10f7d0665e9b47e31f2"
 dependencies = [
  "failure",
  "hmac",
- "once_cell 1.4.1",
+ "once_cell 1.5.2",
  "pbkdf2",
  "rand 0.7.3",
  "rustc-hash",
@@ -7755,9 +7794,18 @@ dependencies = [
 
 [[package]]
 name = "tinyvec"
-version = "0.3.4"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "238ce071d267c5710f9d31451efec16c5ee22de34df17cc05e56cbc92e967117"
+checksum = "b78a366903f506d2ad52ca8dc552102ffdd3e937ba8a227f024dc1d1eae28575"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
 
 [[package]]
 name = "tokio"
@@ -7785,9 +7833,9 @@ dependencies = [
 
 [[package]]
 name = "tokio"
-version = "0.2.22"
+version = "0.2.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d34ca54d84bf2b5b4d7d31e901a8464f7b60ac145a284fba25ceb801f2ddccd"
+checksum = "a6d7ad61edd59bfcc7e80dababf0f4aed2e6d5e0ba1659356ae889752dfc12ff"
 dependencies = [
  "bytes 0.5.6",
  "fnv",
@@ -7920,7 +7968,7 @@ checksum = "e12831b255bcfa39dc0436b01e19fea231a37db570686c06ee72c423479f889a"
 dependencies = [
  "futures-core",
  "rustls",
- "tokio 0.2.22",
+ "tokio 0.2.23",
  "webpki",
 ]
 
@@ -8041,7 +8089,7 @@ dependencies = [
  "futures-sink",
  "log",
  "pin-project-lite",
- "tokio 0.2.22",
+ "tokio 0.2.23",
 ]
 
 [[package]]
@@ -8137,7 +8185,7 @@ dependencies = [
  "serde",
  "serde_json",
  "sharded-slab",
- "smallvec 1.4.2",
+ "smallvec 1.5.0",
  "thread_local",
  "tracing",
  "tracing-core",
@@ -8161,7 +8209,7 @@ dependencies = [
  "hashbrown 0.8.2",
  "log",
  "rustc-hex",
- "smallvec 1.4.2",
+ "smallvec 1.5.0",
 ]
 
 [[package]]
@@ -8228,18 +8276,18 @@ dependencies = [
 
 [[package]]
 name = "unicode-normalization"
-version = "0.1.13"
+version = "0.1.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977"
+checksum = "f1e9a0b71dba18b6fa17c7b3dcf1440bb3522552deb2f84bf47dabd9fb7e5570"
 dependencies = [
  "tinyvec",
 ]
 
 [[package]]
 name = "unicode-segmentation"
-version = "1.6.0"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
+checksum = "db8716a166f290ff49dabc18b44aa407cb7c6dbe1aa0971b44b8a24b0ca35aae"
 
 [[package]]
 name = "unicode-width"
@@ -8457,7 +8505,7 @@ checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f"
 dependencies = [
  "futures 0.3.8",
  "js-sys",
- "parking_lot 0.11.0",
+ "parking_lot 0.11.1",
  "pin-utils",
  "wasm-bindgen",
  "wasm-bindgen-futures",
@@ -8627,7 +8675,7 @@ dependencies = [
  "futures 0.3.8",
  "log",
  "nohash-hasher",
- "parking_lot 0.11.0",
+ "parking_lot 0.11.1",
  "rand 0.7.3",
  "static_assertions",
 ]

+ 1 - 0
Cargo.toml

@@ -20,6 +20,7 @@ members = [
 	"runtime-modules/versioned-store-permissions",
 	"runtime-modules/working-group",
 	"runtime-modules/content-directory",
+	"runtime-modules/constitution",
 	"node",
 	"utils/chain-spec-builder/"
 ]

+ 1 - 3
README.md

@@ -108,9 +108,7 @@ A step by step guide to setup a full node and validator on the Joystream testnet
 ### Integration tests
 
 ```bash
-docker-compose up -d
-DEBUG=* yarn workspace network-tests test-run src/scenarios/full.ts
-docker-compose down
+tests/network-tests/run-tests.sh
 ```
 
 ### Contributing

+ 8698 - 0
_Cargo.lock

@@ -0,0 +1,8698 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "Inflector"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
+dependencies = [
+ "lazy_static",
+ "regex",
+]
+
+[[package]]
+name = "addr2line"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
+
+[[package]]
+name = "aead"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331"
+dependencies = [
+ "generic-array 0.14.4",
+]
+
+[[package]]
+name = "aes"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd2bc6d3f370b5666245ff421e231cba4353df936e26986d2918e61a8fd6aef6"
+dependencies = [
+ "aes-soft",
+ "aesni",
+ "block-cipher",
+]
+
+[[package]]
+name = "aes-gcm"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0301c9e9c443494d970a07885e8cf3e587bae8356a1d5abd0999068413f7205f"
+dependencies = [
+ "aead",
+ "aes",
+ "block-cipher",
+ "ghash",
+ "subtle 2.3.0",
+]
+
+[[package]]
+name = "aes-soft"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63dd91889c49327ad7ef3b500fd1109dbd3c509a03db0d4a9ce413b79f575cb6"
+dependencies = [
+ "block-cipher",
+ "byteorder 1.3.4",
+ "opaque-debug 0.3.0",
+]
+
+[[package]]
+name = "aesni"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a6fe808308bb07d393e2ea47780043ec47683fcf19cf5efc8ca51c50cc8c68a"
+dependencies = [
+ "block-cipher",
+ "opaque-debug 0.3.0",
+]
+
+[[package]]
+name = "ahash"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29661b60bec623f0586702976ff4d0c9942dcb6723161c2df0eea78455cfedfb"
+dependencies = [
+ "const-random",
+]
+
+[[package]]
+name = "ahash"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217"
+
+[[package]]
+name = "ahash"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6789e291be47ace86a60303502173d84af8327e3627ecf334356ee0f87a164c"
+
+[[package]]
+name = "aho-corasick"
+version = "0.7.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "alga"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f823d037a7ec6ea2197046bafd4ae150e6bc36f9ca347404f46a46823fa84f2"
+dependencies = [
+ "approx",
+ "num-complex",
+ "num-traits",
+]
+
+[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+dependencies = [
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "ansi_term"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
+dependencies = [
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7"
+
+[[package]]
+name = "approx"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "arc-swap"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034"
+
+[[package]]
+name = "arrayref"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
+
+[[package]]
+name = "arrayvec"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
+dependencies = [
+ "nodrop",
+]
+
+[[package]]
+name = "arrayvec"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
+
+[[package]]
+name = "asn1_der"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fce6b6a0ffdafebd82c87e79e3f40e8d2c523e5fea5566ff6b90509bf98d638"
+dependencies = [
+ "asn1_der_derive",
+]
+
+[[package]]
+name = "asn1_der_derive"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d0864d84b8e07b145449be9a8537db86bf9de5ce03b913214694643b4743502"
+dependencies = [
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "async-channel"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59740d83946db6a5af71ae25ddf9562c2b176b2ca42cf99a455f09f4a220d6b9"
+dependencies = [
+ "concurrent-queue",
+ "event-listener",
+ "futures-core",
+]
+
+[[package]]
+name = "async-executor"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb877970c7b440ead138f6321a3b5395d6061183af779340b65e20c0fede9146"
+dependencies = [
+ "async-task",
+ "concurrent-queue",
+ "fastrand",
+ "futures-lite",
+ "once_cell 1.4.1",
+ "vec-arena",
+]
+
+[[package]]
+name = "async-global-executor"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73079b49cd26b8fd5a15f68fc7707fc78698dc2a3d61430f2a7a9430230dfa04"
+dependencies = [
+ "async-executor",
+ "async-io",
+ "futures-lite",
+ "num_cpus",
+ "once_cell 1.4.1",
+]
+
+[[package]]
+name = "async-io"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40a0b2bb8ae20fede194e779150fe283f65a4a08461b496de546ec366b174ad9"
+dependencies = [
+ "concurrent-queue",
+ "fastrand",
+ "futures-lite",
+ "libc",
+ "log",
+ "nb-connect",
+ "once_cell 1.4.1",
+ "parking",
+ "polling",
+ "vec-arena",
+ "waker-fn",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "async-mutex"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e"
+dependencies = [
+ "event-listener",
+]
+
+[[package]]
+name = "async-std"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7e82538bc65a25dbdff70e4c5439d52f068048ab97cdea0acd73f131594caa1"
+dependencies = [
+ "async-global-executor",
+ "async-io",
+ "async-mutex",
+ "blocking",
+ "crossbeam-utils 0.8.0",
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-lite",
+ "gloo-timers",
+ "kv-log-macro",
+ "log",
+ "memchr",
+ "num_cpus",
+ "once_cell 1.4.1",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+ "wasm-bindgen-futures",
+]
+
+[[package]]
+name = "async-task"
+version = "4.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0"
+
+[[package]]
+name = "async-tls"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df097e3f506bec0e1a24f06bb3c962c228f36671de841ff579cb99f371772634"
+dependencies = [
+ "futures 0.3.8",
+ "rustls",
+ "webpki",
+ "webpki-roots 0.19.0",
+]
+
+[[package]]
+name = "async-trait"
+version = "0.1.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b246867b8b3b6ae56035f1eb1ed557c1d8eae97f0d53696138a50fa0e3a3b8c0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "atomic"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64f46ca51dca4837f1520754d1c8c36636356b81553d928dc9c177025369a06e"
+
+[[package]]
+name = "atomic-waker"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a"
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "autocfg"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "backtrace"
+version = "0.3.54"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2baad346b2d4e94a24347adeee9c7a93f412ee94b9cc26e5b59dea23848e9f28"
+dependencies = [
+ "addr2line",
+ "cfg-if 1.0.0",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+]
+
+[[package]]
+name = "base58"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83"
+
+[[package]]
+name = "base64"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
+
+[[package]]
+name = "base64"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
+
+[[package]]
+name = "bindgen"
+version = "0.54.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "66c0bb6167449588ff70803f4127f0684f9063097eca5016f37eb52b92c2cf36"
+dependencies = [
+ "bitflags",
+ "cexpr",
+ "cfg-if 0.1.10",
+ "clang-sys",
+ "clap",
+ "env_logger",
+ "lazy_static",
+ "lazycell",
+ "log",
+ "peeking_take_while",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash",
+ "shlex",
+ "which",
+]
+
+[[package]]
+name = "bip39"
+version = "0.6.0-beta.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7059804e226b3ac116519a252d7f5fb985a5ccc0e93255e036a5f7e7283323f4"
+dependencies = [
+ "failure",
+ "hashbrown 0.1.8",
+ "hmac",
+ "once_cell 0.1.8",
+ "pbkdf2",
+ "rand 0.6.5",
+ "sha2 0.8.2",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+
+[[package]]
+name = "bitmask"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5da9b3d9f6f585199287a473f4f8dfab6566cf827d15c00c219f53c645687ead"
+
+[[package]]
+name = "bitvec"
+version = "0.17.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c"
+dependencies = [
+ "either",
+ "radium",
+]
+
+[[package]]
+name = "blake2"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10a5720225ef5daecf08657f23791354e1685a8c91a4c60c7f3d3b2892f978f4"
+dependencies = [
+ "crypto-mac 0.8.0",
+ "digest 0.9.0",
+ "opaque-debug 0.3.0",
+]
+
+[[package]]
+name = "blake2-rfc"
+version = "0.2.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400"
+dependencies = [
+ "arrayvec 0.4.12",
+ "constant_time_eq",
+]
+
+[[package]]
+name = "blake2b_simd"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587"
+dependencies = [
+ "arrayref",
+ "arrayvec 0.5.2",
+ "constant_time_eq",
+]
+
+[[package]]
+name = "blake2s_simd"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e461a7034e85b211a4acb57ee2e6730b32912b06c08cc242243c39fc21ae6a2"
+dependencies = [
+ "arrayref",
+ "arrayvec 0.5.2",
+ "constant_time_eq",
+]
+
+[[package]]
+name = "block-buffer"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
+dependencies = [
+ "block-padding 0.1.5",
+ "byte-tools",
+ "byteorder 1.3.4",
+ "generic-array 0.12.3",
+]
+
+[[package]]
+name = "block-buffer"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
+dependencies = [
+ "block-padding 0.2.1",
+ "generic-array 0.14.4",
+]
+
+[[package]]
+name = "block-cipher"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f337a3e6da609650eb74e02bc9fac7b735049f7623ab12f2e4c719316fcc7e80"
+dependencies = [
+ "generic-array 0.14.4",
+]
+
+[[package]]
+name = "block-padding"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
+dependencies = [
+ "byte-tools",
+]
+
+[[package]]
+name = "block-padding"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
+
+[[package]]
+name = "blocking"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9"
+dependencies = [
+ "async-channel",
+ "async-task",
+ "atomic-waker",
+ "fastrand",
+ "futures-lite",
+ "once_cell 1.4.1",
+]
+
+[[package]]
+name = "bs58"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb"
+
+[[package]]
+name = "bs58"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3"
+
+[[package]]
+name = "bstr"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "473fc6b38233f9af7baa94fb5852dca389e3d95b8e21c8e3719301462c5d9faf"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820"
+
+[[package]]
+name = "byte-slice-cast"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3"
+
+[[package]]
+name = "byte-tools"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
+
+[[package]]
+name = "byteorder"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
+
+[[package]]
+name = "byteorder"
+version = "1.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
+
+[[package]]
+name = "bytes"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
+dependencies = [
+ "byteorder 1.3.4",
+ "either",
+ "iovec",
+]
+
+[[package]]
+name = "bytes"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
+
+[[package]]
+name = "c_linked_list"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4964518bd3b4a8190e832886cdc0da9794f12e8e6c1613a9e90ff331c4c8724b"
+
+[[package]]
+name = "cache-padded"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba"
+
+[[package]]
+name = "cc"
+version = "1.0.62"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40"
+dependencies = [
+ "jobserver",
+]
+
+[[package]]
+name = "cexpr"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27"
+dependencies = [
+ "nom",
+]
+
+[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "chacha20"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "244fbce0d47e97e8ef2f63b81d5e05882cb518c68531eb33194990d7b7e85845"
+dependencies = [
+ "stream-cipher",
+ "zeroize",
+]
+
+[[package]]
+name = "chacha20poly1305"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9bf18d374d66df0c05cdddd528a7db98f78c28e2519b120855c4f84c5027b1f5"
+dependencies = [
+ "aead",
+ "chacha20",
+ "poly1305",
+ "stream-cipher",
+ "zeroize",
+]
+
+[[package]]
+name = "chain-spec-builder"
+version = "3.1.1"
+dependencies = [
+ "ansi_term 0.12.1",
+ "enum-utils",
+ "joystream-node",
+ "rand 0.7.3",
+ "sc-chain-spec",
+ "sc-keystore",
+ "sc-telemetry",
+ "sp-core",
+ "structopt",
+]
+
+[[package]]
+name = "chrono"
+version = "0.4.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
+dependencies = [
+ "js-sys",
+ "libc",
+ "num-integer",
+ "num-traits",
+ "time",
+ "wasm-bindgen",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "clang-sys"
+version = "0.29.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe6837df1d5cba2397b835c8530f51723267e16abbf83892e9e5af4f0e5dd10a"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
+[[package]]
+name = "clap"
+version = "2.33.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
+dependencies = [
+ "ansi_term 0.11.0",
+ "atty",
+ "bitflags",
+ "strsim",
+ "textwrap",
+ "unicode-width",
+ "vec_map",
+]
+
+[[package]]
+name = "cloudabi"
+version = "0.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "cloudabi"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "concurrent-queue"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3"
+dependencies = [
+ "cache-padded",
+]
+
+[[package]]
+name = "console_error_panic_hook"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211"
+dependencies = [
+ "cfg-if 0.1.10",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "console_log"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e7871d2947441b0fdd8e2bd1ce2a2f75304f896582c0d572162d48290683c48"
+dependencies = [
+ "log",
+ "web-sys",
+]
+
+[[package]]
+name = "const-random"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02dc82c12dc2ee6e1ded861cf7d582b46f66f796d1b6c93fa28b911ead95da02"
+dependencies = [
+ "const-random-macro",
+ "proc-macro-hack",
+]
+
+[[package]]
+name = "const-random-macro"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc757bbb9544aa296c2ae00c679e81f886b37e28e59097defe0cf524306f6685"
+dependencies = [
+ "getrandom 0.2.0",
+ "proc-macro-hack",
+]
+
+[[package]]
+name = "const_fn"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c478836e029dcef17fb47c89023448c64f781a046e0300e257ad8225ae59afab"
+
+[[package]]
+name = "constant_time_eq"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
+
+[[package]]
+name = "core-foundation"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac"
+
+[[package]]
+name = "cpuid-bool"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
+
+[[package]]
+name = "crc32fast"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
+dependencies = [
+ "cfg-if 1.0.0",
+]
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
+dependencies = [
+ "cfg-if 1.0.0",
+ "crossbeam-utils 0.8.0",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285"
+dependencies = [
+ "crossbeam-epoch 0.8.2",
+ "crossbeam-utils 0.7.2",
+ "maybe-uninit",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
+dependencies = [
+ "cfg-if 1.0.0",
+ "crossbeam-epoch 0.9.0",
+ "crossbeam-utils 0.8.0",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
+dependencies = [
+ "autocfg 1.0.1",
+ "cfg-if 0.1.10",
+ "crossbeam-utils 0.7.2",
+ "lazy_static",
+ "maybe-uninit",
+ "memoffset",
+ "scopeguard 1.1.0",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0f606a85340376eef0d6d8fec399e6d4a544d648386c6645eb6d0653b27d9f"
+dependencies = [
+ "cfg-if 1.0.0",
+ "const_fn",
+ "crossbeam-utils 0.8.0",
+ "lazy_static",
+ "memoffset",
+ "scopeguard 1.1.0",
+]
+
+[[package]]
+name = "crossbeam-queue"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
+dependencies = [
+ "cfg-if 0.1.10",
+ "crossbeam-utils 0.7.2",
+ "maybe-uninit",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
+dependencies = [
+ "autocfg 1.0.1",
+ "cfg-if 0.1.10",
+ "lazy_static",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec91540d98355f690a86367e566ecad2e9e579f230230eb7c21398372be73ea5"
+dependencies = [
+ "autocfg 1.0.1",
+ "cfg-if 1.0.0",
+ "const_fn",
+ "lazy_static",
+]
+
+[[package]]
+name = "crunchy"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+
+[[package]]
+name = "crypto-mac"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
+dependencies = [
+ "generic-array 0.12.3",
+ "subtle 1.0.0",
+]
+
+[[package]]
+name = "crypto-mac"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab"
+dependencies = [
+ "generic-array 0.14.4",
+ "subtle 2.3.0",
+]
+
+[[package]]
+name = "ct-logs"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c8e13110a84b6315df212c045be706af261fd364791cad863285439ebba672e"
+dependencies = [
+ "sct",
+]
+
+[[package]]
+name = "cuckoofilter"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8dd43f7cfaffe0a386636a10baea2ee05cc50df3b77bea4a456c9572a939bf1f"
+dependencies = [
+ "byteorder 0.5.3",
+ "rand 0.3.23",
+]
+
+[[package]]
+name = "curve25519-dalek"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d85653f070353a16313d0046f173f70d1aadd5b42600a14de626f0dfb3473a5"
+dependencies = [
+ "byteorder 1.3.4",
+ "digest 0.8.1",
+ "rand_core 0.5.1",
+ "subtle 2.3.0",
+ "zeroize",
+]
+
+[[package]]
+name = "curve25519-dalek"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8492de420e9e60bc9a1d66e2dbb91825390b738a388606600663fc529b4b307"
+dependencies = [
+ "byteorder 1.3.4",
+ "digest 0.9.0",
+ "rand_core 0.5.1",
+ "subtle 2.3.0",
+ "zeroize",
+]
+
+[[package]]
+name = "data-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "993a608597367c6377b258c25d7120740f00ed23a2252b729b1932dd7866f908"
+
+[[package]]
+name = "derive_more"
+version = "0.99.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41cb0e6161ad61ed084a36ba71fbba9e3ac5aee3606fb607fe08da6acbcf3d8c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "difference"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
+
+[[package]]
+name = "digest"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
+dependencies = [
+ "generic-array 0.12.3",
+]
+
+[[package]]
+name = "digest"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
+dependencies = [
+ "generic-array 0.14.4",
+]
+
+[[package]]
+name = "directories"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c"
+dependencies = [
+ "cfg-if 0.1.10",
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a"
+dependencies = [
+ "libc",
+ "redox_users",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "dns-parser"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea"
+dependencies = [
+ "byteorder 1.3.4",
+ "quick-error",
+]
+
+[[package]]
+name = "downcast"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bb454f0228b18c7f4c3b0ebbee346ed9c52e7443b0999cd543ff3571205701d"
+
+[[package]]
+name = "dyn-clonable"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e9232f0e607a262ceb9bd5141a3dfb3e4db6994b31989bbfd845878cba59fd4"
+dependencies = [
+ "dyn-clonable-impl",
+ "dyn-clone",
+]
+
+[[package]]
+name = "dyn-clonable-impl"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "dyn-clone"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d55796afa1b20c2945ca8eabfc421839f2b766619209f1ede813cf2484f31804"
+
+[[package]]
+name = "ed25519"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37c66a534cbb46ab4ea03477eae19d5c22c01da8258030280b7bd9d8433fb6ef"
+dependencies = [
+ "signature",
+]
+
+[[package]]
+name = "ed25519-dalek"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d"
+dependencies = [
+ "curve25519-dalek 3.0.0",
+ "ed25519",
+ "rand 0.7.3",
+ "serde",
+ "sha2 0.9.2",
+ "zeroize",
+]
+
+[[package]]
+name = "either"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+
+[[package]]
+name = "enum-utils"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed327f716d0d351d86c9fd3398d20ee39ad8f681873cc081da2ca1c10fed398a"
+dependencies = [
+ "enum-utils-from-str",
+ "failure",
+ "proc-macro2",
+ "quote",
+ "serde_derive_internals",
+ "syn",
+]
+
+[[package]]
+name = "enum-utils-from-str"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d49be08bad6e4ca87b2b8e74146987d4e5cb3b7512efa50ef505b51a22227ee1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+]
+
+[[package]]
+name = "env_logger"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
+dependencies = [
+ "atty",
+ "humantime",
+ "log",
+ "regex",
+ "termcolor",
+]
+
+[[package]]
+name = "environmental"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6576a1755ddffd988788025e75bce9e74b018f7cc226198fe931d077911c6d7e"
+
+[[package]]
+name = "erased-serde"
+version = "0.3.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ca8b296792113e1500fd935ae487be6e00ce318952a6880555554824d6ebf38"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "event-listener"
+version = "2.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59"
+
+[[package]]
+name = "exit-future"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e43f2f1833d64e33f15592464d6fdd70f349dda7b1a53088eb83cd94014008c5"
+dependencies = [
+ "futures 0.3.8",
+]
+
+[[package]]
+name = "failure"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86"
+dependencies = [
+ "backtrace",
+ "failure_derive",
+]
+
+[[package]]
+name = "failure_derive"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
+name = "fake-simd"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
+
+[[package]]
+name = "fastrand"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca5faf057445ce5c9d4329e382b2ce7ca38550ef3b73a5348362d5f24e0c7fe3"
+dependencies = [
+ "instant",
+]
+
+[[package]]
+name = "fdlimit"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c4c9e43643f5a3be4ca5b67d26b98031ff9db6806c3440ae32e02e3ceac3f1b"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "finality-grandpa"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8feb87a63249689640ac9c011742c33139204e3c134293d3054022276869133b"
+dependencies = [
+ "either",
+ "futures 0.3.8",
+ "futures-timer 2.0.2",
+ "log",
+ "num-traits",
+ "parity-scale-codec",
+ "parking_lot 0.9.0",
+]
+
+[[package]]
+name = "fixed-hash"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11498d382790b7a8f2fd211780bec78619bba81cdad3a283997c0c41f836759c"
+dependencies = [
+ "byteorder 1.3.4",
+ "rand 0.7.3",
+ "rustc-hex",
+ "static_assertions",
+]
+
+[[package]]
+name = "fixedbitset"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
+
+[[package]]
+name = "flate2"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7411863d55df97a419aa64cb4d2f167103ea9d767e2c54a1868b7ac3f6b47129"
+dependencies = [
+ "cfg-if 1.0.0",
+ "crc32fast",
+ "libc",
+ "libz-sys",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "float-cmp"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "fork-tree"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "parity-scale-codec",
+]
+
+[[package]]
+name = "form_urlencoded"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00"
+dependencies = [
+ "matches",
+ "percent-encoding 2.1.0",
+]
+
+[[package]]
+name = "fragile"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69a039c3498dc930fe810151a34ba0c1c70b02b8625035592e74432f678591f2"
+
+[[package]]
+name = "frame-benchmarking"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "linregress",
+ "parity-scale-codec",
+ "paste",
+ "sp-api",
+ "sp-io",
+ "sp-runtime",
+ "sp-runtime-interface",
+ "sp-std",
+ "sp-storage",
+]
+
+[[package]]
+name = "frame-benchmarking-cli"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-benchmarking",
+ "parity-scale-codec",
+ "sc-cli",
+ "sc-client-db",
+ "sc-executor",
+ "sc-service",
+ "sp-core",
+ "sp-externalities",
+ "sp-runtime",
+ "sp-state-machine",
+ "structopt",
+]
+
+[[package]]
+name = "frame-executive"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "parity-scale-codec",
+ "serde",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+ "sp-tracing",
+]
+
+[[package]]
+name = "frame-metadata"
+version = "12.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "parity-scale-codec",
+ "serde",
+ "sp-core",
+ "sp-std",
+]
+
+[[package]]
+name = "frame-support"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "bitmask",
+ "frame-metadata",
+ "frame-support-procedural",
+ "impl-trait-for-tuples",
+ "log",
+ "once_cell 1.4.1",
+ "parity-scale-codec",
+ "paste",
+ "serde",
+ "smallvec 1.4.2",
+ "sp-arithmetic",
+ "sp-core",
+ "sp-inherents",
+ "sp-io",
+ "sp-runtime",
+ "sp-state-machine",
+ "sp-std",
+ "sp-tracing",
+]
+
+[[package]]
+name = "frame-support-procedural"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-support-procedural-tools",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "frame-support-procedural-tools"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-support-procedural-tools-derive",
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "frame-support-procedural-tools-derive"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "frame-system"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-support",
+ "impl-trait-for-tuples",
+ "parity-scale-codec",
+ "serde",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+ "sp-version",
+]
+
+[[package]]
+name = "frame-system-benchmarking"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "parity-scale-codec",
+ "sp-core",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "frame-system-rpc-runtime-api"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "parity-scale-codec",
+ "sp-api",
+]
+
+[[package]]
+name = "fs-swap"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "921d332c89b3b61a826de38c61ee5b6e02c56806cade1b0e5d81bd71f57a71bb"
+dependencies = [
+ "lazy_static",
+ "libc",
+ "libloading",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "fuchsia-cprng"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
+
+[[package]]
+name = "fuchsia-zircon"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
+dependencies = [
+ "bitflags",
+ "fuchsia-zircon-sys",
+]
+
+[[package]]
+name = "fuchsia-zircon-sys"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
+
+[[package]]
+name = "futures"
+version = "0.1.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c7e4c2612746b0df8fed4ce0c69156021b704c9aefa360311c04e6e9e002eed"
+
+[[package]]
+name = "futures"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b3b0c040a1fe6529d30b3c5944b280c7f0dcb2930d2c3062bca967b602583d0"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b7109687aa4e177ef6fe84553af6280ef2778bdb7783ba44c9dc3399110fe64"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-channel-preview"
+version = "0.3.0-alpha.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5e5f4df964fa9c1c2f8bddeb5c3611631cacd93baf810fc8bb2fb4b495c263a"
+dependencies = [
+ "futures-core-preview",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "847ce131b72ffb13b6109a221da9ad97a64cbe48feb1028356b836b47b8f1748"
+
+[[package]]
+name = "futures-core-preview"
+version = "0.3.0-alpha.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b35b6263fb1ef523c3056565fa67b1d16f0a8604ff12b11b08c25f28a734c60a"
+
+[[package]]
+name = "futures-cpupool"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
+dependencies = [
+ "futures 0.1.30",
+ "num_cpus",
+]
+
+[[package]]
+name = "futures-diagnose"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdcef58a173af8148b182684c9f2d5250875adbcaff7b5794073894f9d8634a9"
+dependencies = [
+ "futures 0.1.30",
+ "futures 0.3.8",
+ "lazy_static",
+ "log",
+ "parking_lot 0.9.0",
+ "pin-project 0.4.27",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "futures-executor"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4caa2b2b68b880003057c1dd49f1ed937e38f22fcf6c212188a121f08cf40a65"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+ "num_cpus",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "611834ce18aaa1bd13c4b374f5d653e1027cf99b6b502584ff8c9a64413b30bb"
+
+[[package]]
+name = "futures-lite"
+version = "1.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e6c079abfac3ab269e2927ec048dabc89d009ebfdda6b8ee86624f30c689658"
+dependencies = [
+ "fastrand",
+ "futures-core",
+ "futures-io",
+ "memchr",
+ "parking",
+ "pin-project-lite",
+ "waker-fn",
+]
+
+[[package]]
+name = "futures-macro"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77408a692f1f97bcc61dc001d752e00643408fbc922e4d634c655df50d595556"
+dependencies = [
+ "proc-macro-hack",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f878195a49cee50e006b02b93cf7e0a95a38ac7b776b4c4d9cc1207cd20fcb3d"
+
+[[package]]
+name = "futures-task"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c554eb5bf48b2426c4771ab68c6b14468b6e76cc90996f528c3338d761a4d0d"
+dependencies = [
+ "once_cell 1.4.1",
+]
+
+[[package]]
+name = "futures-timer"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1de7508b218029b0f01662ed8f61b1c964b3ae99d6f25462d0f55a595109df6"
+
+[[package]]
+name = "futures-timer"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
+dependencies = [
+ "gloo-timers",
+ "send_wrapper 0.4.0",
+]
+
+[[package]]
+name = "futures-util"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d304cff4a7b99cfb7986f7d43fbe93d175e72e704a8860787cc95e9ffd85cbd2"
+dependencies = [
+ "futures 0.1.30",
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project 1.0.1",
+ "pin-utils",
+ "proc-macro-hack",
+ "proc-macro-nested",
+ "slab",
+]
+
+[[package]]
+name = "futures-util-preview"
+version = "0.3.0-alpha.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ce968633c17e5f97936bd2797b6e38fb56cf16a7422319f7ec2e30d3c470e8d"
+dependencies = [
+ "futures-channel-preview",
+ "futures-core-preview",
+ "pin-utils",
+ "slab",
+]
+
+[[package]]
+name = "futures_codec"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce54d63f8b0c75023ed920d46fd71d0cbbb830b0ee012726b5b4f506fb6dea5b"
+dependencies = [
+ "bytes 0.5.6",
+ "futures 0.3.8",
+ "memchr",
+ "pin-project 0.4.27",
+]
+
+[[package]]
+name = "gcc"
+version = "0.3.55"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
+
+[[package]]
+name = "generator"
+version = "0.6.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8cdc09201b2e8ca1b19290cf7e65de2246b8e91fb6874279722189c4de7b94dc"
+dependencies = [
+ "cc",
+ "libc",
+ "log",
+ "rustc_version",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
+dependencies = [
+ "typenum",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "get_if_addrs"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abddb55a898d32925f3148bd281174a68eeb68bbfd9a5938a57b18f506ee4ef7"
+dependencies = [
+ "c_linked_list",
+ "get_if_addrs-sys",
+ "libc",
+ "winapi 0.2.8",
+]
+
+[[package]]
+name = "get_if_addrs-sys"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d04f9fb746cf36b191c00f3ede8bde9c8e64f9f4b05ae2694a9ccf5e3f5ab48"
+dependencies = [
+ "gcc",
+ "libc",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.1.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
+dependencies = [
+ "cfg-if 0.1.10",
+ "libc",
+ "wasi 0.9.0+wasi-snapshot-preview1",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4"
+dependencies = [
+ "cfg-if 0.1.10",
+ "libc",
+ "wasi 0.9.0+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "ghash"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6e27f0689a6e15944bdce7e45425efb87eaa8ab0c6e87f11d0987a9133e2531"
+dependencies = [
+ "polyval",
+]
+
+[[package]]
+name = "gimli"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
+
+[[package]]
+name = "glob"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
+
+[[package]]
+name = "globset"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c152169ef1e421390738366d2f796655fec62621dabbd0fd476f905934061e4a"
+dependencies = [
+ "aho-corasick",
+ "bstr",
+ "fnv",
+ "log",
+ "regex",
+]
+
+[[package]]
+name = "gloo-timers"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "h2"
+version = "0.1.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462"
+dependencies = [
+ "byteorder 1.3.4",
+ "bytes 0.4.12",
+ "fnv",
+ "futures 0.1.30",
+ "http 0.1.21",
+ "indexmap",
+ "log",
+ "slab",
+ "string",
+ "tokio-io",
+]
+
+[[package]]
+name = "h2"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535"
+dependencies = [
+ "bytes 0.5.6",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "http 0.2.1",
+ "indexmap",
+ "slab",
+ "tokio 0.2.22",
+ "tokio-util",
+ "tracing",
+ "tracing-futures",
+]
+
+[[package]]
+name = "hash-db"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a"
+
+[[package]]
+name = "hash256-std-hasher"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2"
+dependencies = [
+ "crunchy",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da"
+dependencies = [
+ "byteorder 1.3.4",
+ "scopeguard 0.3.3",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e6073d0ca812575946eb5f35ff68dbe519907b25c42530389ff946dc84c6ead"
+dependencies = [
+ "ahash 0.2.19",
+ "autocfg 0.1.7",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25"
+dependencies = [
+ "ahash 0.3.8",
+ "autocfg 1.0.1",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
+dependencies = [
+ "ahash 0.4.6",
+]
+
+[[package]]
+name = "heck"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "hex"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
+
+[[package]]
+name = "hex-literal"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "hex-literal"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5af1f635ef1bc545d78392b136bfe1c9809e029023c84a3638a864a10b8819c8"
+
+[[package]]
+name = "hex_fmt"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f"
+
+[[package]]
+name = "hmac"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695"
+dependencies = [
+ "crypto-mac 0.7.0",
+ "digest 0.8.1",
+]
+
+[[package]]
+name = "hmac-drbg"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6e570451493f10f6581b48cdd530413b63ea9e780f544bfd3bdcaa0d89d1a7b"
+dependencies = [
+ "digest 0.8.1",
+ "generic-array 0.12.3",
+ "hmac",
+]
+
+[[package]]
+name = "http"
+version = "0.1.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0"
+dependencies = [
+ "bytes 0.4.12",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d569972648b2c512421b5f2a405ad6ac9666547189d0c5477a3f200f3e02f9"
+dependencies = [
+ "bytes 0.5.6",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d"
+dependencies = [
+ "bytes 0.4.12",
+ "futures 0.1.30",
+ "http 0.1.21",
+ "tokio-buf",
+]
+
+[[package]]
+name = "http-body"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b"
+dependencies = [
+ "bytes 0.5.6",
+ "http 0.2.1",
+]
+
+[[package]]
+name = "httparse"
+version = "1.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
+
+[[package]]
+name = "httpdate"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47"
+
+[[package]]
+name = "humantime"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
+dependencies = [
+ "quick-error",
+]
+
+[[package]]
+name = "hyper"
+version = "0.12.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9dbe6ed1438e1f8ad955a4701e9a944938e9519f6888d12d8558b645e247d5f6"
+dependencies = [
+ "bytes 0.4.12",
+ "futures 0.1.30",
+ "futures-cpupool",
+ "h2 0.1.26",
+ "http 0.1.21",
+ "http-body 0.1.0",
+ "httparse",
+ "iovec",
+ "itoa",
+ "log",
+ "net2",
+ "rustc_version",
+ "time",
+ "tokio 0.1.22",
+ "tokio-buf",
+ "tokio-executor 0.1.10",
+ "tokio-io",
+ "tokio-reactor",
+ "tokio-tcp",
+ "tokio-threadpool",
+ "tokio-timer",
+ "want 0.2.0",
+]
+
+[[package]]
+name = "hyper"
+version = "0.13.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6ad767baac13b44d4529fcf58ba2cd0995e36e7b435bc5b039de6f47e880dbf"
+dependencies = [
+ "bytes 0.5.6",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "h2 0.2.7",
+ "http 0.2.1",
+ "http-body 0.3.1",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project 1.0.1",
+ "socket2",
+ "tokio 0.2.22",
+ "tower-service",
+ "tracing",
+ "want 0.3.0",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37743cc83e8ee85eacfce90f2f4102030d9ff0a95244098d781e9bee4a90abb6"
+dependencies = [
+ "bytes 0.5.6",
+ "ct-logs",
+ "futures-util",
+ "hyper 0.13.9",
+ "log",
+ "rustls",
+ "rustls-native-certs",
+ "tokio 0.2.22",
+ "tokio-rustls",
+ "webpki",
+]
+
+[[package]]
+name = "idna"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
+dependencies = [
+ "matches",
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "idna"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
+dependencies = [
+ "matches",
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "impl-codec"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1be51a921b067b0eaca2fad532d9400041561aa922221cc65f95a85641c6bf53"
+dependencies = [
+ "parity-scale-codec",
+]
+
+[[package]]
+name = "impl-serde"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b47ca4d2b6931707a55fce5cf66aff80e2178c8b63bbb4ecb5695cbc870ddf6f"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "impl-trait-for-tuples"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ef5550a42e3740a0e71f909d4c861056a284060af885ae7aa6242820f920d9d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2"
+dependencies = [
+ "autocfg 1.0.1",
+ "hashbrown 0.9.1",
+]
+
+[[package]]
+name = "instant"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb1fc4429a33e1f80d41dc9fea4d108a88bec1de8053878898ae448a0b52f613"
+dependencies = [
+ "cfg-if 1.0.0",
+]
+
+[[package]]
+name = "integer-sqrt"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "276ec31bcb4a9ee45f58bec6f9ec700ae4cf4f4f8f2fa7e06cb406bd5ffdd770"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "intervalier"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64fa110ec7b8f493f416eed552740d10e7030ad5f63b2308f82c9608ec2df275"
+dependencies = [
+ "futures 0.3.8",
+ "futures-timer 2.0.2",
+]
+
+[[package]]
+name = "iovec"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "ip_network"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ee15951c035f79eddbef745611ec962f63f4558f1dadf98ab723cc603487c6f"
+
+[[package]]
+name = "ipnet"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135"
+
+[[package]]
+name = "itertools"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
+
+[[package]]
+name = "jobserver"
+version = "0.1.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "joystream-node"
+version = "4.0.0"
+dependencies = [
+ "frame-benchmarking",
+ "frame-benchmarking-cli",
+ "frame-system",
+ "futures 0.3.8",
+ "hex",
+ "joystream-node-runtime",
+ "jsonrpc-core",
+ "node-inspect",
+ "pallet-grandpa",
+ "pallet-im-online",
+ "pallet-transaction-payment",
+ "pallet-transaction-payment-rpc",
+ "parity-scale-codec",
+ "sc-authority-discovery",
+ "sc-basic-authorship",
+ "sc-chain-spec",
+ "sc-cli",
+ "sc-client-api",
+ "sc-consensus",
+ "sc-consensus-babe",
+ "sc-consensus-babe-rpc",
+ "sc-consensus-epochs",
+ "sc-executor",
+ "sc-finality-grandpa",
+ "sc-finality-grandpa-rpc",
+ "sc-keystore",
+ "sc-network",
+ "sc-rpc",
+ "sc-rpc-api",
+ "sc-service",
+ "sc-service-test",
+ "sc-transaction-pool",
+ "serde",
+ "serde_json",
+ "sp-api",
+ "sp-authority-discovery",
+ "sp-block-builder",
+ "sp-blockchain",
+ "sp-consensus",
+ "sp-consensus-babe",
+ "sp-core",
+ "sp-finality-grandpa",
+ "sp-finality-tracker",
+ "sp-inherents",
+ "sp-keyring",
+ "sp-runtime",
+ "sp-timestamp",
+ "sp-transaction-pool",
+ "structopt",
+ "substrate-browser-utils",
+ "substrate-build-script-utils",
+ "substrate-frame-rpc-system",
+ "tempfile",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+]
+
+[[package]]
+name = "joystream-node-runtime"
+version = "7.8.0"
+dependencies = [
+ "frame-benchmarking",
+ "frame-executive",
+ "frame-support",
+ "frame-system",
+ "frame-system-benchmarking",
+ "frame-system-rpc-runtime-api",
+ "hex-literal 0.3.1",
+ "lazy_static",
+ "lite-json",
+ "pallet-authority-discovery",
+ "pallet-authorship",
+ "pallet-babe",
+ "pallet-balances",
+ "pallet-common",
+ "pallet-constitution",
+ "pallet-content-directory",
+ "pallet-content-working-group",
+ "pallet-finality-tracker",
+ "pallet-forum",
+ "pallet-governance",
+ "pallet-grandpa",
+ "pallet-hiring",
+ "pallet-im-online",
+ "pallet-membership",
+ "pallet-memo",
+ "pallet-offences",
+ "pallet-offences-benchmarking",
+ "pallet-proposals-codex",
+ "pallet-proposals-discussion",
+ "pallet-proposals-engine",
+ "pallet-randomness-collective-flip",
+ "pallet-recurring-reward",
+ "pallet-service-discovery",
+ "pallet-session",
+ "pallet-session-benchmarking",
+ "pallet-stake",
+ "pallet-staking",
+ "pallet-staking-reward-curve",
+ "pallet-storage",
+ "pallet-sudo",
+ "pallet-timestamp",
+ "pallet-token-mint",
+ "pallet-transaction-payment",
+ "pallet-transaction-payment-rpc-runtime-api",
+ "pallet-utility",
+ "pallet-versioned-store",
+ "pallet-versioned-store-permissions",
+ "pallet-working-group",
+ "parity-scale-codec",
+ "serde",
+ "sp-api",
+ "sp-application-crypto",
+ "sp-arithmetic",
+ "sp-authority-discovery",
+ "sp-block-builder",
+ "sp-consensus-babe",
+ "sp-core",
+ "sp-io",
+ "sp-offchain",
+ "sp-runtime",
+ "sp-session",
+ "sp-staking",
+ "sp-std",
+ "sp-transaction-pool",
+ "sp-version",
+ "strum 0.19.5",
+ "substrate-wasm-builder-runner",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca059e81d9486668f12d455a4ea6daa600bd408134cd17e3d3fb5a32d1f016f8"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "jsonrpc-client-transports"
+version = "15.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "489b9c612e60c766f751ab40fcb43cbb55a1e10bb44a9b4307ed510ca598cbd7"
+dependencies = [
+ "failure",
+ "futures 0.1.30",
+ "jsonrpc-core",
+ "jsonrpc-pubsub",
+ "log",
+ "serde",
+ "serde_json",
+ "url 1.7.2",
+]
+
+[[package]]
+name = "jsonrpc-core"
+version = "15.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0745a6379e3edc893c84ec203589790774e4247420033e71a76d3ab4687991fa"
+dependencies = [
+ "futures 0.1.30",
+ "log",
+ "serde",
+ "serde_derive",
+ "serde_json",
+]
+
+[[package]]
+name = "jsonrpc-core-client"
+version = "15.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f764902d7b891344a0acb65625f32f6f7c6db006952143bd650209fbe7d94db"
+dependencies = [
+ "jsonrpc-client-transports",
+]
+
+[[package]]
+name = "jsonrpc-derive"
+version = "15.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99a847f9ec7bb52149b2786a17c9cb260d6effc6b8eeb8c16b343a487a7563a3"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "jsonrpc-http-server"
+version = "15.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fb5c4513b7b542f42da107942b7b759f27120b5cc894729f88254b28dff44b7"
+dependencies = [
+ "hyper 0.12.35",
+ "jsonrpc-core",
+ "jsonrpc-server-utils",
+ "log",
+ "net2",
+ "parking_lot 0.10.2",
+ "unicase",
+]
+
+[[package]]
+name = "jsonrpc-ipc-server"
+version = "15.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf50e53e4eea8f421a7316c5f63e395f7bc7c4e786a6dc54d76fab6ff7aa7ce7"
+dependencies = [
+ "jsonrpc-core",
+ "jsonrpc-server-utils",
+ "log",
+ "parity-tokio-ipc",
+ "parking_lot 0.10.2",
+ "tokio-service",
+]
+
+[[package]]
+name = "jsonrpc-pubsub"
+version = "15.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "639558e0604013be9787ae52f798506ae42bf4220fe587bdc5625871cc8b9c77"
+dependencies = [
+ "jsonrpc-core",
+ "log",
+ "parking_lot 0.10.2",
+ "rand 0.7.3",
+ "serde",
+]
+
+[[package]]
+name = "jsonrpc-server-utils"
+version = "15.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72f1f3990650c033bd8f6bd46deac76d990f9bbfb5f8dc8c4767bf0a00392176"
+dependencies = [
+ "bytes 0.4.12",
+ "globset",
+ "jsonrpc-core",
+ "lazy_static",
+ "log",
+ "tokio 0.1.22",
+ "tokio-codec",
+ "unicase",
+]
+
+[[package]]
+name = "jsonrpc-ws-server"
+version = "15.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6596fe75209b73a2a75ebe1dce4e60e03b88a2b25e8807b667597f6315150d22"
+dependencies = [
+ "jsonrpc-core",
+ "jsonrpc-server-utils",
+ "log",
+ "parity-ws",
+ "parking_lot 0.10.2",
+ "slab",
+]
+
+[[package]]
+name = "keccak"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7"
+
+[[package]]
+name = "kernel32-sys"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
+dependencies = [
+ "winapi 0.2.8",
+ "winapi-build",
+]
+
+[[package]]
+name = "kv-log-macro"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f"
+dependencies = [
+ "log",
+]
+
+[[package]]
+name = "kvdb"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0315ef2f688e33844400b31f11c263f2b3dc21d8b9355c6891c5f185fae43f9a"
+dependencies = [
+ "parity-util-mem",
+ "smallvec 1.4.2",
+]
+
+[[package]]
+name = "kvdb-memorydb"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73de822b260a3bdfb889dbbb65bb2d473eee2253973d6fa4a5d149a2a4a7c66e"
+dependencies = [
+ "kvdb",
+ "parity-util-mem",
+ "parking_lot 0.10.2",
+]
+
+[[package]]
+name = "kvdb-rocksdb"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44947dd392f09475af614d740fe0320b66d01cb5b977f664bbbb5e45a70ea4c1"
+dependencies = [
+ "fs-swap",
+ "kvdb",
+ "log",
+ "num_cpus",
+ "owning_ref",
+ "parity-util-mem",
+ "parking_lot 0.10.2",
+ "regex",
+ "rocksdb",
+ "smallvec 1.4.2",
+]
+
+[[package]]
+name = "kvdb-web"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2701a1369d6ea4f1b9f606db46e5e2a4a8e47f22530a07823d653f85ab1f6c34"
+dependencies = [
+ "futures 0.3.8",
+ "js-sys",
+ "kvdb",
+ "kvdb-memorydb",
+ "log",
+ "parity-util-mem",
+ "send_wrapper 0.3.0",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+dependencies = [
+ "spin",
+]
+
+[[package]]
+name = "lazycell"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
+
+[[package]]
+name = "libc"
+version = "0.2.80"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
+
+[[package]]
+name = "libloading"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753"
+dependencies = [
+ "cc",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "libm"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a"
+
+[[package]]
+name = "libp2p"
+version = "0.28.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "571f5a4604c1a40d75651da141dfde29ad15329f537a779528803297d2220274"
+dependencies = [
+ "atomic",
+ "bytes 0.5.6",
+ "futures 0.3.8",
+ "lazy_static",
+ "libp2p-core",
+ "libp2p-core-derive",
+ "libp2p-deflate",
+ "libp2p-dns",
+ "libp2p-floodsub",
+ "libp2p-gossipsub",
+ "libp2p-identify",
+ "libp2p-kad",
+ "libp2p-mdns",
+ "libp2p-mplex",
+ "libp2p-noise",
+ "libp2p-ping",
+ "libp2p-plaintext",
+ "libp2p-pnet",
+ "libp2p-request-response",
+ "libp2p-swarm",
+ "libp2p-tcp",
+ "libp2p-uds",
+ "libp2p-wasm-ext",
+ "libp2p-websocket",
+ "libp2p-yamux",
+ "multihash",
+ "parity-multiaddr",
+ "parking_lot 0.10.2",
+ "pin-project 0.4.27",
+ "smallvec 1.4.2",
+ "wasm-timer",
+]
+
+[[package]]
+name = "libp2p-core"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52f13ba8c7df0768af2eb391696d562c7de88cc3a35122531aaa6a7d77754d25"
+dependencies = [
+ "asn1_der",
+ "bs58 0.3.1",
+ "ed25519-dalek",
+ "either",
+ "fnv",
+ "futures 0.3.8",
+ "futures-timer 3.0.2",
+ "lazy_static",
+ "libsecp256k1",
+ "log",
+ "multihash",
+ "multistream-select",
+ "parity-multiaddr",
+ "parking_lot 0.10.2",
+ "pin-project 0.4.27",
+ "prost",
+ "prost-build",
+ "rand 0.7.3",
+ "ring",
+ "rw-stream-sink",
+ "sha2 0.8.2",
+ "smallvec 1.4.2",
+ "thiserror",
+ "unsigned-varint 0.4.0",
+ "void",
+ "zeroize",
+]
+
+[[package]]
+name = "libp2p-core-derive"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f753d9324cd3ec14bf04b8a8cd0d269c87f294153d6bf2a84497a63a5ad22213"
+dependencies = [
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "libp2p-deflate"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74029ae187f35f4b8ddf26b9779a68b340045d708528a103917cdca49a296db5"
+dependencies = [
+ "flate2",
+ "futures 0.3.8",
+ "libp2p-core",
+]
+
+[[package]]
+name = "libp2p-dns"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cf319822e08dd65c8e060d2354e9f952895bbc433f5706c75ed010c152aee5e"
+dependencies = [
+ "futures 0.3.8",
+ "libp2p-core",
+ "log",
+]
+
+[[package]]
+name = "libp2p-floodsub"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8a9acb43a3e4a4e413e0c4abe0fa49308df7c6335c88534757b647199cb8a51"
+dependencies = [
+ "cuckoofilter",
+ "fnv",
+ "futures 0.3.8",
+ "libp2p-core",
+ "libp2p-swarm",
+ "prost",
+ "prost-build",
+ "rand 0.7.3",
+ "smallvec 1.4.2",
+]
+
+[[package]]
+name = "libp2p-gossipsub"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab20fcb60edebe3173bbb708c6ac3444afdf1e3152dc2866b10c4f5497f17467"
+dependencies = [
+ "base64 0.11.0",
+ "byteorder 1.3.4",
+ "bytes 0.5.6",
+ "fnv",
+ "futures 0.3.8",
+ "futures_codec",
+ "hex_fmt",
+ "libp2p-core",
+ "libp2p-swarm",
+ "log",
+ "lru_time_cache",
+ "prost",
+ "prost-build",
+ "rand 0.7.3",
+ "sha2 0.8.2",
+ "smallvec 1.4.2",
+ "unsigned-varint 0.4.0",
+ "wasm-timer",
+]
+
+[[package]]
+name = "libp2p-identify"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56396ee63aa9164eacf40c2c5d2bda8c4133c2f57e1b0425d51d3a4e362583b1"
+dependencies = [
+ "futures 0.3.8",
+ "libp2p-core",
+ "libp2p-swarm",
+ "log",
+ "prost",
+ "prost-build",
+ "smallvec 1.4.2",
+ "wasm-timer",
+]
+
+[[package]]
+name = "libp2p-kad"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc7fa9047f8b8f544278a35c2d9d45d3b2c1785f2d86d4e1629d6edf97be3955"
+dependencies = [
+ "arrayvec 0.5.2",
+ "bytes 0.5.6",
+ "either",
+ "fnv",
+ "futures 0.3.8",
+ "futures_codec",
+ "libp2p-core",
+ "libp2p-swarm",
+ "log",
+ "multihash",
+ "prost",
+ "prost-build",
+ "rand 0.7.3",
+ "sha2 0.8.2",
+ "smallvec 1.4.2",
+ "uint",
+ "unsigned-varint 0.4.0",
+ "void",
+ "wasm-timer",
+]
+
+[[package]]
+name = "libp2p-mdns"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3173b5a6b2f690c29ae07798d85b9441a131ac76ddae9015ef22905b623d0c69"
+dependencies = [
+ "async-std",
+ "data-encoding",
+ "dns-parser",
+ "either",
+ "futures 0.3.8",
+ "lazy_static",
+ "libp2p-core",
+ "libp2p-swarm",
+ "log",
+ "net2",
+ "rand 0.7.3",
+ "smallvec 1.4.2",
+ "void",
+ "wasm-timer",
+]
+
+[[package]]
+name = "libp2p-mplex"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a73a799cc8410b36e40b8f4c4b6babbcb9efd3727111bf517876e4acfa612d3"
+dependencies = [
+ "bytes 0.5.6",
+ "fnv",
+ "futures 0.3.8",
+ "futures_codec",
+ "libp2p-core",
+ "log",
+ "parking_lot 0.10.2",
+ "unsigned-varint 0.4.0",
+]
+
+[[package]]
+name = "libp2p-noise"
+version = "0.24.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ef6c490042f549fb1025f2892dfe6083d97a77558f450c1feebe748ca9eb15a"
+dependencies = [
+ "bytes 0.5.6",
+ "curve25519-dalek 2.1.0",
+ "futures 0.3.8",
+ "lazy_static",
+ "libp2p-core",
+ "log",
+ "prost",
+ "prost-build",
+ "rand 0.7.3",
+ "sha2 0.8.2",
+ "snow",
+ "static_assertions",
+ "x25519-dalek 0.6.0",
+ "zeroize",
+]
+
+[[package]]
+name = "libp2p-ping"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad063c21dfcea4518ac9e8bd4119d33a5b26c41e674f602f41f05617a368a5c8"
+dependencies = [
+ "futures 0.3.8",
+ "libp2p-core",
+ "libp2p-swarm",
+ "log",
+ "rand 0.7.3",
+ "void",
+ "wasm-timer",
+]
+
+[[package]]
+name = "libp2p-plaintext"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "903a12e99c72dbebefea258de887982adeacc7025baa1ceb10b7fa9928f54791"
+dependencies = [
+ "bytes 0.5.6",
+ "futures 0.3.8",
+ "futures_codec",
+ "libp2p-core",
+ "log",
+ "prost",
+ "prost-build",
+ "rw-stream-sink",
+ "unsigned-varint 0.4.0",
+ "void",
+]
+
+[[package]]
+name = "libp2p-pnet"
+version = "0.19.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96b3c2d5d26a9500e959a0e19743897239a6c4be78dadf99b70414301a70c006"
+dependencies = [
+ "futures 0.3.8",
+ "log",
+ "pin-project 0.4.27",
+ "rand 0.7.3",
+ "salsa20",
+ "sha3",
+]
+
+[[package]]
+name = "libp2p-request-response"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c0c9e8a4cd69d97e9646c54313d007512f411aba8c5226cfcda16df6a6e84a3"
+dependencies = [
+ "async-trait",
+ "bytes 0.5.6",
+ "futures 0.3.8",
+ "libp2p-core",
+ "libp2p-swarm",
+ "log",
+ "lru 0.6.1",
+ "minicbor",
+ "rand 0.7.3",
+ "smallvec 1.4.2",
+ "unsigned-varint 0.5.1",
+ "wasm-timer",
+]
+
+[[package]]
+name = "libp2p-swarm"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7193e444210132237b81b755ec7fe53f1c4bd2f53cf719729b94c0c72eb6eaa1"
+dependencies = [
+ "either",
+ "futures 0.3.8",
+ "libp2p-core",
+ "log",
+ "rand 0.7.3",
+ "smallvec 1.4.2",
+ "void",
+ "wasm-timer",
+]
+
+[[package]]
+name = "libp2p-tcp"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44f42ec130d7a37a7e47bf4398026b7ad9185c08ed26972e2720f8b94112796f"
+dependencies = [
+ "async-std",
+ "futures 0.3.8",
+ "futures-timer 3.0.2",
+ "get_if_addrs",
+ "ipnet",
+ "libp2p-core",
+ "log",
+ "socket2",
+]
+
+[[package]]
+name = "libp2p-uds"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dea7acb0a034f70d7db94c300eba3f65c0f6298820105624088a9609c9974d77"
+dependencies = [
+ "async-std",
+ "futures 0.3.8",
+ "libp2p-core",
+ "log",
+]
+
+[[package]]
+name = "libp2p-wasm-ext"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34c1faac6f92c21fbe155417957863ea822fba9e9fd5eb24c0912336a100e63f"
+dependencies = [
+ "futures 0.3.8",
+ "js-sys",
+ "libp2p-core",
+ "parity-send-wrapper",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+]
+
+[[package]]
+name = "libp2p-websocket"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d650534ebd99f48f6fa292ed5db10d30df2444943afde4407ceeddab8e513fca"
+dependencies = [
+ "async-tls",
+ "either",
+ "futures 0.3.8",
+ "libp2p-core",
+ "log",
+ "quicksink",
+ "rustls",
+ "rw-stream-sink",
+ "soketto",
+ "url 2.2.0",
+ "webpki",
+ "webpki-roots 0.18.0",
+]
+
+[[package]]
+name = "libp2p-yamux"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "781d9b9f043dcdabc40640807125368596b849fd4d96cdca2dcf052fdf6f33fd"
+dependencies = [
+ "futures 0.3.8",
+ "libp2p-core",
+ "parking_lot 0.11.0",
+ "thiserror",
+ "yamux",
+]
+
+[[package]]
+name = "librocksdb-sys"
+version = "6.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb5b56f651c204634b936be2f92dbb42c36867e00ff7fe2405591f3b9fa66f09"
+dependencies = [
+ "bindgen",
+ "cc",
+ "glob",
+ "libc",
+]
+
+[[package]]
+name = "libsecp256k1"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fc1e2c808481a63dc6da2074752fdd4336a3c8fcc68b83db6f1fd5224ae7962"
+dependencies = [
+ "arrayref",
+ "crunchy",
+ "digest 0.8.1",
+ "hmac-drbg",
+ "rand 0.7.3",
+ "sha2 0.8.2",
+ "subtle 2.3.0",
+ "typenum",
+]
+
+[[package]]
+name = "libz-sys"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655"
+dependencies = [
+ "cc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "linked-hash-map"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
+
+[[package]]
+name = "linked_hash_set"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47186c6da4d81ca383c7c47c1bfc80f4b95f4720514d860a5407aaf4233f9588"
+dependencies = [
+ "linked-hash-map",
+]
+
+[[package]]
+name = "linregress"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9290cf6f928576eeb9c096c6fad9d8d452a0a1a70a2bbffa6e36064eedc0aac9"
+dependencies = [
+ "failure",
+ "nalgebra",
+ "statrs",
+]
+
+[[package]]
+name = "lite-json"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0460d985423a026b4d9b828a7c6eed1bcf606f476322f3f9b507529686a61715"
+dependencies = [
+ "lite-parser",
+]
+
+[[package]]
+name = "lite-parser"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c50092e40e0ccd1bf2015a10333fde0502ff95b832b0895dc1ca0d7ac6c52f6"
+dependencies = [
+ "paste",
+]
+
+[[package]]
+name = "lock_api"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
+dependencies = [
+ "scopeguard 0.3.3",
+]
+
+[[package]]
+name = "lock_api"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75"
+dependencies = [
+ "scopeguard 1.1.0",
+]
+
+[[package]]
+name = "lock_api"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c"
+dependencies = [
+ "scopeguard 1.1.0",
+]
+
+[[package]]
+name = "log"
+version = "0.4.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
+dependencies = [
+ "cfg-if 0.1.10",
+]
+
+[[package]]
+name = "loom"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0e8460f2f2121162705187214720353c517b97bdfb3494c0b1e33d83ebe4bed"
+dependencies = [
+ "cfg-if 0.1.10",
+ "generator",
+ "scoped-tls",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "lru"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0609345ddee5badacf857d4f547e0e5a2e987db77085c24cd887f73573a04237"
+dependencies = [
+ "hashbrown 0.6.3",
+]
+
+[[package]]
+name = "lru"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be716eb6878ca2263eb5d00a781aa13264a794f519fe6af4fbb2668b2d5441c0"
+dependencies = [
+ "hashbrown 0.9.1",
+]
+
+[[package]]
+name = "lru_time_cache"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adb241df5c4caeb888755363fc95f8a896618dc0d435e9e775f7930cb099beab"
+
+[[package]]
+name = "matchers"
+version = "0.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1"
+dependencies = [
+ "regex-automata",
+]
+
+[[package]]
+name = "matches"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
+
+[[package]]
+name = "matrixmultiply"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4f7ec66360130972f34830bfad9ef05c6610a43938a467bcc9ab9369ab3478f"
+dependencies = [
+ "rawpointer",
+]
+
+[[package]]
+name = "maybe-uninit"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
+
+[[package]]
+name = "memchr"
+version = "2.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
+
+[[package]]
+name = "memmap"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
+dependencies = [
+ "libc",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "memoffset"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa"
+dependencies = [
+ "autocfg 1.0.1",
+]
+
+[[package]]
+name = "memory-db"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36f36ddb0b2cdc25d38babba472108798e3477f02be5165f038c5e393e50c57a"
+dependencies = [
+ "hash-db",
+ "hashbrown 0.8.2",
+ "parity-util-mem",
+]
+
+[[package]]
+name = "memory_units"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882"
+
+[[package]]
+name = "merlin"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6feca46f4fa3443a01769d768727f10c10a20fdb65e52dc16a81f0c8269bb78"
+dependencies = [
+ "byteorder 1.3.4",
+ "keccak",
+ "rand_core 0.5.1",
+ "zeroize",
+]
+
+[[package]]
+name = "minicbor"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2fc03ad6f8f548db7194a5ff5a6f96342ecae4e3ef67d2bf18bacc0e245cd041"
+dependencies = [
+ "minicbor-derive",
+]
+
+[[package]]
+name = "minicbor-derive"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c214bf3d90099b52f3e4b328ae0fe34837fd0fab683ad1e10fceb4629106df48"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "miniz_oxide"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d"
+dependencies = [
+ "adler",
+ "autocfg 1.0.1",
+]
+
+[[package]]
+name = "mio"
+version = "0.6.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430"
+dependencies = [
+ "cfg-if 0.1.10",
+ "fuchsia-zircon",
+ "fuchsia-zircon-sys",
+ "iovec",
+ "kernel32-sys",
+ "libc",
+ "log",
+ "miow 0.2.1",
+ "net2",
+ "slab",
+ "winapi 0.2.8",
+]
+
+[[package]]
+name = "mio-extras"
+version = "2.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19"
+dependencies = [
+ "lazycell",
+ "log",
+ "mio",
+ "slab",
+]
+
+[[package]]
+name = "mio-named-pipes"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656"
+dependencies = [
+ "log",
+ "mio",
+ "miow 0.3.5",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "mio-uds"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0"
+dependencies = [
+ "iovec",
+ "libc",
+ "mio",
+]
+
+[[package]]
+name = "miow"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
+dependencies = [
+ "kernel32-sys",
+ "net2",
+ "winapi 0.2.8",
+ "ws2_32-sys",
+]
+
+[[package]]
+name = "miow"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e"
+dependencies = [
+ "socket2",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "mockall"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01458f8a19b10cb28195290942e3149161c75acf67ebc8fbf714ab67a2b943bc"
+dependencies = [
+ "cfg-if 0.1.10",
+ "downcast",
+ "fragile",
+ "lazy_static",
+ "mockall_derive",
+ "predicates",
+ "predicates-tree",
+]
+
+[[package]]
+name = "mockall_derive"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a673cb441f78cd9af4f5919c28576a3cc325fb6b54e42f7047dacce3c718c17b"
+dependencies = [
+ "cfg-if 0.1.10",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "multihash"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567122ab6492f49b59def14ecc36e13e64dca4188196dd0cd41f9f3f979f3df6"
+dependencies = [
+ "blake2b_simd",
+ "blake2s_simd",
+ "digest 0.9.0",
+ "sha-1 0.9.2",
+ "sha2 0.9.2",
+ "sha3",
+ "unsigned-varint 0.5.1",
+]
+
+[[package]]
+name = "multimap"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1255076139a83bb467426e7f8d0134968a8118844faa755985e077cf31850333"
+
+[[package]]
+name = "multistream-select"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93faf2e41f9ee62fb01680ed48f3cc26652352327aa2e59869070358f6b7dd75"
+dependencies = [
+ "bytes 0.5.6",
+ "futures 0.3.8",
+ "log",
+ "pin-project 1.0.1",
+ "smallvec 1.4.2",
+ "unsigned-varint 0.5.1",
+]
+
+[[package]]
+name = "nalgebra"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aaa9fddbc34c8c35dd2108515587b8ce0cab396f17977b8c738568e4edb521a2"
+dependencies = [
+ "alga",
+ "approx",
+ "generic-array 0.12.3",
+ "matrixmultiply",
+ "num-complex",
+ "num-rational",
+ "num-traits",
+ "rand 0.6.5",
+ "typenum",
+]
+
+[[package]]
+name = "names"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef320dab323286b50fb5cdda23f61c796a72a89998ab565ca32525c5c556f2da"
+dependencies = [
+ "rand 0.3.23",
+]
+
+[[package]]
+name = "nb-connect"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8123a81538e457d44b933a02faf885d3fe8408806b23fa700e8f01c6c3a98998"
+dependencies = [
+ "libc",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "net2"
+version = "0.2.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ebc3ec692ed7c9a255596c67808dee269f64655d8baf7b4f0638e51ba1d6853"
+dependencies = [
+ "cfg-if 0.1.10",
+ "libc",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "nix"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363"
+dependencies = [
+ "bitflags",
+ "cc",
+ "cfg-if 0.1.10",
+ "libc",
+ "void",
+]
+
+[[package]]
+name = "node-inspect"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "derive_more",
+ "log",
+ "parity-scale-codec",
+ "sc-cli",
+ "sc-client-api",
+ "sc-service",
+ "sp-blockchain",
+ "sp-core",
+ "sp-runtime",
+ "structopt",
+]
+
+[[package]]
+name = "nodrop"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
+
+[[package]]
+name = "nohash-hasher"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
+
+[[package]]
+name = "nom"
+version = "5.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
+dependencies = [
+ "memchr",
+ "version_check",
+]
+
+[[package]]
+name = "normalize-line-endings"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
+
+[[package]]
+name = "num-bigint"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
+dependencies = [
+ "autocfg 1.0.1",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-complex"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95"
+dependencies = [
+ "autocfg 1.0.1",
+ "num-traits",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
+dependencies = [
+ "autocfg 1.0.1",
+ "num-traits",
+]
+
+[[package]]
+name = "num-rational"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef"
+dependencies = [
+ "autocfg 1.0.1",
+ "num-bigint",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
+dependencies = [
+ "autocfg 1.0.1",
+ "libm",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "object"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"
+
+[[package]]
+name = "once_cell"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "532c29a261168a45ce28948f9537ddd7a5dd272cc513b3017b1e82a88f962c37"
+dependencies = [
+ "parking_lot 0.7.1",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad"
+dependencies = [
+ "parking_lot 0.11.0",
+]
+
+[[package]]
+name = "opaque-debug"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
+
+[[package]]
+name = "opaque-debug"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
+
+[[package]]
+name = "owning_ref"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce"
+dependencies = [
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "pallet-authority-discovery"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-session",
+ "parity-scale-codec",
+ "serde",
+ "sp-application-crypto",
+ "sp-authority-discovery",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-authorship"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "impl-trait-for-tuples",
+ "parity-scale-codec",
+ "sp-authorship",
+ "sp-inherents",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-babe"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "pallet-authorship",
+ "pallet-session",
+ "pallet-timestamp",
+ "parity-scale-codec",
+ "serde",
+ "sp-application-crypto",
+ "sp-consensus-babe",
+ "sp-consensus-vrf",
+ "sp-inherents",
+ "sp-io",
+ "sp-runtime",
+ "sp-session",
+ "sp-staking",
+ "sp-std",
+ "sp-timestamp",
+]
+
+[[package]]
+name = "pallet-balances"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "parity-scale-codec",
+ "serde",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-common"
+version = "3.1.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-timestamp",
+ "parity-scale-codec",
+ "serde",
+ "sp-runtime",
+ "strum 0.19.5",
+ "strum_macros 0.19.4",
+]
+
+[[package]]
+name = "pallet-constitution"
+version = "1.0.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "parity-scale-codec",
+ "serde",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-content-directory"
+version = "3.1.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "parity-scale-codec",
+ "serde",
+ "sp-arithmetic",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-content-working-group"
+version = "3.1.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-balances",
+ "pallet-common",
+ "pallet-hiring",
+ "pallet-membership",
+ "pallet-recurring-reward",
+ "pallet-stake",
+ "pallet-timestamp",
+ "pallet-token-mint",
+ "pallet-versioned-store",
+ "pallet-versioned-store-permissions",
+ "parity-scale-codec",
+ "serde",
+ "sp-arithmetic",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-finality-tracker"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "impl-trait-for-tuples",
+ "parity-scale-codec",
+ "serde",
+ "sp-finality-tracker",
+ "sp-inherents",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-forum"
+version = "3.1.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-common",
+ "pallet-timestamp",
+ "parity-scale-codec",
+ "serde",
+ "sp-arithmetic",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-governance"
+version = "3.1.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-balances",
+ "pallet-common",
+ "pallet-membership",
+ "pallet-recurring-reward",
+ "pallet-timestamp",
+ "pallet-token-mint",
+ "parity-scale-codec",
+ "serde",
+ "sp-arithmetic",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-grandpa"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "pallet-authorship",
+ "pallet-finality-tracker",
+ "pallet-session",
+ "parity-scale-codec",
+ "serde",
+ "sp-application-crypto",
+ "sp-core",
+ "sp-finality-grandpa",
+ "sp-runtime",
+ "sp-session",
+ "sp-staking",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-hiring"
+version = "3.1.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "mockall",
+ "pallet-balances",
+ "pallet-stake",
+ "parity-scale-codec",
+ "serde",
+ "sp-arithmetic",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-im-online"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "pallet-authorship",
+ "pallet-session",
+ "parity-scale-codec",
+ "serde",
+ "sp-application-crypto",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-staking",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-membership"
+version = "3.1.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-balances",
+ "pallet-common",
+ "pallet-timestamp",
+ "parity-scale-codec",
+ "serde",
+ "sp-arithmetic",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-memo"
+version = "3.1.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-common",
+ "parity-scale-codec",
+ "sp-arithmetic",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-offences"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-balances",
+ "parity-scale-codec",
+ "serde",
+ "sp-runtime",
+ "sp-staking",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-offences-benchmarking"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "pallet-babe",
+ "pallet-balances",
+ "pallet-grandpa",
+ "pallet-im-online",
+ "pallet-offences",
+ "pallet-session",
+ "pallet-staking",
+ "parity-scale-codec",
+ "sp-runtime",
+ "sp-staking",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-proposals-codex"
+version = "4.0.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-balances",
+ "pallet-common",
+ "pallet-constitution",
+ "pallet-governance",
+ "pallet-hiring",
+ "pallet-membership",
+ "pallet-proposals-discussion",
+ "pallet-proposals-engine",
+ "pallet-recurring-reward",
+ "pallet-stake",
+ "pallet-staking",
+ "pallet-staking-reward-curve",
+ "pallet-timestamp",
+ "pallet-token-mint",
+ "pallet-working-group",
+ "parity-scale-codec",
+ "serde",
+ "sp-arithmetic",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-staking",
+ "sp-std",
+ "strum 0.19.5",
+]
+
+[[package]]
+name = "pallet-proposals-discussion"
+version = "4.0.0"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "pallet-balances",
+ "pallet-common",
+ "pallet-membership",
+ "pallet-timestamp",
+ "parity-scale-codec",
+ "serde",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-proposals-engine"
+version = "4.0.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-balances",
+ "pallet-common",
+ "pallet-membership",
+ "pallet-timestamp",
+ "parity-scale-codec",
+ "serde",
+ "sp-arithmetic",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-randomness-collective-flip"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "parity-scale-codec",
+ "safe-mix",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-recurring-reward"
+version = "3.1.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-balances",
+ "pallet-token-mint",
+ "parity-scale-codec",
+ "sp-arithmetic",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+]
+
+[[package]]
+name = "pallet-service-discovery"
+version = "3.1.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-balances",
+ "pallet-common",
+ "pallet-hiring",
+ "pallet-membership",
+ "pallet-recurring-reward",
+ "pallet-stake",
+ "pallet-timestamp",
+ "pallet-token-mint",
+ "pallet-working-group",
+ "parity-scale-codec",
+ "serde",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-session"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "impl-trait-for-tuples",
+ "pallet-timestamp",
+ "parity-scale-codec",
+ "serde",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-session",
+ "sp-staking",
+ "sp-std",
+ "sp-trie",
+]
+
+[[package]]
+name = "pallet-session-benchmarking"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "pallet-session",
+ "pallet-staking",
+ "rand 0.7.3",
+ "sp-runtime",
+ "sp-session",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-stake"
+version = "3.1.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-balances",
+ "pallet-timestamp",
+ "parity-scale-codec",
+ "sp-arithmetic",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-staking"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "pallet-authorship",
+ "pallet-session",
+ "parity-scale-codec",
+ "rand_chacha 0.2.2",
+ "serde",
+ "sp-application-crypto",
+ "sp-io",
+ "sp-npos-elections",
+ "sp-runtime",
+ "sp-staking",
+ "sp-std",
+ "static_assertions",
+]
+
+[[package]]
+name = "pallet-staking-reward-curve"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pallet-storage"
+version = "3.1.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-balances",
+ "pallet-common",
+ "pallet-hiring",
+ "pallet-membership",
+ "pallet-recurring-reward",
+ "pallet-stake",
+ "pallet-timestamp",
+ "pallet-token-mint",
+ "pallet-working-group",
+ "parity-scale-codec",
+ "serde",
+ "sp-arithmetic",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-sudo"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "parity-scale-codec",
+ "serde",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-timestamp"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "impl-trait-for-tuples",
+ "parity-scale-codec",
+ "serde",
+ "sp-inherents",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+ "sp-timestamp",
+]
+
+[[package]]
+name = "pallet-token-mint"
+version = "3.1.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-balances",
+ "parity-scale-codec",
+ "sp-arithmetic",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+]
+
+[[package]]
+name = "pallet-transaction-payment"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-transaction-payment-rpc-runtime-api",
+ "parity-scale-codec",
+ "serde",
+ "smallvec 1.4.2",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-transaction-payment-rpc"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "jsonrpc-core",
+ "jsonrpc-core-client",
+ "jsonrpc-derive",
+ "pallet-transaction-payment-rpc-runtime-api",
+ "parity-scale-codec",
+ "serde",
+ "sp-api",
+ "sp-blockchain",
+ "sp-core",
+ "sp-rpc",
+ "sp-runtime",
+]
+
+[[package]]
+name = "pallet-transaction-payment-rpc-runtime-api"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-support",
+ "parity-scale-codec",
+ "serde",
+ "sp-api",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-utility"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "parity-scale-codec",
+ "serde",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-versioned-store"
+version = "3.1.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-common",
+ "pallet-timestamp",
+ "parity-scale-codec",
+ "serde",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-versioned-store-permissions"
+version = "3.1.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-common",
+ "pallet-timestamp",
+ "pallet-versioned-store",
+ "parity-scale-codec",
+ "serde",
+ "sp-arithmetic",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-working-group"
+version = "3.1.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "pallet-balances",
+ "pallet-common",
+ "pallet-hiring",
+ "pallet-membership",
+ "pallet-recurring-reward",
+ "pallet-stake",
+ "pallet-timestamp",
+ "pallet-token-mint",
+ "parity-scale-codec",
+ "serde",
+ "sp-arithmetic",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "parity-db"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00d595e372d119261593297debbe4193811a4dc811d2a1ccbb8caaa6666ad7ab"
+dependencies = [
+ "blake2-rfc",
+ "crc32fast",
+ "libc",
+ "log",
+ "memmap",
+ "parking_lot 0.10.2",
+]
+
+[[package]]
+name = "parity-multiaddr"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22fe99b938abd57507e37f8d4ef30cd74b33c71face2809b37b8beb71bab15ab"
+dependencies = [
+ "arrayref",
+ "bs58 0.4.0",
+ "byteorder 1.3.4",
+ "data-encoding",
+ "multihash",
+ "percent-encoding 2.1.0",
+ "serde",
+ "static_assertions",
+ "unsigned-varint 0.5.1",
+ "url 2.2.0",
+]
+
+[[package]]
+name = "parity-scale-codec"
+version = "1.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c740e5fbcb6847058b40ac7e5574766c6388f585e184d769910fe0d3a2ca861"
+dependencies = [
+ "arrayvec 0.5.2",
+ "bitvec",
+ "byte-slice-cast",
+ "parity-scale-codec-derive",
+ "serde",
+]
+
+[[package]]
+name = "parity-scale-codec-derive"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "198db82bb1c18fc00176004462dd809b2a6d851669550aa17af6dacd21ae0c14"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "parity-send-wrapper"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f"
+
+[[package]]
+name = "parity-tokio-ipc"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e57fea504fea33f9fbb5f49f378359030e7e026a6ab849bb9e8f0787376f1bf"
+dependencies = [
+ "bytes 0.4.12",
+ "futures 0.1.30",
+ "libc",
+ "log",
+ "mio-named-pipes",
+ "miow 0.3.5",
+ "rand 0.7.3",
+ "tokio 0.1.22",
+ "tokio-named-pipes",
+ "tokio-uds",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "parity-util-mem"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "297ff91fa36aec49ce183484b102f6b75b46776822bd81525bfc4cc9b0dd0f5c"
+dependencies = [
+ "cfg-if 0.1.10",
+ "hashbrown 0.8.2",
+ "impl-trait-for-tuples",
+ "parity-util-mem-derive",
+ "parking_lot 0.10.2",
+ "primitive-types",
+ "smallvec 1.4.2",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "parity-util-mem-derive"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2"
+dependencies = [
+ "proc-macro2",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
+name = "parity-wasm"
+version = "0.41.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddfc878dac00da22f8f61e7af3157988424567ab01d9920b962ef7dcbd7cd865"
+
+[[package]]
+name = "parity-ws"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e02a625dd75084c2a7024f07c575b61b782f729d18702dabb3cdbf31911dc61"
+dependencies = [
+ "byteorder 1.3.4",
+ "bytes 0.4.12",
+ "httparse",
+ "log",
+ "mio",
+ "mio-extras",
+ "rand 0.7.3",
+ "sha-1 0.8.2",
+ "slab",
+ "url 2.2.0",
+]
+
+[[package]]
+name = "parking"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
+
+[[package]]
+name = "parking_lot"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
+dependencies = [
+ "lock_api 0.1.5",
+ "parking_lot_core 0.4.0",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252"
+dependencies = [
+ "lock_api 0.3.4",
+ "parking_lot_core 0.6.2",
+ "rustc_version",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e"
+dependencies = [
+ "lock_api 0.3.4",
+ "parking_lot_core 0.7.2",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4893845fa2ca272e647da5d0e46660a314ead9c2fdd9a883aabc32e481a8733"
+dependencies = [
+ "instant",
+ "lock_api 0.4.1",
+ "parking_lot_core 0.8.0",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9"
+dependencies = [
+ "libc",
+ "rand 0.6.5",
+ "rustc_version",
+ "smallvec 0.6.13",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b"
+dependencies = [
+ "cfg-if 0.1.10",
+ "cloudabi 0.0.3",
+ "libc",
+ "redox_syscall",
+ "rustc_version",
+ "smallvec 0.6.13",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3"
+dependencies = [
+ "cfg-if 0.1.10",
+ "cloudabi 0.0.3",
+ "libc",
+ "redox_syscall",
+ "smallvec 1.4.2",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b"
+dependencies = [
+ "cfg-if 0.1.10",
+ "cloudabi 0.1.0",
+ "instant",
+ "libc",
+ "redox_syscall",
+ "smallvec 1.4.2",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "paste"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880"
+dependencies = [
+ "paste-impl",
+ "proc-macro-hack",
+]
+
+[[package]]
+name = "paste-impl"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6"
+dependencies = [
+ "proc-macro-hack",
+]
+
+[[package]]
+name = "pbkdf2"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9"
+dependencies = [
+ "byteorder 1.3.4",
+ "crypto-mac 0.7.0",
+ "rayon",
+]
+
+[[package]]
+name = "pdqselect"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ec91767ecc0a0bbe558ce8c9da33c068066c57ecc8bb8477ef8c1ad3ef77c27"
+
+[[package]]
+name = "peeking_take_while"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
+
+[[package]]
+name = "percent-encoding"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
+
+[[package]]
+name = "percent-encoding"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
+
+[[package]]
+name = "petgraph"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
+dependencies = [
+ "fixedbitset",
+ "indexmap",
+]
+
+[[package]]
+name = "pin-project"
+version = "0.4.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15"
+dependencies = [
+ "pin-project-internal 0.4.27",
+]
+
+[[package]]
+name = "pin-project"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee41d838744f60d959d7074e3afb6b35c7456d0f61cad38a24e35e6553f73841"
+dependencies = [
+ "pin-project-internal 1.0.1",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "0.4.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81a4ffa594b66bff340084d4081df649a7dc049ac8d7fc458d8e628bfbbb2f86"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
+
+[[package]]
+name = "platforms"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "feb3b2b1033b8a60b4da6ee470325f887758c95d5320f52f9ce0df055a55940e"
+
+[[package]]
+name = "polling"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2a7bc6b2a29e632e45451c941832803a18cce6781db04de8a04696cdca8bde4"
+dependencies = [
+ "cfg-if 0.1.10",
+ "libc",
+ "log",
+ "wepoll-sys",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "poly1305"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22ce46de8e53ee414ca4d02bfefac75d8c12fba948b76622a40b4be34dfce980"
+dependencies = [
+ "universal-hash",
+]
+
+[[package]]
+name = "polyval"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5884790f1ce3553ad55fec37b5aaac5882e0e845a2612df744d6c85c9bf046c"
+dependencies = [
+ "cfg-if 0.1.10",
+ "universal-hash",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+
+[[package]]
+name = "predicates"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96bfead12e90dccead362d62bb2c90a5f6fc4584963645bc7f71a735e0b0735a"
+dependencies = [
+ "difference",
+ "float-cmp",
+ "normalize-line-endings",
+ "predicates-core",
+ "regex",
+]
+
+[[package]]
+name = "predicates-core"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06075c3a3e92559ff8929e7a280684489ea27fe44805174c3ebd9328dcb37178"
+
+[[package]]
+name = "predicates-tree"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e63c4859013b38a76eca2414c64911fba30def9e3202ac461a2d22831220124"
+dependencies = [
+ "predicates-core",
+ "treeline",
+]
+
+[[package]]
+name = "primitive-types"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c55c21c64d0eaa4d7ed885d959ef2d62d9e488c27c0e02d9aa5ce6c877b7d5f8"
+dependencies = [
+ "fixed-hash",
+ "impl-codec",
+ "impl-serde",
+ "uint",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
+dependencies = [
+ "toml",
+]
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-hack"
+version = "0.5.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
+
+[[package]]
+name = "proc-macro-nested"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "prometheus"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30d70cf4412832bcac9cffe27906f4a66e450d323525e977168c70d1b36120ae"
+dependencies = [
+ "cfg-if 0.1.10",
+ "fnv",
+ "lazy_static",
+ "parking_lot 0.11.0",
+ "regex",
+ "thiserror",
+]
+
+[[package]]
+name = "prost"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce49aefe0a6144a45de32927c77bd2859a5f7677b55f220ae5b744e87389c212"
+dependencies = [
+ "bytes 0.5.6",
+ "prost-derive",
+]
+
+[[package]]
+name = "prost-build"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02b10678c913ecbd69350e8535c3aef91a8676c0773fc1d7b95cdd196d7f2f26"
+dependencies = [
+ "bytes 0.5.6",
+ "heck",
+ "itertools",
+ "log",
+ "multimap",
+ "petgraph",
+ "prost",
+ "prost-types",
+ "tempfile",
+ "which",
+]
+
+[[package]]
+name = "prost-derive"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "537aa19b95acde10a12fec4301466386f757403de4cd4e5b4fa78fb5ecb18f72"
+dependencies = [
+ "anyhow",
+ "itertools",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "prost-types"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1834f67c0697c001304b75be76f67add9c89742eda3a085ad8ee0bb38c3417aa"
+dependencies = [
+ "bytes 0.5.6",
+ "prost",
+]
+
+[[package]]
+name = "quick-error"
+version = "1.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
+
+[[package]]
+name = "quicksink"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77de3c815e5a160b1539c6592796801df2043ae35e123b46d73380cfa57af858"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "radium"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac"
+
+[[package]]
+name = "rand"
+version = "0.3.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c"
+dependencies = [
+ "libc",
+ "rand 0.4.6",
+]
+
+[[package]]
+name = "rand"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
+dependencies = [
+ "fuchsia-cprng",
+ "libc",
+ "rand_core 0.3.1",
+ "rdrand",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "rand"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9"
+dependencies = [
+ "cloudabi 0.0.3",
+ "fuchsia-cprng",
+ "libc",
+ "rand_core 0.3.1",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "rand"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
+dependencies = [
+ "autocfg 0.1.7",
+ "libc",
+ "rand_chacha 0.1.1",
+ "rand_core 0.4.2",
+ "rand_hc 0.1.0",
+ "rand_isaac",
+ "rand_jitter",
+ "rand_os",
+ "rand_pcg 0.1.2",
+ "rand_xorshift",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "rand"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
+dependencies = [
+ "getrandom 0.1.15",
+ "libc",
+ "rand_chacha 0.2.2",
+ "rand_core 0.5.1",
+ "rand_hc 0.2.0",
+ "rand_pcg 0.2.1",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
+dependencies = [
+ "autocfg 0.1.7",
+ "rand_core 0.3.1",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.5.1",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
+dependencies = [
+ "rand_core 0.4.2",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
+
+[[package]]
+name = "rand_core"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
+dependencies = [
+ "getrandom 0.1.15",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
+dependencies = [
+ "rand_core 0.3.1",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+dependencies = [
+ "rand_core 0.5.1",
+]
+
+[[package]]
+name = "rand_isaac"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
+dependencies = [
+ "rand_core 0.3.1",
+]
+
+[[package]]
+name = "rand_jitter"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
+dependencies = [
+ "libc",
+ "rand_core 0.4.2",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "rand_os"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
+dependencies = [
+ "cloudabi 0.0.3",
+ "fuchsia-cprng",
+ "libc",
+ "rand_core 0.4.2",
+ "rdrand",
+ "wasm-bindgen",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "rand_pcg"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
+dependencies = [
+ "autocfg 0.1.7",
+ "rand_core 0.4.2",
+]
+
+[[package]]
+name = "rand_pcg"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
+dependencies = [
+ "rand_core 0.5.1",
+]
+
+[[package]]
+name = "rand_xorshift"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
+dependencies = [
+ "rand_core 0.3.1",
+]
+
+[[package]]
+name = "rawpointer"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
+
+[[package]]
+name = "rayon"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674"
+dependencies = [
+ "autocfg 1.0.1",
+ "crossbeam-deque 0.8.0",
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
+dependencies = [
+ "crossbeam-channel",
+ "crossbeam-deque 0.8.0",
+ "crossbeam-utils 0.8.0",
+ "lazy_static",
+ "num_cpus",
+]
+
+[[package]]
+name = "rdrand"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
+dependencies = [
+ "rand_core 0.3.1",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.1.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
+
+[[package]]
+name = "redox_users"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
+dependencies = [
+ "getrandom 0.1.15",
+ "redox_syscall",
+ "rust-argon2",
+]
+
+[[package]]
+name = "ref-cast"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e17626b2f4bcf35b84bf379072a66e28cfe5c3c6ae58b38e4914bb8891dabece"
+dependencies = [
+ "ref-cast-impl",
+]
+
+[[package]]
+name = "ref-cast-impl"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c523ccaed8ac4b0288948849a350b37d3035827413c458b6a40ddb614bb4f72"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "regex"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+ "thread_local",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4"
+dependencies = [
+ "byteorder 1.3.4",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189"
+
+[[package]]
+name = "remove_dir_all"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
+dependencies = [
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "retain_mut"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e005d658ad26eacc2b6c506dfde519f4e277e328d0eb3379ca61647d70a8f531"
+
+[[package]]
+name = "ring"
+version = "0.16.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "952cd6b98c85bbc30efa1ba5783b8abf12fec8b3287ffa52605b9432313e34e4"
+dependencies = [
+ "cc",
+ "libc",
+ "once_cell 1.4.1",
+ "spin",
+ "untrusted",
+ "web-sys",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "rocksdb"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23d83c02c429044d58474eaf5ae31e062d0de894e21125b47437ec0edc1397e6"
+dependencies = [
+ "libc",
+ "librocksdb-sys",
+]
+
+[[package]]
+name = "rpassword"
+version = "4.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99371657d3c8e4d816fb6221db98fa408242b0b53bac08f8676a41f8554fe99f"
+dependencies = [
+ "libc",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "rust-argon2"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19"
+dependencies = [
+ "base64 0.12.3",
+ "blake2b_simd",
+ "constant_time_eq",
+ "crossbeam-utils 0.7.2",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232"
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "rustc-hex"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6"
+
+[[package]]
+name = "rustc_version"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "rustls"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d1126dcf58e93cee7d098dbda643b5f92ed724f1f6a63007c1116eed6700c81"
+dependencies = [
+ "base64 0.12.3",
+ "log",
+ "ring",
+ "sct",
+ "webpki",
+]
+
+[[package]]
+name = "rustls-native-certs"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "629d439a7672da82dd955498445e496ee2096fe2117b9f796558a43fdb9e59b8"
+dependencies = [
+ "openssl-probe",
+ "rustls",
+ "schannel",
+ "security-framework",
+]
+
+[[package]]
+name = "rw-stream-sink"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4da5fcb054c46f5a5dff833b129285a93d3f0179531735e6c866e8cc307d2020"
+dependencies = [
+ "futures 0.3.8",
+ "pin-project 0.4.27",
+ "static_assertions",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
+
+[[package]]
+name = "safe-mix"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d3d055a2582e6b00ed7a31c1524040aa391092bf636328350813f3a0605215c"
+dependencies = [
+ "rustc_version",
+]
+
+[[package]]
+name = "salsa20"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7f47b10fa80f6969bbbd9c8e7cc998f082979d402a9e10579e2303a87955395"
+dependencies = [
+ "stream-cipher",
+]
+
+[[package]]
+name = "sc-authority-discovery"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "bytes 0.5.6",
+ "derive_more",
+ "either",
+ "futures 0.3.8",
+ "futures-timer 3.0.2",
+ "libp2p",
+ "log",
+ "parity-scale-codec",
+ "prost",
+ "prost-build",
+ "rand 0.7.3",
+ "sc-client-api",
+ "sc-keystore",
+ "sc-network",
+ "serde_json",
+ "sp-api",
+ "sp-authority-discovery",
+ "sp-blockchain",
+ "sp-core",
+ "sp-runtime",
+ "substrate-prometheus-endpoint",
+]
+
+[[package]]
+name = "sc-basic-authorship"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "futures 0.3.8",
+ "futures-timer 3.0.2",
+ "log",
+ "parity-scale-codec",
+ "sc-block-builder",
+ "sc-client-api",
+ "sc-proposer-metrics",
+ "sc-telemetry",
+ "sp-api",
+ "sp-blockchain",
+ "sp-consensus",
+ "sp-core",
+ "sp-inherents",
+ "sp-runtime",
+ "sp-transaction-pool",
+ "substrate-prometheus-endpoint",
+ "tokio-executor 0.2.0-alpha.6",
+]
+
+[[package]]
+name = "sc-block-builder"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "parity-scale-codec",
+ "sc-client-api",
+ "sp-api",
+ "sp-block-builder",
+ "sp-blockchain",
+ "sp-consensus",
+ "sp-core",
+ "sp-inherents",
+ "sp-runtime",
+ "sp-state-machine",
+]
+
+[[package]]
+name = "sc-chain-spec"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "impl-trait-for-tuples",
+ "parity-scale-codec",
+ "sc-chain-spec-derive",
+ "sc-network",
+ "sc-telemetry",
+ "serde",
+ "serde_json",
+ "sp-chain-spec",
+ "sp-core",
+ "sp-runtime",
+]
+
+[[package]]
+name = "sc-chain-spec-derive"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "sc-cli"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "ansi_term 0.12.1",
+ "atty",
+ "bip39",
+ "chrono",
+ "derive_more",
+ "fdlimit",
+ "futures 0.3.8",
+ "hex",
+ "lazy_static",
+ "libp2p",
+ "log",
+ "names",
+ "nix",
+ "parity-scale-codec",
+ "parity-util-mem",
+ "rand 0.7.3",
+ "regex",
+ "rpassword",
+ "sc-client-api",
+ "sc-informant",
+ "sc-keystore",
+ "sc-network",
+ "sc-service",
+ "sc-telemetry",
+ "sc-tracing",
+ "serde",
+ "serde_json",
+ "sp-blockchain",
+ "sp-core",
+ "sp-keyring",
+ "sp-panic-handler",
+ "sp-runtime",
+ "sp-state-machine",
+ "sp-utils",
+ "sp-version",
+ "structopt",
+ "substrate-prometheus-endpoint",
+ "time",
+ "tokio 0.2.22",
+ "tracing",
+ "tracing-log",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "sc-client-api"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "derive_more",
+ "fnv",
+ "futures 0.3.8",
+ "hash-db",
+ "hex-literal 0.2.1",
+ "kvdb",
+ "lazy_static",
+ "log",
+ "parity-scale-codec",
+ "parking_lot 0.10.2",
+ "sc-executor",
+ "sc-telemetry",
+ "sp-api",
+ "sp-blockchain",
+ "sp-consensus",
+ "sp-core",
+ "sp-database",
+ "sp-externalities",
+ "sp-inherents",
+ "sp-keyring",
+ "sp-runtime",
+ "sp-state-machine",
+ "sp-std",
+ "sp-storage",
+ "sp-transaction-pool",
+ "sp-trie",
+ "sp-utils",
+ "sp-version",
+ "substrate-prometheus-endpoint",
+]
+
+[[package]]
+name = "sc-client-db"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "blake2-rfc",
+ "hash-db",
+ "kvdb",
+ "kvdb-memorydb",
+ "kvdb-rocksdb",
+ "linked-hash-map",
+ "log",
+ "parity-db",
+ "parity-scale-codec",
+ "parity-util-mem",
+ "parking_lot 0.10.2",
+ "sc-client-api",
+ "sc-executor",
+ "sc-state-db",
+ "sp-arithmetic",
+ "sp-blockchain",
+ "sp-consensus",
+ "sp-core",
+ "sp-database",
+ "sp-runtime",
+ "sp-state-machine",
+ "sp-trie",
+ "substrate-prometheus-endpoint",
+]
+
+[[package]]
+name = "sc-consensus"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "sc-client-api",
+ "sp-blockchain",
+ "sp-consensus",
+ "sp-runtime",
+]
+
+[[package]]
+name = "sc-consensus-babe"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "derive_more",
+ "fork-tree",
+ "futures 0.3.8",
+ "futures-timer 3.0.2",
+ "log",
+ "merlin",
+ "num-bigint",
+ "num-rational",
+ "num-traits",
+ "parity-scale-codec",
+ "parking_lot 0.10.2",
+ "pdqselect",
+ "rand 0.7.3",
+ "retain_mut",
+ "sc-client-api",
+ "sc-consensus-epochs",
+ "sc-consensus-slots",
+ "sc-consensus-uncles",
+ "sc-keystore",
+ "sc-telemetry",
+ "schnorrkel",
+ "serde",
+ "sp-api",
+ "sp-application-crypto",
+ "sp-block-builder",
+ "sp-blockchain",
+ "sp-consensus",
+ "sp-consensus-babe",
+ "sp-consensus-vrf",
+ "sp-core",
+ "sp-inherents",
+ "sp-io",
+ "sp-runtime",
+ "sp-timestamp",
+ "sp-utils",
+ "sp-version",
+ "substrate-prometheus-endpoint",
+]
+
+[[package]]
+name = "sc-consensus-babe-rpc"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "derive_more",
+ "futures 0.3.8",
+ "jsonrpc-core",
+ "jsonrpc-core-client",
+ "jsonrpc-derive",
+ "sc-consensus-babe",
+ "sc-consensus-epochs",
+ "sc-keystore",
+ "sc-rpc-api",
+ "serde",
+ "sp-api",
+ "sp-application-crypto",
+ "sp-blockchain",
+ "sp-consensus",
+ "sp-consensus-babe",
+ "sp-core",
+ "sp-runtime",
+]
+
+[[package]]
+name = "sc-consensus-epochs"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "fork-tree",
+ "parity-scale-codec",
+ "parking_lot 0.10.2",
+ "sc-client-api",
+ "sp-blockchain",
+ "sp-runtime",
+]
+
+[[package]]
+name = "sc-consensus-slots"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "futures 0.3.8",
+ "futures-timer 3.0.2",
+ "log",
+ "parity-scale-codec",
+ "parking_lot 0.10.2",
+ "sc-client-api",
+ "sc-telemetry",
+ "sp-api",
+ "sp-application-crypto",
+ "sp-blockchain",
+ "sp-consensus",
+ "sp-consensus-slots",
+ "sp-core",
+ "sp-inherents",
+ "sp-runtime",
+ "sp-state-machine",
+]
+
+[[package]]
+name = "sc-consensus-uncles"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "log",
+ "sc-client-api",
+ "sp-authorship",
+ "sp-consensus",
+ "sp-core",
+ "sp-inherents",
+ "sp-runtime",
+]
+
+[[package]]
+name = "sc-executor"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "derive_more",
+ "lazy_static",
+ "libsecp256k1",
+ "log",
+ "parity-scale-codec",
+ "parity-wasm",
+ "parking_lot 0.10.2",
+ "sc-executor-common",
+ "sc-executor-wasmi",
+ "sp-api",
+ "sp-core",
+ "sp-externalities",
+ "sp-io",
+ "sp-panic-handler",
+ "sp-runtime-interface",
+ "sp-serializer",
+ "sp-trie",
+ "sp-version",
+ "sp-wasm-interface",
+ "wasmi",
+]
+
+[[package]]
+name = "sc-executor-common"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "derive_more",
+ "log",
+ "parity-scale-codec",
+ "parity-wasm",
+ "sp-allocator",
+ "sp-core",
+ "sp-runtime-interface",
+ "sp-serializer",
+ "sp-wasm-interface",
+ "wasmi",
+]
+
+[[package]]
+name = "sc-executor-wasmi"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "log",
+ "parity-scale-codec",
+ "sc-executor-common",
+ "sp-allocator",
+ "sp-core",
+ "sp-runtime-interface",
+ "sp-wasm-interface",
+ "wasmi",
+]
+
+[[package]]
+name = "sc-finality-grandpa"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "derive_more",
+ "finality-grandpa",
+ "fork-tree",
+ "futures 0.3.8",
+ "futures-timer 3.0.2",
+ "log",
+ "parity-scale-codec",
+ "parking_lot 0.10.2",
+ "pin-project 0.4.27",
+ "rand 0.7.3",
+ "sc-block-builder",
+ "sc-client-api",
+ "sc-consensus",
+ "sc-keystore",
+ "sc-network",
+ "sc-network-gossip",
+ "sc-telemetry",
+ "serde_json",
+ "sp-api",
+ "sp-application-crypto",
+ "sp-arithmetic",
+ "sp-blockchain",
+ "sp-consensus",
+ "sp-core",
+ "sp-finality-grandpa",
+ "sp-finality-tracker",
+ "sp-inherents",
+ "sp-runtime",
+ "sp-utils",
+ "substrate-prometheus-endpoint",
+]
+
+[[package]]
+name = "sc-finality-grandpa-rpc"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "derive_more",
+ "finality-grandpa",
+ "futures 0.3.8",
+ "jsonrpc-core",
+ "jsonrpc-core-client",
+ "jsonrpc-derive",
+ "jsonrpc-pubsub",
+ "log",
+ "parity-scale-codec",
+ "sc-client-api",
+ "sc-finality-grandpa",
+ "sc-rpc",
+ "serde",
+ "serde_json",
+ "sp-blockchain",
+ "sp-core",
+ "sp-runtime",
+]
+
+[[package]]
+name = "sc-informant"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "ansi_term 0.12.1",
+ "futures 0.3.8",
+ "log",
+ "parity-util-mem",
+ "sc-client-api",
+ "sc-network",
+ "sp-blockchain",
+ "sp-runtime",
+ "sp-transaction-pool",
+ "sp-utils",
+ "wasm-timer",
+]
+
+[[package]]
+name = "sc-keystore"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "derive_more",
+ "hex",
+ "merlin",
+ "parking_lot 0.10.2",
+ "rand 0.7.3",
+ "serde_json",
+ "sp-application-crypto",
+ "sp-core",
+ "subtle 2.3.0",
+]
+
+[[package]]
+name = "sc-light"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "hash-db",
+ "lazy_static",
+ "parity-scale-codec",
+ "parking_lot 0.10.2",
+ "sc-client-api",
+ "sc-executor",
+ "sp-api",
+ "sp-blockchain",
+ "sp-core",
+ "sp-externalities",
+ "sp-runtime",
+ "sp-state-machine",
+]
+
+[[package]]
+name = "sc-network"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "async-std",
+ "async-trait",
+ "bitflags",
+ "bs58 0.3.1",
+ "bytes 0.5.6",
+ "derive_more",
+ "either",
+ "erased-serde",
+ "fnv",
+ "fork-tree",
+ "futures 0.3.8",
+ "futures-timer 3.0.2",
+ "futures_codec",
+ "hex",
+ "ip_network",
+ "libp2p",
+ "linked-hash-map",
+ "linked_hash_set",
+ "log",
+ "lru 0.4.3",
+ "nohash-hasher",
+ "parity-scale-codec",
+ "parking_lot 0.10.2",
+ "pin-project 0.4.27",
+ "prost",
+ "prost-build",
+ "rand 0.7.3",
+ "sc-block-builder",
+ "sc-client-api",
+ "sc-peerset",
+ "serde",
+ "serde_json",
+ "slog",
+ "slog_derive",
+ "smallvec 0.6.13",
+ "sp-arithmetic",
+ "sp-blockchain",
+ "sp-consensus",
+ "sp-core",
+ "sp-runtime",
+ "sp-utils",
+ "substrate-prometheus-endpoint",
+ "thiserror",
+ "unsigned-varint 0.4.0",
+ "void",
+ "wasm-timer",
+ "zeroize",
+]
+
+[[package]]
+name = "sc-network-gossip"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "futures 0.3.8",
+ "futures-timer 3.0.2",
+ "libp2p",
+ "log",
+ "lru 0.4.3",
+ "sc-network",
+ "sp-runtime",
+ "wasm-timer",
+]
+
+[[package]]
+name = "sc-offchain"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "bytes 0.5.6",
+ "fnv",
+ "futures 0.3.8",
+ "futures-timer 3.0.2",
+ "hyper 0.13.9",
+ "hyper-rustls",
+ "log",
+ "num_cpus",
+ "parity-scale-codec",
+ "parking_lot 0.10.2",
+ "rand 0.7.3",
+ "sc-client-api",
+ "sc-keystore",
+ "sc-network",
+ "sp-api",
+ "sp-core",
+ "sp-offchain",
+ "sp-runtime",
+ "sp-utils",
+ "threadpool",
+]
+
+[[package]]
+name = "sc-peerset"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "futures 0.3.8",
+ "libp2p",
+ "log",
+ "serde_json",
+ "sp-utils",
+ "wasm-timer",
+]
+
+[[package]]
+name = "sc-proposer-metrics"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "log",
+ "substrate-prometheus-endpoint",
+]
+
+[[package]]
+name = "sc-rpc"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "futures 0.3.8",
+ "hash-db",
+ "jsonrpc-core",
+ "jsonrpc-pubsub",
+ "log",
+ "parity-scale-codec",
+ "parking_lot 0.10.2",
+ "sc-block-builder",
+ "sc-client-api",
+ "sc-executor",
+ "sc-keystore",
+ "sc-rpc-api",
+ "serde_json",
+ "sp-api",
+ "sp-blockchain",
+ "sp-chain-spec",
+ "sp-core",
+ "sp-offchain",
+ "sp-rpc",
+ "sp-runtime",
+ "sp-session",
+ "sp-state-machine",
+ "sp-transaction-pool",
+ "sp-utils",
+ "sp-version",
+]
+
+[[package]]
+name = "sc-rpc-api"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "derive_more",
+ "futures 0.3.8",
+ "jsonrpc-core",
+ "jsonrpc-core-client",
+ "jsonrpc-derive",
+ "jsonrpc-pubsub",
+ "log",
+ "parity-scale-codec",
+ "parking_lot 0.10.2",
+ "serde",
+ "serde_json",
+ "sp-chain-spec",
+ "sp-core",
+ "sp-rpc",
+ "sp-runtime",
+ "sp-transaction-pool",
+ "sp-version",
+]
+
+[[package]]
+name = "sc-rpc-server"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "futures 0.1.30",
+ "jsonrpc-core",
+ "jsonrpc-http-server",
+ "jsonrpc-ipc-server",
+ "jsonrpc-pubsub",
+ "jsonrpc-ws-server",
+ "log",
+ "serde",
+ "serde_json",
+ "sp-runtime",
+ "substrate-prometheus-endpoint",
+]
+
+[[package]]
+name = "sc-service"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "derive_more",
+ "directories",
+ "exit-future",
+ "futures 0.1.30",
+ "futures 0.3.8",
+ "futures-timer 3.0.2",
+ "hash-db",
+ "jsonrpc-core",
+ "jsonrpc-pubsub",
+ "lazy_static",
+ "log",
+ "parity-scale-codec",
+ "parity-util-mem",
+ "parking_lot 0.10.2",
+ "pin-project 0.4.27",
+ "rand 0.7.3",
+ "sc-block-builder",
+ "sc-chain-spec",
+ "sc-client-api",
+ "sc-client-db",
+ "sc-executor",
+ "sc-informant",
+ "sc-keystore",
+ "sc-light",
+ "sc-network",
+ "sc-offchain",
+ "sc-rpc",
+ "sc-rpc-server",
+ "sc-telemetry",
+ "sc-tracing",
+ "sc-transaction-pool",
+ "serde",
+ "serde_json",
+ "slog",
+ "sp-api",
+ "sp-application-crypto",
+ "sp-block-builder",
+ "sp-blockchain",
+ "sp-consensus",
+ "sp-core",
+ "sp-externalities",
+ "sp-inherents",
+ "sp-io",
+ "sp-runtime",
+ "sp-session",
+ "sp-state-machine",
+ "sp-tracing",
+ "sp-transaction-pool",
+ "sp-trie",
+ "sp-utils",
+ "sp-version",
+ "substrate-prometheus-endpoint",
+ "tempfile",
+ "tracing",
+ "wasm-timer",
+]
+
+[[package]]
+name = "sc-service-test"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "fdlimit",
+ "futures 0.1.30",
+ "futures 0.3.8",
+ "hex-literal 0.2.1",
+ "log",
+ "parity-scale-codec",
+ "parking_lot 0.10.2",
+ "sc-block-builder",
+ "sc-client-api",
+ "sc-client-db",
+ "sc-executor",
+ "sc-light",
+ "sc-network",
+ "sc-service",
+ "sp-api",
+ "sp-blockchain",
+ "sp-consensus",
+ "sp-core",
+ "sp-externalities",
+ "sp-panic-handler",
+ "sp-runtime",
+ "sp-state-machine",
+ "sp-storage",
+ "sp-tracing",
+ "sp-transaction-pool",
+ "sp-trie",
+ "substrate-test-runtime",
+ "substrate-test-runtime-client",
+ "tempfile",
+ "tokio 0.1.22",
+]
+
+[[package]]
+name = "sc-state-db"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "log",
+ "parity-scale-codec",
+ "parity-util-mem",
+ "parity-util-mem-derive",
+ "parking_lot 0.10.2",
+ "sc-client-api",
+ "sp-core",
+]
+
+[[package]]
+name = "sc-telemetry"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "futures 0.3.8",
+ "futures-timer 3.0.2",
+ "libp2p",
+ "log",
+ "parking_lot 0.10.2",
+ "pin-project 0.4.27",
+ "rand 0.7.3",
+ "serde",
+ "slog",
+ "slog-json",
+ "slog-scope",
+ "take_mut",
+ "void",
+ "wasm-timer",
+]
+
+[[package]]
+name = "sc-tracing"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "erased-serde",
+ "log",
+ "parking_lot 0.10.2",
+ "rustc-hash",
+ "sc-telemetry",
+ "serde",
+ "serde_json",
+ "slog",
+ "sp-tracing",
+ "tracing",
+ "tracing-core",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "sc-transaction-graph"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "derive_more",
+ "futures 0.3.8",
+ "linked-hash-map",
+ "log",
+ "parity-util-mem",
+ "parking_lot 0.10.2",
+ "retain_mut",
+ "serde",
+ "sp-blockchain",
+ "sp-core",
+ "sp-runtime",
+ "sp-transaction-pool",
+ "sp-utils",
+ "wasm-timer",
+]
+
+[[package]]
+name = "sc-transaction-pool"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "derive_more",
+ "futures 0.3.8",
+ "futures-diagnose",
+ "intervalier",
+ "log",
+ "parity-scale-codec",
+ "parity-util-mem",
+ "parking_lot 0.10.2",
+ "sc-client-api",
+ "sc-transaction-graph",
+ "sp-api",
+ "sp-blockchain",
+ "sp-core",
+ "sp-runtime",
+ "sp-tracing",
+ "sp-transaction-pool",
+ "sp-utils",
+ "substrate-prometheus-endpoint",
+ "wasm-timer",
+]
+
+[[package]]
+name = "schannel"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75"
+dependencies = [
+ "lazy_static",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "schnorrkel"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "021b403afe70d81eea68f6ea12f6b3c9588e5d536a94c3bf80f15e7faa267862"
+dependencies = [
+ "arrayref",
+ "arrayvec 0.5.2",
+ "curve25519-dalek 2.1.0",
+ "getrandom 0.1.15",
+ "merlin",
+ "rand 0.7.3",
+ "rand_core 0.5.1",
+ "sha2 0.8.2",
+ "subtle 2.3.0",
+ "zeroize",
+]
+
+[[package]]
+name = "scoped-tls"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
+
+[[package]]
+name = "scopeguard"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
+
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+
+[[package]]
+name = "sct"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3042af939fca8c3453b7af0f1c66e533a15a86169e39de2657310ade8f98d3c"
+dependencies = [
+ "ring",
+ "untrusted",
+]
+
+[[package]]
+name = "secrecy"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9182278ed645df3477a9c27bfee0621c621aa16f6972635f7f795dae3d81070f"
+dependencies = [
+ "zeroize",
+]
+
+[[package]]
+name = "security-framework"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad502866817f0575705bd7be36e2b2535cc33262d493aa733a2ec862baa2bc2b"
+dependencies = [
+ "bitflags",
+ "core-foundation",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51ceb04988b17b6d1dcd555390fa822ca5637b4a14e1f5099f13d351bed4d6c7"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "semver"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
+dependencies = [
+ "semver-parser",
+]
+
+[[package]]
+name = "semver-parser"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
+
+[[package]]
+name = "send_wrapper"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "686ef91cf020ad8d4aca9a7047641fd6add626b7b89e14546c2b6a76781cf822"
+
+[[package]]
+name = "send_wrapper"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0"
+
+[[package]]
+name = "serde"
+version = "1.0.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_derive_internals"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.59"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "sha-1"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
+dependencies = [
+ "block-buffer 0.7.3",
+ "digest 0.8.1",
+ "fake-simd",
+ "opaque-debug 0.2.3",
+]
+
+[[package]]
+name = "sha-1"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce3cdf1b5e620a498ee6f2a171885ac7e22f0e12089ec4b3d22b84921792507c"
+dependencies = [
+ "block-buffer 0.9.0",
+ "cfg-if 1.0.0",
+ "cpuid-bool",
+ "digest 0.9.0",
+ "opaque-debug 0.3.0",
+]
+
+[[package]]
+name = "sha2"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69"
+dependencies = [
+ "block-buffer 0.7.3",
+ "digest 0.8.1",
+ "fake-simd",
+ "opaque-debug 0.2.3",
+]
+
+[[package]]
+name = "sha2"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e7aab86fe2149bad8c507606bdb3f4ef5e7b2380eb92350f56122cca72a42a8"
+dependencies = [
+ "block-buffer 0.9.0",
+ "cfg-if 1.0.0",
+ "cpuid-bool",
+ "digest 0.9.0",
+ "opaque-debug 0.3.0",
+]
+
+[[package]]
+name = "sha3"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809"
+dependencies = [
+ "block-buffer 0.9.0",
+ "digest 0.9.0",
+ "keccak",
+ "opaque-debug 0.3.0",
+]
+
+[[package]]
+name = "sharded-slab"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b4921be914e16899a80adefb821f8ddb7974e3f1250223575a44ed994882127"
+dependencies = [
+ "lazy_static",
+ "loom",
+]
+
+[[package]]
+name = "shlex"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "signature"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29f060a7d147e33490ec10da418795238fd7545bba241504d6b31a409f2e6210"
+
+[[package]]
+name = "slab"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
+
+[[package]]
+name = "slog"
+version = "2.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1cc9c640a4adbfbcc11ffb95efe5aa7af7309e002adab54b185507dbf2377b99"
+dependencies = [
+ "erased-serde",
+]
+
+[[package]]
+name = "slog-json"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddc0d2aff1f8f325ef660d9a0eb6e6dcd20b30b3f581a5897f58bf42d061c37a"
+dependencies = [
+ "chrono",
+ "erased-serde",
+ "serde",
+ "serde_json",
+ "slog",
+]
+
+[[package]]
+name = "slog-scope"
+version = "4.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c44c89dd8b0ae4537d1ae318353eaf7840b4869c536e31c41e963d1ea523ee6"
+dependencies = [
+ "arc-swap",
+ "lazy_static",
+ "slog",
+]
+
+[[package]]
+name = "slog_derive"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a945ec7f7ce853e89ffa36be1e27dce9a43e82ff9093bf3461c30d5da74ed11b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "smallvec"
+version = "0.6.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6"
+dependencies = [
+ "maybe-uninit",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252"
+
+[[package]]
+name = "snow"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "795dd7aeeee24468e5a32661f6d27f7b5cbed802031b2d7640c7b10f8fb2dd50"
+dependencies = [
+ "aes-gcm",
+ "blake2",
+ "chacha20poly1305",
+ "rand 0.7.3",
+ "rand_core 0.5.1",
+ "ring",
+ "rustc_version",
+ "sha2 0.9.2",
+ "subtle 2.3.0",
+ "x25519-dalek 1.1.0",
+]
+
+[[package]]
+name = "socket2"
+version = "0.3.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fd8b795c389288baa5f355489c65e71fd48a02104600d15c4cfbc561e9e429d"
+dependencies = [
+ "cfg-if 0.1.10",
+ "libc",
+ "redox_syscall",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "soketto"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5c71ed3d54db0a699f4948e1bb3e45b450fa31fe602621dee6680361d569c88"
+dependencies = [
+ "base64 0.12.3",
+ "bytes 0.5.6",
+ "flate2",
+ "futures 0.3.8",
+ "httparse",
+ "log",
+ "rand 0.7.3",
+ "sha-1 0.9.2",
+]
+
+[[package]]
+name = "sp-allocator"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "derive_more",
+ "log",
+ "sp-core",
+ "sp-std",
+ "sp-wasm-interface",
+]
+
+[[package]]
+name = "sp-api"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "hash-db",
+ "parity-scale-codec",
+ "sp-api-proc-macro",
+ "sp-core",
+ "sp-runtime",
+ "sp-state-machine",
+ "sp-std",
+ "sp-version",
+]
+
+[[package]]
+name = "sp-api-proc-macro"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "blake2-rfc",
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "sp-application-crypto"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "parity-scale-codec",
+ "serde",
+ "sp-core",
+ "sp-io",
+ "sp-std",
+]
+
+[[package]]
+name = "sp-arithmetic"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "integer-sqrt",
+ "num-traits",
+ "parity-scale-codec",
+ "serde",
+ "sp-debug-derive",
+ "sp-std",
+]
+
+[[package]]
+name = "sp-authority-discovery"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "parity-scale-codec",
+ "sp-api",
+ "sp-application-crypto",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "sp-authorship"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "parity-scale-codec",
+ "sp-inherents",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "sp-block-builder"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "parity-scale-codec",
+ "sp-api",
+ "sp-inherents",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "sp-blockchain"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "derive_more",
+ "log",
+ "lru 0.4.3",
+ "parity-scale-codec",
+ "parking_lot 0.10.2",
+ "sp-block-builder",
+ "sp-consensus",
+ "sp-database",
+ "sp-runtime",
+ "sp-state-machine",
+]
+
+[[package]]
+name = "sp-chain-spec"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "sp-consensus"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "derive_more",
+ "futures 0.3.8",
+ "futures-timer 3.0.2",
+ "libp2p",
+ "log",
+ "parity-scale-codec",
+ "parking_lot 0.10.2",
+ "serde",
+ "sp-api",
+ "sp-core",
+ "sp-inherents",
+ "sp-runtime",
+ "sp-state-machine",
+ "sp-std",
+ "sp-trie",
+ "sp-utils",
+ "sp-version",
+ "substrate-prometheus-endpoint",
+ "wasm-timer",
+]
+
+[[package]]
+name = "sp-consensus-aura"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "parity-scale-codec",
+ "sp-api",
+ "sp-application-crypto",
+ "sp-inherents",
+ "sp-runtime",
+ "sp-std",
+ "sp-timestamp",
+]
+
+[[package]]
+name = "sp-consensus-babe"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "merlin",
+ "parity-scale-codec",
+ "sp-api",
+ "sp-application-crypto",
+ "sp-consensus",
+ "sp-consensus-slots",
+ "sp-consensus-vrf",
+ "sp-core",
+ "sp-inherents",
+ "sp-runtime",
+ "sp-std",
+ "sp-timestamp",
+]
+
+[[package]]
+name = "sp-consensus-slots"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "parity-scale-codec",
+ "sp-runtime",
+]
+
+[[package]]
+name = "sp-consensus-vrf"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "parity-scale-codec",
+ "schnorrkel",
+ "sp-core",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "sp-core"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "base58",
+ "blake2-rfc",
+ "byteorder 1.3.4",
+ "derive_more",
+ "dyn-clonable",
+ "ed25519-dalek",
+ "futures 0.3.8",
+ "hash-db",
+ "hash256-std-hasher",
+ "hex",
+ "impl-serde",
+ "lazy_static",
+ "libsecp256k1",
+ "log",
+ "merlin",
+ "num-traits",
+ "parity-scale-codec",
+ "parity-util-mem",
+ "parking_lot 0.10.2",
+ "primitive-types",
+ "rand 0.7.3",
+ "regex",
+ "schnorrkel",
+ "secrecy",
+ "serde",
+ "sha2 0.8.2",
+ "sp-debug-derive",
+ "sp-externalities",
+ "sp-runtime-interface",
+ "sp-std",
+ "sp-storage",
+ "substrate-bip39",
+ "tiny-bip39",
+ "tiny-keccak",
+ "twox-hash",
+ "wasmi",
+ "zeroize",
+]
+
+[[package]]
+name = "sp-database"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "kvdb",
+ "parking_lot 0.10.2",
+]
+
+[[package]]
+name = "sp-debug-derive"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "sp-externalities"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "environmental",
+ "parity-scale-codec",
+ "sp-std",
+ "sp-storage",
+]
+
+[[package]]
+name = "sp-finality-grandpa"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "finality-grandpa",
+ "log",
+ "parity-scale-codec",
+ "serde",
+ "sp-api",
+ "sp-application-crypto",
+ "sp-core",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "sp-finality-tracker"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "parity-scale-codec",
+ "sp-inherents",
+ "sp-std",
+]
+
+[[package]]
+name = "sp-inherents"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "derive_more",
+ "parity-scale-codec",
+ "parking_lot 0.10.2",
+ "sp-core",
+ "sp-std",
+]
+
+[[package]]
+name = "sp-io"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "futures 0.3.8",
+ "hash-db",
+ "libsecp256k1",
+ "log",
+ "parity-scale-codec",
+ "parking_lot 0.10.2",
+ "sp-core",
+ "sp-externalities",
+ "sp-runtime-interface",
+ "sp-state-machine",
+ "sp-std",
+ "sp-tracing",
+ "sp-trie",
+ "sp-wasm-interface",
+ "tracing",
+ "tracing-core",
+]
+
+[[package]]
+name = "sp-keyring"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "lazy_static",
+ "sp-core",
+ "sp-runtime",
+ "strum 0.16.0",
+]
+
+[[package]]
+name = "sp-npos-elections"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "parity-scale-codec",
+ "serde",
+ "sp-arithmetic",
+ "sp-npos-elections-compact",
+ "sp-std",
+]
+
+[[package]]
+name = "sp-npos-elections-compact"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "sp-offchain"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "sp-api",
+ "sp-core",
+ "sp-runtime",
+]
+
+[[package]]
+name = "sp-panic-handler"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "backtrace",
+ "log",
+]
+
+[[package]]
+name = "sp-rpc"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "serde",
+ "sp-core",
+]
+
+[[package]]
+name = "sp-runtime"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "either",
+ "hash256-std-hasher",
+ "impl-trait-for-tuples",
+ "log",
+ "parity-scale-codec",
+ "parity-util-mem",
+ "paste",
+ "rand 0.7.3",
+ "serde",
+ "sp-application-crypto",
+ "sp-arithmetic",
+ "sp-core",
+ "sp-inherents",
+ "sp-io",
+ "sp-std",
+]
+
+[[package]]
+name = "sp-runtime-interface"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "parity-scale-codec",
+ "primitive-types",
+ "sp-externalities",
+ "sp-runtime-interface-proc-macro",
+ "sp-std",
+ "sp-storage",
+ "sp-tracing",
+ "sp-wasm-interface",
+ "static_assertions",
+]
+
+[[package]]
+name = "sp-runtime-interface-proc-macro"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "Inflector",
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "sp-serializer"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "sp-session"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "parity-scale-codec",
+ "sp-api",
+ "sp-core",
+ "sp-runtime",
+ "sp-staking",
+ "sp-std",
+]
+
+[[package]]
+name = "sp-staking"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "parity-scale-codec",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "sp-state-machine"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "hash-db",
+ "log",
+ "num-traits",
+ "parity-scale-codec",
+ "parking_lot 0.10.2",
+ "rand 0.7.3",
+ "smallvec 1.4.2",
+ "sp-core",
+ "sp-externalities",
+ "sp-panic-handler",
+ "sp-std",
+ "sp-trie",
+ "trie-db",
+ "trie-root",
+]
+
+[[package]]
+name = "sp-std"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+
+[[package]]
+name = "sp-storage"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "impl-serde",
+ "parity-scale-codec",
+ "ref-cast",
+ "serde",
+ "sp-debug-derive",
+ "sp-std",
+]
+
+[[package]]
+name = "sp-timestamp"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "impl-trait-for-tuples",
+ "parity-scale-codec",
+ "sp-api",
+ "sp-inherents",
+ "sp-runtime",
+ "sp-std",
+ "wasm-timer",
+]
+
+[[package]]
+name = "sp-tracing"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "log",
+ "parity-scale-codec",
+ "sp-std",
+ "tracing",
+ "tracing-core",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "sp-transaction-pool"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "derive_more",
+ "futures 0.3.8",
+ "log",
+ "parity-scale-codec",
+ "serde",
+ "sp-api",
+ "sp-blockchain",
+ "sp-runtime",
+]
+
+[[package]]
+name = "sp-trie"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "hash-db",
+ "memory-db",
+ "parity-scale-codec",
+ "sp-core",
+ "sp-std",
+ "trie-db",
+ "trie-root",
+]
+
+[[package]]
+name = "sp-utils"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "futures 0.3.8",
+ "futures-core",
+ "futures-timer 3.0.2",
+ "lazy_static",
+ "prometheus",
+]
+
+[[package]]
+name = "sp-version"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "impl-serde",
+ "parity-scale-codec",
+ "serde",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "sp-wasm-interface"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "impl-trait-for-tuples",
+ "parity-scale-codec",
+ "sp-std",
+ "wasmi",
+]
+
+[[package]]
+name = "spin"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "statrs"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10102ac8d55e35db2b3fafc26f81ba8647da2e15879ab686a67e6d19af2685e8"
+dependencies = [
+ "rand 0.5.6",
+]
+
+[[package]]
+name = "stream-cipher"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c80e15f898d8d8f25db24c253ea615cc14acf418ff307822995814e7d42cfa89"
+dependencies = [
+ "block-cipher",
+ "generic-array 0.14.4",
+]
+
+[[package]]
+name = "string"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d"
+dependencies = [
+ "bytes 0.4.12",
+]
+
+[[package]]
+name = "strsim"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+
+[[package]]
+name = "structopt"
+version = "0.3.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "126d630294ec449fae0b16f964e35bf3c74f940da9dca17ee9b905f7b3112eb8"
+dependencies = [
+ "clap",
+ "lazy_static",
+ "structopt-derive",
+]
+
+[[package]]
+name = "structopt-derive"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65e51c492f9e23a220534971ff5afc14037289de430e3c83f9daf6a1b6ae91e8"
+dependencies = [
+ "heck",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "strum"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6138f8f88a16d90134763314e3fc76fa3ed6a7db4725d6acf9a3ef95a3188d22"
+dependencies = [
+ "strum_macros 0.16.0",
+]
+
+[[package]]
+name = "strum"
+version = "0.19.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b89a286a7e3b5720b9a477b23253bc50debac207c8d21505f8e70b36792f11b5"
+
+[[package]]
+name = "strum_macros"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0054a7df764039a6cd8592b9de84be4bec368ff081d203a7d5371cbfa8e65c81"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "strum_macros"
+version = "0.19.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e61bb0be289045cb80bfce000512e32d09f8337e54c186725da381377ad1f8d5"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "substrate-bip39"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bed6646a0159b9935b5d045611560eeef842b78d7adc3ba36f5ca325a13a0236"
+dependencies = [
+ "hmac",
+ "pbkdf2",
+ "schnorrkel",
+ "sha2 0.8.2",
+ "zeroize",
+]
+
+[[package]]
+name = "substrate-browser-utils"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "chrono",
+ "console_error_panic_hook",
+ "console_log",
+ "futures 0.1.30",
+ "futures 0.3.8",
+ "futures-timer 3.0.2",
+ "js-sys",
+ "kvdb-web",
+ "libp2p-wasm-ext",
+ "log",
+ "rand 0.6.5",
+ "rand 0.7.3",
+ "sc-chain-spec",
+ "sc-informant",
+ "sc-network",
+ "sc-service",
+ "sp-database",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+]
+
+[[package]]
+name = "substrate-build-script-utils"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "platforms",
+]
+
+[[package]]
+name = "substrate-frame-rpc-system"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "frame-system-rpc-runtime-api",
+ "futures 0.3.8",
+ "jsonrpc-core",
+ "jsonrpc-core-client",
+ "jsonrpc-derive",
+ "log",
+ "parity-scale-codec",
+ "sc-client-api",
+ "sc-rpc-api",
+ "serde",
+ "sp-api",
+ "sp-block-builder",
+ "sp-blockchain",
+ "sp-core",
+ "sp-runtime",
+ "sp-transaction-pool",
+]
+
+[[package]]
+name = "substrate-prometheus-endpoint"
+version = "0.8.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "async-std",
+ "derive_more",
+ "futures-util",
+ "hyper 0.13.9",
+ "log",
+ "prometheus",
+ "tokio 0.2.22",
+]
+
+[[package]]
+name = "substrate-test-client"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "futures 0.1.30",
+ "futures 0.3.8",
+ "hash-db",
+ "hex",
+ "parity-scale-codec",
+ "sc-client-api",
+ "sc-client-db",
+ "sc-consensus",
+ "sc-executor",
+ "sc-light",
+ "sc-service",
+ "serde",
+ "serde_json",
+ "sp-blockchain",
+ "sp-consensus",
+ "sp-core",
+ "sp-keyring",
+ "sp-runtime",
+ "sp-state-machine",
+]
+
+[[package]]
+name = "substrate-test-runtime"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "cfg-if 0.1.10",
+ "frame-executive",
+ "frame-support",
+ "frame-system",
+ "frame-system-rpc-runtime-api",
+ "log",
+ "memory-db",
+ "pallet-babe",
+ "pallet-timestamp",
+ "parity-scale-codec",
+ "parity-util-mem",
+ "sc-service",
+ "serde",
+ "sp-api",
+ "sp-application-crypto",
+ "sp-block-builder",
+ "sp-consensus-aura",
+ "sp-consensus-babe",
+ "sp-core",
+ "sp-externalities",
+ "sp-finality-grandpa",
+ "sp-inherents",
+ "sp-io",
+ "sp-keyring",
+ "sp-offchain",
+ "sp-runtime",
+ "sp-runtime-interface",
+ "sp-session",
+ "sp-state-machine",
+ "sp-std",
+ "sp-transaction-pool",
+ "sp-trie",
+ "sp-version",
+ "substrate-wasm-builder-runner",
+ "trie-db",
+]
+
+[[package]]
+name = "substrate-test-runtime-client"
+version = "2.0.0"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+dependencies = [
+ "futures 0.3.8",
+ "parity-scale-codec",
+ "sc-block-builder",
+ "sc-client-api",
+ "sc-consensus",
+ "sc-light",
+ "sc-service",
+ "sp-api",
+ "sp-blockchain",
+ "sp-consensus",
+ "sp-core",
+ "sp-runtime",
+ "substrate-test-client",
+ "substrate-test-runtime",
+]
+
+[[package]]
+name = "substrate-wasm-builder-runner"
+version = "1.0.6"
+source = "git+https://github.com/paritytech/substrate.git?rev=a200cdb93c6af5763b9c7bf313fa708764ac88ca#a200cdb93c6af5763b9c7bf313fa708764ac88ca"
+
+[[package]]
+name = "subtle"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
+
+[[package]]
+name = "subtle"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "343f3f510c2915908f155e94f17220b19ccfacf2a64a2a5d8004f2c3e311e7fd"
+
+[[package]]
+name = "syn"
+version = "1.0.48"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "unicode-xid",
+]
+
+[[package]]
+name = "take_mut"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
+
+[[package]]
+name = "tempfile"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
+dependencies = [
+ "cfg-if 0.1.10",
+ "libc",
+ "rand 0.7.3",
+ "redox_syscall",
+ "remove_dir_all",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e9ae34b84616eedaaf1e9dd6026dbe00dcafa92aa0c8077cb69df1fcfe5e53e"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ba20f23e85b10754cd195504aebf6a27e2e6cbe28c17778a0c930724628dd56"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "threadpool"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
+dependencies = [
+ "num_cpus",
+]
+
+[[package]]
+name = "time"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
+dependencies = [
+ "libc",
+ "wasi 0.10.0+wasi-snapshot-preview1",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "tiny-bip39"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0165e045cc2ae1660270ca65e1676dbaab60feb0f91b10f7d0665e9b47e31f2"
+dependencies = [
+ "failure",
+ "hmac",
+ "once_cell 1.4.1",
+ "pbkdf2",
+ "rand 0.7.3",
+ "rustc-hash",
+ "sha2 0.8.2",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "tiny-keccak"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
+dependencies = [
+ "crunchy",
+]
+
+[[package]]
+name = "tinyvec"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "238ce071d267c5710f9d31451efec16c5ee22de34df17cc05e56cbc92e967117"
+
+[[package]]
+name = "tokio"
+version = "0.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6"
+dependencies = [
+ "bytes 0.4.12",
+ "futures 0.1.30",
+ "mio",
+ "num_cpus",
+ "tokio-codec",
+ "tokio-current-thread",
+ "tokio-executor 0.1.10",
+ "tokio-fs",
+ "tokio-io",
+ "tokio-reactor",
+ "tokio-sync 0.1.8",
+ "tokio-tcp",
+ "tokio-threadpool",
+ "tokio-timer",
+ "tokio-udp",
+ "tokio-uds",
+]
+
+[[package]]
+name = "tokio"
+version = "0.2.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d34ca54d84bf2b5b4d7d31e901a8464f7b60ac145a284fba25ceb801f2ddccd"
+dependencies = [
+ "bytes 0.5.6",
+ "fnv",
+ "futures-core",
+ "iovec",
+ "lazy_static",
+ "libc",
+ "memchr",
+ "mio",
+ "mio-uds",
+ "num_cpus",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "slab",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "tokio-buf"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46"
+dependencies = [
+ "bytes 0.4.12",
+ "either",
+ "futures 0.1.30",
+]
+
+[[package]]
+name = "tokio-codec"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b"
+dependencies = [
+ "bytes 0.4.12",
+ "futures 0.1.30",
+ "tokio-io",
+]
+
+[[package]]
+name = "tokio-current-thread"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e"
+dependencies = [
+ "futures 0.1.30",
+ "tokio-executor 0.1.10",
+]
+
+[[package]]
+name = "tokio-executor"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671"
+dependencies = [
+ "crossbeam-utils 0.7.2",
+ "futures 0.1.30",
+]
+
+[[package]]
+name = "tokio-executor"
+version = "0.2.0-alpha.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ee9ceecf69145923834ea73f32ba40c790fd877b74a7817dd0b089f1eb9c7c8"
+dependencies = [
+ "futures-util-preview",
+ "lazy_static",
+ "tokio-sync 0.2.0-alpha.6",
+]
+
+[[package]]
+name = "tokio-fs"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4"
+dependencies = [
+ "futures 0.1.30",
+ "tokio-io",
+ "tokio-threadpool",
+]
+
+[[package]]
+name = "tokio-io"
+version = "0.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674"
+dependencies = [
+ "bytes 0.4.12",
+ "futures 0.1.30",
+ "log",
+]
+
+[[package]]
+name = "tokio-named-pipes"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d282d483052288b2308ba5ee795f5673b159c9bdf63c385a05609da782a5eae"
+dependencies = [
+ "bytes 0.4.12",
+ "futures 0.1.30",
+ "mio",
+ "mio-named-pipes",
+ "tokio 0.1.22",
+]
+
+[[package]]
+name = "tokio-reactor"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351"
+dependencies = [
+ "crossbeam-utils 0.7.2",
+ "futures 0.1.30",
+ "lazy_static",
+ "log",
+ "mio",
+ "num_cpus",
+ "parking_lot 0.9.0",
+ "slab",
+ "tokio-executor 0.1.10",
+ "tokio-io",
+ "tokio-sync 0.1.8",
+]
+
+[[package]]
+name = "tokio-rustls"
+version = "0.14.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e12831b255bcfa39dc0436b01e19fea231a37db570686c06ee72c423479f889a"
+dependencies = [
+ "futures-core",
+ "rustls",
+ "tokio 0.2.22",
+ "webpki",
+]
+
+[[package]]
+name = "tokio-service"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162"
+dependencies = [
+ "futures 0.1.30",
+]
+
+[[package]]
+name = "tokio-sync"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee"
+dependencies = [
+ "fnv",
+ "futures 0.1.30",
+]
+
+[[package]]
+name = "tokio-sync"
+version = "0.2.0-alpha.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f1aaeb685540f7407ea0e27f1c9757d258c7c6bf4e3eb19da6fc59b747239d2"
+dependencies = [
+ "fnv",
+ "futures-core-preview",
+ "futures-util-preview",
+]
+
+[[package]]
+name = "tokio-tcp"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72"
+dependencies = [
+ "bytes 0.4.12",
+ "futures 0.1.30",
+ "iovec",
+ "mio",
+ "tokio-io",
+ "tokio-reactor",
+]
+
+[[package]]
+name = "tokio-threadpool"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89"
+dependencies = [
+ "crossbeam-deque 0.7.3",
+ "crossbeam-queue",
+ "crossbeam-utils 0.7.2",
+ "futures 0.1.30",
+ "lazy_static",
+ "log",
+ "num_cpus",
+ "slab",
+ "tokio-executor 0.1.10",
+]
+
+[[package]]
+name = "tokio-timer"
+version = "0.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296"
+dependencies = [
+ "crossbeam-utils 0.7.2",
+ "futures 0.1.30",
+ "slab",
+ "tokio-executor 0.1.10",
+]
+
+[[package]]
+name = "tokio-udp"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82"
+dependencies = [
+ "bytes 0.4.12",
+ "futures 0.1.30",
+ "log",
+ "mio",
+ "tokio-codec",
+ "tokio-io",
+ "tokio-reactor",
+]
+
+[[package]]
+name = "tokio-uds"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab57a4ac4111c8c9dbcf70779f6fc8bc35ae4b2454809febac840ad19bd7e4e0"
+dependencies = [
+ "bytes 0.4.12",
+ "futures 0.1.30",
+ "iovec",
+ "libc",
+ "log",
+ "mio",
+ "mio-uds",
+ "tokio-codec",
+ "tokio-io",
+ "tokio-reactor",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499"
+dependencies = [
+ "bytes 0.5.6",
+ "futures-core",
+ "futures-sink",
+ "log",
+ "pin-project-lite",
+ "tokio 0.2.22",
+]
+
+[[package]]
+name = "toml"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "tower-service"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860"
+
+[[package]]
+name = "tracing"
+version = "0.1.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0987850db3733619253fe60e17cb59b82d37c7e6c0236bb81e4d6b87c879f27"
+dependencies = [
+ "cfg-if 0.1.10",
+ "log",
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80e0ccfc3378da0cce270c946b676a376943f5cd16aeba64568e7939806f4ada"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "tracing-futures"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab7bb6f14721aa00656086e9335d363c5c8747bae02ebe32ea2c7dece5689b4c"
+dependencies = [
+ "pin-project 0.4.27",
+ "tracing",
+]
+
+[[package]]
+name = "tracing-log"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e0f8c7178e13481ff6765bd169b33e8d554c5d2bbede5e32c356194be02b9b9"
+dependencies = [
+ "lazy_static",
+ "log",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-serde"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b"
+dependencies = [
+ "serde",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1fa8f0c8f4c594e4fc9debc1990deab13238077271ba84dd853d54902ee3401"
+dependencies = [
+ "ansi_term 0.12.1",
+ "chrono",
+ "lazy_static",
+ "matchers",
+ "regex",
+ "serde",
+ "serde_json",
+ "sharded-slab",
+ "smallvec 1.4.2",
+ "thread_local",
+ "tracing",
+ "tracing-core",
+ "tracing-log",
+ "tracing-serde",
+]
+
+[[package]]
+name = "treeline"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
+
+[[package]]
+name = "trie-db"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e55f7ace33d6237e14137e386f4e1672e2a5c6bbc97fef9f438581a143971f0"
+dependencies = [
+ "hash-db",
+ "hashbrown 0.8.2",
+ "log",
+ "rustc-hex",
+ "smallvec 1.4.2",
+]
+
+[[package]]
+name = "trie-root"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "652931506d2c1244d7217a70b99f56718a7b4161b37f04e7cd868072a99f68cd"
+dependencies = [
+ "hash-db",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
+
+[[package]]
+name = "twox-hash"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04f8ab788026715fa63b31960869617cba39117e520eb415b0139543e325ab59"
+dependencies = [
+ "cfg-if 0.1.10",
+ "rand 0.7.3",
+ "static_assertions",
+]
+
+[[package]]
+name = "typenum"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
+
+[[package]]
+name = "uint"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9db035e67dfaf7edd9aebfe8676afcd63eed53c8a4044fed514c8cccf1835177"
+dependencies = [
+ "byteorder 1.3.4",
+ "crunchy",
+ "rustc-hex",
+ "static_assertions",
+]
+
+[[package]]
+name = "unicase"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
+dependencies = [
+ "version_check",
+]
+
+[[package]]
+name = "unicode-bidi"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
+dependencies = [
+ "matches",
+]
+
+[[package]]
+name = "unicode-normalization"
+version = "0.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
+
+[[package]]
+name = "universal-hash"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402"
+dependencies = [
+ "generic-array 0.14.4",
+ "subtle 2.3.0",
+]
+
+[[package]]
+name = "unsigned-varint"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "669d776983b692a906c881fcd0cfb34271a48e197e4d6cb8df32b05bfc3d3fa5"
+dependencies = [
+ "bytes 0.5.6",
+ "futures-io",
+ "futures-util",
+ "futures_codec",
+]
+
+[[package]]
+name = "unsigned-varint"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7fdeedbf205afadfe39ae559b75c3240f24e257d0ca27e85f85cb82aa19ac35"
+dependencies = [
+ "futures-io",
+ "futures-util",
+]
+
+[[package]]
+name = "untrusted"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
+
+[[package]]
+name = "url"
+version = "1.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
+dependencies = [
+ "idna 0.1.5",
+ "matches",
+ "percent-encoding 1.0.1",
+]
+
+[[package]]
+name = "url"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e"
+dependencies = [
+ "form_urlencoded",
+ "idna 0.2.0",
+ "matches",
+ "percent-encoding 2.1.0",
+]
+
+[[package]]
+name = "vcpkg"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c"
+
+[[package]]
+name = "vec-arena"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d"
+
+[[package]]
+name = "vec_map"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
+
+[[package]]
+name = "version_check"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
+
+[[package]]
+name = "void"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
+
+[[package]]
+name = "waker-fn"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
+
+[[package]]
+name = "want"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230"
+dependencies = [
+ "futures 0.1.30",
+ "log",
+ "try-lock",
+]
+
+[[package]]
+name = "want"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
+dependencies = [
+ "log",
+ "try-lock",
+]
+
+[[package]]
+name = "wasi"
+version = "0.9.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+
+[[package]]
+name = "wasi"
+version = "0.10.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.68"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ac64ead5ea5f05873d7c12b545865ca2b8d28adfc50a49b84770a3a97265d42"
+dependencies = [
+ "cfg-if 0.1.10",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.68"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f22b422e2a757c35a73774860af8e112bff612ce6cb604224e8e47641a9e4f68"
+dependencies = [
+ "bumpalo",
+ "lazy_static",
+ "log",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7866cab0aa01de1edf8b5d7936938a7e397ee50ce24119aef3e1eaa3b6171da"
+dependencies = [
+ "cfg-if 0.1.10",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.68"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b13312a745c08c469f0b292dd2fcd6411dba5f7160f593da6ef69b64e407038"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.68"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.68"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307"
+
+[[package]]
+name = "wasm-timer"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f"
+dependencies = [
+ "futures 0.3.8",
+ "js-sys",
+ "parking_lot 0.11.0",
+ "pin-utils",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "wasmi"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf617d864d25af3587aa745529f7aaa541066c876d57e050c0d0c85c61c92aff"
+dependencies = [
+ "libc",
+ "memory_units",
+ "num-rational",
+ "num-traits",
+ "parity-wasm",
+ "wasmi-validation",
+]
+
+[[package]]
+name = "wasmi-validation"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea78c597064ba73596099281e2f4cfc019075122a65cdda3205af94f0b264d93"
+dependencies = [
+ "parity-wasm",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bf6ef87ad7ae8008e15a355ce696bed26012b7caa21605188cfd8214ab51e2d"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "webpki"
+version = "0.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab146130f5f790d45f82aeeb09e55a256573373ec64409fc19a6fb82fb1032ae"
+dependencies = [
+ "ring",
+ "untrusted",
+]
+
+[[package]]
+name = "webpki-roots"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91cd5736df7f12a964a5067a12c62fa38e1bd8080aff1f80bc29be7c80d19ab4"
+dependencies = [
+ "webpki",
+]
+
+[[package]]
+name = "webpki-roots"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8eff4b7516a57307f9349c64bf34caa34b940b66fed4b2fb3136cb7386e5739"
+dependencies = [
+ "webpki",
+]
+
+[[package]]
+name = "wepoll-sys"
+version = "3.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fcb14dea929042224824779fbc82d9fab8d2e6d3cbc0ac404de8edf489e77ff"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "which"
+version = "3.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "winapi"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-build"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "ws2_32-sys"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
+dependencies = [
+ "winapi 0.2.8",
+ "winapi-build",
+]
+
+[[package]]
+name = "x25519-dalek"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "637ff90c9540fa3073bb577e65033069e4bae7c79d49d74aa3ffdf5342a53217"
+dependencies = [
+ "curve25519-dalek 2.1.0",
+ "rand_core 0.5.1",
+ "zeroize",
+]
+
+[[package]]
+name = "x25519-dalek"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc614d95359fd7afc321b66d2107ede58b246b844cf5d8a0adcca413e439f088"
+dependencies = [
+ "curve25519-dalek 3.0.0",
+ "rand_core 0.5.1",
+ "zeroize",
+]
+
+[[package]]
+name = "yamux"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9aeb8c4043cac71c3c299dff107171c220d179492350ea198e109a414981b83c"
+dependencies = [
+ "futures 0.3.8",
+ "log",
+ "nohash-hasher",
+ "parking_lot 0.11.0",
+ "rand 0.7.3",
+ "static_assertions",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f33972566adbd2d3588b0491eb94b98b43695c4ef897903470ede4f3f5a28a"
+dependencies = [
+ "zeroize_derive",
+]
+
+[[package]]
+name = "zeroize_derive"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3f369ddb18862aba61aa49bf31e74d29f0f162dec753063200e1dc084345d16"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]

+ 1 - 3
apps.Dockerfile

@@ -7,9 +7,7 @@ COPY . /joystream
 # to ensure dev dependencies are installed.
 RUN yarn install --frozen-lockfile
 
-# Pioneer is failing to build only on github actions workflow runner
-# Error: packages/page-staking/src/index.tsx(24,21): error TS2307: Cannot find module './Targets' or its corresponding type declarations.
-# RUN yarn workspace pioneer build
+RUN yarn workspace pioneer build
 RUN yarn workspace storage-node build
 RUN yarn workspace query-node-root build
 

+ 55 - 0
build.sh

@@ -0,0 +1,55 @@
+#!/usr/bin/env bash
+
+set -e
+
+yarn
+yarn workspace @joystream/types build
+yarn workspace cd-schemas generate:all
+yarn workspace cd-schemas build
+yarn workspace @joystream/cli build
+yarn workspace query-node-root build
+yarn workspace storage-node build
+# Not strictly needed during development, we run "yarn workspace pioneer start" to start
+# a dev instance, but will show highlight build issues
+yarn workspace pioneer build
+
+if ! command -v docker-compose &> /dev/null
+then
+  echo "docker-compose not found, skipping docker build!"
+else
+  # Build joystream/apps docker image
+  docker-compose build pioneer
+
+  # Optionally build joystream/node docker image
+  # TODO: Try to fetch a cached joystream/node image
+  # if one is found matching code shasum instead of building
+  while true
+  do
+    read -p "Rebuild joystream/node docker image? (y/N): " answer2
+
+    case $answer2 in
+    [yY]* ) docker-compose build joystream-node
+            break;;
+
+    [nN]* ) break;;
+
+    * )     break;;
+    esac
+  done
+fi
+
+# Build cargo crates: native binaries joystream/node, wasm runtime, and chainspec builder.
+while true
+do
+  read -p "Compile joystream node native binary? (y/N): " answer1
+
+  case $answer1 in
+   [yY]* ) yarn cargo-checks
+           yarn cargo-build
+           break;;
+
+   [nN]* ) break;;
+
+   * )     break;;
+  esac
+done

+ 5 - 1
cli/package.json

@@ -125,5 +125,9 @@
     "format": "prettier ./ --write",
     "generate:schema-typings": "rm -rf ./src/json-schemas/typings && json2ts -i ./src/json-schemas/ -o ./src/json-schemas/typings/"
   },
-  "types": "lib/index.d.ts"
+  "types": "lib/index.d.ts",
+  "volta": {
+    "node": "12.18.2",
+    "yarn": "1.22.4"
+  }
 }

+ 5 - 1
content-directory-schemas/package.json

@@ -44,5 +44,9 @@
   "bugs": {
     "url": "https://github.com/Joystream/joystream/issues"
   },
-  "homepage": "https://github.com/Joystream/joystream"
+  "homepage": "https://github.com/Joystream/joystream",
+  "volta": {
+    "node": "12.18.2",
+    "yarn": "1.22.4"
+  }
 }

+ 0 - 39
docker-compose-with-storage.yml

@@ -1,39 +0,0 @@
-version: '3'
-services:
-  ipfs:
-    image: ipfs/go-ipfs:latest
-    ports:
-      - '127.0.0.1:5001:5001'
-      - '127.0.0.1:8080:8080'
-    entrypoint: ''
-    command: |
-      /bin/sh -c "
-        set -e
-        /usr/local/bin/start_ipfs config profile apply lowpower
-        /usr/local/bin/start_ipfs config --json Gateway.PublicGateways '{\"localhost\": null }'
-        /sbin/tini -- /usr/local/bin/start_ipfs daemon --migrate=true
-      "
-  chain:
-    image: joystream/node
-    build:
-      context: .
-      dockerfile: joystream-node.Dockerfile
-    ports:
-      - '127.0.0.1:9944:9944'
-    command: --dev --ws-external --base-path /data --log runtime
-
-  colossus:
-    image: joystream/apps
-    restart: on-failure
-    depends_on:
-      - "chain"
-      - "ipfs"
-    build:
-      context: .
-      dockerfile: apps.Dockerfile
-    ports:
-      - '127.0.0.1:3001:3001'
-    command: colossus --dev --ws-provider ws://chain:9944 --ipfs-host ipfs
-    environment:
-      - DEBUG=*
-

+ 141 - 8
docker-compose.yml

@@ -1,17 +1,150 @@
-# Compiles new joystream node image if local image not found,
-# and runs local development chain.
-# To prevent build run docker-compose with "--no-build" arg
-version: "3"
+# Compiles new joystream/node and joystream/apps images if local images not found
+# and runs a complete joystream development network
+# To prevent build of docker images run docker-compose with "--no-build" arg
+version: "3.4"
 services:
   joystream-node:
-    image: joystream/node
+    image: joystream/node:latest
     build:
       # context is relative to the compose file
       context: .
       # dockerfile is relative to the context
       dockerfile: joystream-node.Dockerfile
     container_name: joystream-node
-    command: --dev --alice --validator --unsafe-ws-external --rpc-cors=all --log runtime
+    volumes:
+      - /data
+    command: --dev --alice --validator --unsafe-ws-external --rpc-cors=all --log runtime --base-path /data
     ports:
-      - "9944:9944"
-  
+      - "127.0.0.1:9944:9944"
+
+  ipfs:
+    image: ipfs/go-ipfs:latest
+    ports:
+      - '127.0.0.1:5001:5001'
+      - '127.0.0.1:8080:8080'
+    volumes:
+      - /data/ipfs
+    entrypoint: ''
+    command: |
+      /bin/sh -c "
+        set -e
+        /usr/local/bin/start_ipfs config profile apply lowpower
+        /usr/local/bin/start_ipfs config --json Gateway.PublicGateways '{\"localhost\": null }'
+        /sbin/tini -- /usr/local/bin/start_ipfs daemon --migrate=true
+      "
+
+  colossus:
+    image: joystream/apps
+    restart: on-failure
+    depends_on:
+      - "joystream-node"
+      - "ipfs"
+    build:
+      context: .
+      dockerfile: apps.Dockerfile
+    ports:
+      - '127.0.0.1:3001:3001'
+    command: colossus --dev --ws-provider ${WS_PROVIDER_ENDPOINT_URI} --ipfs-host ipfs
+    environment:
+      - DEBUG=*
+
+  db:
+    image: postgres:12
+    restart: always
+    ports:
+      - "127.0.0.1:${DB_PORT}:5432"
+    volumes:
+      - /var/lib/postgresql/data
+    environment:
+      POSTGRES_USER: ${DB_USER}
+      POSTGRES_PASSWORD: ${DB_PASS}
+      POSTGRES_DB: ${DB_NAME}
+
+  graphql-server:
+    image: joystream/apps
+    restart: unless-stopped
+    build: 
+      context: .
+      dockerfile: apps.Dockerfile
+    env_file:
+      # relative to working directory where docker-compose was run from 
+      - .env
+    environment:
+      - DB_HOST=db
+    ports:
+      - "127.0.0.1:8081:${GRAPHQL_SERVER_PORT}"
+    depends_on: 
+      - db
+    command: ["workspace", "query-node-root", "server:start:prod"]
+
+  processor:
+    image: joystream/apps
+    restart: unless-stopped
+    build: 
+      context: .
+      dockerfile: apps.Dockerfile
+    env_file:
+      # relative to working directory where docker-compose was run from 
+      - .env
+    environment:
+      - INDEXER_ENDPOINT_URL=http://indexer-api-gateway:4000/graphql
+      - DB_HOST=db
+      - TYPEORM_HOST=db
+      - DEBUG=index-builder:*
+      - WS_PROVIDER_ENDPOINT_URI=${WS_PROVIDER_ENDPOINT_URI}
+    depends_on:
+      - indexer-api-gateway
+    command: ["workspace", "query-node-root", "processor:start"]
+
+  indexer:
+    image: joystream/apps
+    restart: unless-stopped
+    build: 
+      context: .
+      dockerfile: apps.Dockerfile
+    env_file:
+      # relative to working directory where docker-compose was run from 
+      - .env 
+    environment:
+      - TYPEORM_HOST=db
+      - INDEXER_WORKERS=5
+      - PROCESSOR_POLL_INTERVAL=1000 # refresh every second 
+      - REDIS_URI=redis://redis:6379/0
+      - DEBUG=index-builder:*
+      - WS_PROVIDER_ENDPOINT_URI=${WS_PROVIDER_ENDPOINT_URI}
+    depends_on: 
+      - db
+    command: ["workspace", "query-node-root", "indexer:start"] 
+
+  indexer-api-gateway:
+    image: joystream/hydra-indexer-gateway:latest
+    restart: unless-stopped
+    environment:
+      - WARTHOG_STARTER_DB_DATABASE=${DB_NAME}
+      - WARTHOG_STARTER_DB_HOST=db 
+      - WARTHOG_STARTER_DB_PASSWORD=${DB_PASS}
+      - WARTHOG_STARTER_DB_PORT=${DB_PORT}
+      - WARTHOG_STARTER_DB_USERNAME=${DB_USER}
+      - WARTHOG_STARTER_REDIS_URI=redis://redis:6379/0 
+      - PORT=4000
+    ports:
+      - "127.0.0.1:4000:4000"
+    depends_on:
+      - redis
+      - db
+      - indexer
+
+  redis:
+    image: redis:6.0-alpine
+    restart: always
+    ports:
+      - "127.0.0.1:6379:6379"
+
+  pioneer:
+    image: joystream/apps
+    build:
+      context: .
+      dockerfile: apps.Dockerfile
+    ports:
+      - "127.0.0.1:3000:3000"
+    command: workspace pioneer start

+ 8 - 1
joystream-node.Dockerfile

@@ -1,4 +1,11 @@
-FROM joystream/rust-builder AS builder
+FROM liuchong/rustup:1.47.0 AS rustup
+RUN rustup component add rustfmt clippy
+RUN rustup install nightly-2020-10-06 --force
+RUN rustup target add wasm32-unknown-unknown --toolchain nightly-2020-10-06
+RUN apt-get update && \
+  apt-get install -y curl git gcc xz-utils sudo pkg-config unzip clang libc6-dev-i386
+
+FROM rustup AS builder
 LABEL description="Compiles all workspace artifacts"
 WORKDIR /joystream
 COPY . /joystream

+ 3 - 57
node/src/chain_spec/mod.rs

@@ -33,9 +33,9 @@ use node_runtime::{
     ContentDirectoryConfig, ContentDirectoryWorkingGroupConfig, ContentWorkingGroupConfig,
     CouncilConfig, CouncilElectionConfig, DataDirectoryConfig, DataObjectStorageRegistryConfig,
     DataObjectTypeRegistryConfig, ElectionParameters, ForumConfig, ForumWorkingGroupConfig,
-    GrandpaConfig, ImOnlineConfig, MembersConfig, Moment, ProposalsCodexConfig, SessionConfig,
-    SessionKeys, Signature, StakerStatus, StakingConfig, StorageWorkingGroupConfig, SudoConfig,
-    SystemConfig, VersionedStoreConfig, VersionedStorePermissionsConfig, DAYS,
+    GrandpaConfig, ImOnlineConfig, MembersConfig, Moment, SessionConfig, SessionKeys, Signature,
+    StakerStatus, StakingConfig, StorageWorkingGroupConfig, SudoConfig, SystemConfig,
+    VersionedStoreConfig, VersionedStorePermissionsConfig, DAYS,
 };
 
 // Exported to be used by chain-spec-builder
@@ -45,7 +45,6 @@ pub mod content_config;
 pub mod forum_config;
 pub mod initial_balances;
 pub mod initial_members;
-pub mod proposals_config;
 
 type AccountPublic = <Signature as Verify>::Signer;
 
@@ -133,7 +132,6 @@ impl Alternative {
                             get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
                             get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
                         ],
-                        proposals_config::development(),
                         initial_members::none(),
                         forum_config::empty(get_account_id_from_seed::<sr25519::Public>("Alice")),
                         content_config::empty_versioned_store_config(),
@@ -174,7 +172,6 @@ impl Alternative {
                             get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
                             get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
                         ],
-                        proposals_config::development(),
                         initial_members::none(),
                         forum_config::empty(get_account_id_from_seed::<sr25519::Public>("Alice")),
                         content_config::empty_versioned_store_config(),
@@ -220,7 +217,6 @@ pub fn testnet_genesis(
     )>,
     root_key: AccountId,
     endowed_accounts: Vec<AccountId>,
-    cpcp: node_runtime::ProposalsConfigParameters,
     members: Vec<membership::genesis::Member<u64, AccountId, Moment>>,
     forum_config: ForumConfig,
     versioned_store_config: VersionedStoreConfig,
@@ -348,54 +344,6 @@ pub fn testnet_genesis(
         versioned_store: Some(versioned_store_config),
         versioned_store_permissions: Some(versioned_store_permissions_config),
         content_wg: Some(content_working_group_config),
-        proposals_codex: Some(ProposalsCodexConfig {
-            set_validator_count_proposal_voting_period: cpcp
-                .set_validator_count_proposal_voting_period,
-            set_validator_count_proposal_grace_period: cpcp
-                .set_validator_count_proposal_grace_period,
-            runtime_upgrade_proposal_voting_period: cpcp.runtime_upgrade_proposal_voting_period,
-            runtime_upgrade_proposal_grace_period: cpcp.runtime_upgrade_proposal_grace_period,
-            text_proposal_voting_period: cpcp.text_proposal_voting_period,
-            text_proposal_grace_period: cpcp.text_proposal_grace_period,
-            set_election_parameters_proposal_voting_period: cpcp
-                .set_election_parameters_proposal_voting_period,
-            set_election_parameters_proposal_grace_period: cpcp
-                .set_election_parameters_proposal_grace_period,
-            spending_proposal_voting_period: cpcp.spending_proposal_voting_period,
-            spending_proposal_grace_period: cpcp.spending_proposal_grace_period,
-            add_working_group_opening_proposal_voting_period: cpcp
-                .add_working_group_opening_proposal_voting_period,
-            add_working_group_opening_proposal_grace_period: cpcp
-                .add_working_group_opening_proposal_grace_period,
-            begin_review_working_group_leader_applications_proposal_voting_period: cpcp
-                .begin_review_working_group_leader_applications_proposal_voting_period,
-            begin_review_working_group_leader_applications_proposal_grace_period: cpcp
-                .begin_review_working_group_leader_applications_proposal_grace_period,
-            fill_working_group_leader_opening_proposal_voting_period: cpcp
-                .fill_working_group_leader_opening_proposal_voting_period,
-            fill_working_group_leader_opening_proposal_grace_period: cpcp
-                .fill_working_group_leader_opening_proposal_grace_period,
-            set_working_group_mint_capacity_proposal_voting_period: cpcp
-                .set_working_group_mint_capacity_proposal_voting_period,
-            set_working_group_mint_capacity_proposal_grace_period: cpcp
-                .set_working_group_mint_capacity_proposal_grace_period,
-            decrease_working_group_leader_stake_proposal_voting_period: cpcp
-                .decrease_working_group_leader_stake_proposal_voting_period,
-            decrease_working_group_leader_stake_proposal_grace_period: cpcp
-                .decrease_working_group_leader_stake_proposal_grace_period,
-            slash_working_group_leader_stake_proposal_voting_period: cpcp
-                .slash_working_group_leader_stake_proposal_voting_period,
-            slash_working_group_leader_stake_proposal_grace_period: cpcp
-                .slash_working_group_leader_stake_proposal_grace_period,
-            set_working_group_leader_reward_proposal_voting_period: cpcp
-                .set_working_group_leader_reward_proposal_voting_period,
-            set_working_group_leader_reward_proposal_grace_period: cpcp
-                .set_working_group_leader_reward_proposal_grace_period,
-            terminate_working_group_leader_role_proposal_voting_period: cpcp
-                .terminate_working_group_leader_role_proposal_voting_period,
-            terminate_working_group_leader_role_proposal_grace_period: cpcp
-                .terminate_working_group_leader_role_proposal_grace_period,
-        }),
     }
 }
 
@@ -410,7 +358,6 @@ pub(crate) mod tests {
             vec![get_authority_keys_from_seed("Alice")],
             get_account_id_from_seed::<sr25519::Public>("Alice"),
             vec![get_authority_keys_from_seed("Alice").0],
-            proposals_config::development(),
             initial_members::none(),
             forum_config::empty(get_account_id_from_seed::<sr25519::Public>("Alice")),
             content_config::empty_versioned_store_config(),
@@ -447,7 +394,6 @@ pub(crate) mod tests {
                 get_authority_keys_from_seed("Alice").0,
                 get_authority_keys_from_seed("Bob").0,
             ],
-            proposals_config::development(),
             initial_members::none(),
             forum_config::empty(get_account_id_from_seed::<sr25519::Public>("Alice")),
             content_config::empty_versioned_store_config(),

+ 0 - 17
node/src/chain_spec/proposals_config.rs

@@ -1,17 +0,0 @@
-use node_runtime::ProposalsConfigParameters;
-
-/// Development chain config. 0 grace period for all proposals, ie.
-/// proposals executed immediatly. Short voting period.
-pub fn development() -> ProposalsConfigParameters {
-    ProposalsConfigParameters::with_grace_and_voting_periods(0, 200)
-}
-
-/// Staging chain config. Shorter grace periods and voting periods than default.
-pub fn staging() -> ProposalsConfigParameters {
-    ProposalsConfigParameters::with_grace_and_voting_periods(20, 30)
-}
-
-/// The default configuration as defined in the runtime module
-pub fn production() -> ProposalsConfigParameters {
-    ProposalsConfigParameters::default()
-}

+ 6 - 0
package.json

@@ -5,6 +5,8 @@
   "license": "GPL-3.0-only",
   "scripts": {
     "postinstall": "yarn workspace @joystream/types build && yarn workspace cd-schemas generate:all && yarn workspace cd-schemas build && yarn workspace @joystream/cli build",
+    "build": "./build.sh",
+    "start": "./start.sh",
     "cargo-checks": "devops/git-hooks/pre-commit && devops/git-hooks/pre-push",
     "cargo-build": "scripts/cargo-build.sh"
   },
@@ -50,5 +52,9 @@
   "engines": {
     "node": ">=12.18.0",
     "yarn": "^1.22.0"
+  },
+  "volta": {
+    "node": "12.18.2",
+    "yarn": "1.22.4"
   }
 }

+ 3 - 0
pioneer/package.json

@@ -93,5 +93,8 @@
     "sass-loader": "^8.0.0",
     "style-loader": "^1.0.0",
     "@joystream/types": "link:../types"
+  },
+  "volta": {
+    "extends": "../package.json"
   }
 }

+ 2 - 0
query-node/.env

@@ -1,3 +1,5 @@
+COMPOSE_PROJECT_NAME=joystream
+
 # Project name
 PROJECT_NAME=query_node
 

+ 0 - 91
query-node/docker-compose.yml

@@ -1,91 +0,0 @@
-version: "3.4"
-
-services:
-  db:
-    image: postgres:12
-    restart: always
-    ports:
-      - "${DB_PORT}:5432"
-    volumes:
-      - /var/lib/postgresql/data
-    environment:
-      POSTGRES_USER: ${DB_USER}
-      POSTGRES_PASSWORD: ${DB_PASS}
-      POSTGRES_DB: ${DB_NAME}
-
-  graphql-server:
-    image: joystream/apps
-    restart: unless-stopped
-    build: 
-      context: ../
-      dockerfile: apps.Dockerfile
-    env_file:
-      - .env
-    environment:
-      - DB_HOST=db
-    ports:
-      - "8080:${GRAPHQL_SERVER_PORT}"
-    depends_on: 
-      - db
-    command: ["workspace", "query-node-root", "server:start:prod"]
-
-  processor:
-    image: joystream/apps
-    restart: unless-stopped
-    build: 
-      context: ../
-      dockerfile: apps.Dockerfile
-    env_file:
-      - .env
-    environment:
-      - INDEXER_ENDPOINT_URL=http://indexer-api-gateway:4000/graphql
-      - DB_HOST=db
-      - TYPEORM_HOST=db
-      - DEBUG=index-builder:*
-      - WS_PROVIDER_ENDPOINT_URI=${WS_PROVIDER_ENDPOINT_URI}
-    depends_on:
-      - indexer-api-gateway
-    command: ["workspace", "query-node-root", "processor:start"]
-  
-  indexer:
-    image: joystream/apps
-    restart: unless-stopped
-    build: 
-      context: ../
-      dockerfile: apps.Dockerfile
-    env_file:
-      - .env 
-    environment:
-      - TYPEORM_HOST=db
-      - INDEXER_WORKERS=5
-      - PROCESSOR_POLL_INTERVAL=1000 # refresh every second 
-      - REDIS_URI=redis://redis:6379/0
-      - DEBUG=index-builder:*
-      - WS_PROVIDER_ENDPOINT_URI=${WS_PROVIDER_ENDPOINT_URI}
-    depends_on: 
-      - db
-    command: ["workspace", "query-node-root", "indexer:start"] 
-  
-  indexer-api-gateway:
-    image: joystream/hydra-indexer-gateway:latest
-    restart: unless-stopped
-    environment:
-      - WARTHOG_STARTER_DB_DATABASE=${DB_NAME}
-      - WARTHOG_STARTER_DB_HOST=db 
-      - WARTHOG_STARTER_DB_PASSWORD=${DB_PASS}
-      - WARTHOG_STARTER_DB_PORT=${DB_PORT}
-      - WARTHOG_STARTER_DB_USERNAME=${DB_USER}
-      - WARTHOG_STARTER_REDIS_URI=redis://redis:6379/0 
-      - PORT=4000
-    ports:
-      - "4000:4000"
-    depends_on:
-      - redis
-      - db
-      - indexer
-    
-  redis:
-    image: redis:6.0-alpine
-    restart: always
-    ports:
-      - "6379:6379"

+ 10 - 6
query-node/package.json

@@ -16,23 +16,27 @@
 		"db:schema:migrate": "(cd ./generated/graphql-server && yarn db:create && yarn db:sync && yarn db:migrate)",
 		"db:indexer:migrate": "(cd ./generated/indexer && yarn db:migrate)",
 		"db:migrate": "yarn db:schema:migrate && yarn db:indexer:migrate",
-		"codegen:all": "yarn hydra-cli codegen && cp indexer-tsconfig.json generated/indexer/tsconfig.json",
-		"codegen:indexer": "yarn hydra-cli codegen --no-graphql && cp indexer-tsconfig.json generated/indexer/tsconfig.json",
-		"codegen:server": "yarn hydra-cli codegen --no-indexer",
-		"docker:up": "docker-compose up -d",
-    "cd-classes": "ts-node scripts/get-class-id-and-name.ts"
+		"codegen:all": "yarn hydra-cli codegen --no-install && cp indexer-tsconfig.json generated/indexer/tsconfig.json",
+		"codegen:indexer": "yarn hydra-cli codegen --no-install --no-graphql && cp indexer-tsconfig.json generated/indexer/tsconfig.json",
+		"codegen:server": "yarn hydra-cli codegen --no-install --no-indexer",
+		"cd-classes": "ts-node scripts/get-class-id-and-name.ts"
 	},
 	"author": "",
 	"license": "ISC",
 	"devDependencies": {
-		"@dzlzv/hydra-cli": "^0.0.19"
+		"@dzlzv/hydra-cli": "^0.0.20"
 	},
 	"dependencies": {
+		"@dzlzv/hydra-indexer-lib": "^0.0.19-legacy.1.26.1",
 		"@joystream/types": "^0.14.0",
 		"@types/bn.js": "^4.11.6",
 		"@types/debug": "^4.1.5",
 		"bn.js": "^5.1.2",
 		"debug": "^4.2.0",
+		"dotenvi": "^0.9.1",
 		"tslib": "^2.0.0"
+	},
+	"volta": {
+		"extends": "../package.json"
 	}
 }

+ 10 - 5
query-node/run-tests.sh

@@ -7,8 +7,8 @@ cd $SCRIPT_PATH
 function cleanup() {
     # Show tail end of logs for the processor and indexer containers to
     # see any possible errors
-    (echo "## Processor Logs ##" && docker logs query-node_processor_1 --tail 50) || :
-    (echo "## Indexer Logs ##" && docker logs query-node_indexer_1 --tail 50) || :
+    (echo "## Processor Logs ##" && docker logs joystream_processor_1 --tail 50) || :
+    (echo "## Indexer Logs ##" && docker logs joystream_indexer_1 --tail 50) || :
     docker-compose down -v
 }
 
@@ -23,9 +23,14 @@ export WS_PROVIDER_ENDPOINT_URI=ws://joystream-node:9944/
 # typeorm commandline is used by db:migrate step below.
 ln -s ../../../../../node_modules/typeorm/cli.js generated/graphql-server/node_modules/.bin/typeorm || :
 
-yarn db:up
+# clean start
+docker-compose down -v
+
+docker-compose up -d db
 yarn db:migrate
-yarn docker:up
+docker-compose up -d graphql-server
+# Starting up processor will bring up all services it depends on
+docker-compose up -d processor
 
 # Run tests
-ATTACH_TO_NETWORK=query-node_default ../tests/network-tests/run-tests.sh content-directory
+ATTACH_TO_NETWORK=joystream_default ../tests/network-tests/run-tests.sh content-directory

+ 0 - 21
runtime-modules/common/src/origin.rs

@@ -1,26 +1,5 @@
-use frame_system::RawOrigin;
-
 /// Abstract validator for the origin(account_id) and actor_id (eg.: thread author id).
 pub trait ActorOriginValidator<Origin, ActorId, AccountId> {
     /// Check for valid combination of origin and actor_id.
     fn ensure_actor_origin(origin: Origin, actor_id: ActorId) -> Result<AccountId, &'static str>;
 }
-
-// TODO: delete when T::Origin will support the clone()
-/// Multiplies the T::Origin.
-/// In our current substrate version frame_system::Origin doesn't support clone(),
-/// but it will be supported in latest up-to-date substrate version.
-pub fn double_origin<T: frame_system::Trait>(origin: T::Origin) -> (T::Origin, T::Origin) {
-    let coerced_origin = origin.into().ok().unwrap_or(RawOrigin::None);
-
-    let (cloned_origin1, cloned_origin2) = match coerced_origin {
-        RawOrigin::None => (RawOrigin::None, RawOrigin::None),
-        RawOrigin::Root => (RawOrigin::Root, RawOrigin::Root),
-        RawOrigin::Signed(account_id) => (
-            RawOrigin::Signed(account_id.clone()),
-            RawOrigin::Signed(account_id),
-        ),
-    };
-
-    (cloned_origin1.into(), cloned_origin2.into())
-}

+ 29 - 0
runtime-modules/constitution/Cargo.toml

@@ -0,0 +1,29 @@
+[package]
+name = 'pallet-constitution'
+version = '1.0.0'
+authors = ['Joystream contributors']
+edition = '2018'
+
+[dependencies]
+serde = { version = "1.0.101", optional = true, features = ["derive"] }
+codec = { package = 'parity-scale-codec', version = '1.3.1', default-features = false, features = ['derive'] }
+sp-std = { package = 'sp-std', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
+frame-support = { package = 'frame-support', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
+frame_system = { package = 'frame-system', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
+sp-runtime = { package = 'sp-runtime', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
+
+[dev-dependencies]
+sp-io = { package = 'sp-io', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
+sp-core = { package = 'sp-core', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
+
+
+[features]
+default = ['std']
+std = [
+    'serde',
+    'codec/std',
+    'sp-std/std',
+    'frame-support/std',
+    'frame_system/std',
+    'sp-runtime/std',
+]

+ 73 - 0
runtime-modules/constitution/src/lib.rs

@@ -0,0 +1,73 @@
+//! # Constitution pallet.
+//! `Constitution` pallet for the Joystream platform. Version 1.
+//! It contains current constitution text hash and amendment number in the storage and extrinsic for
+//! setting the new constitution.
+//!
+
+// Ensure we're `no_std` when compiling for Wasm.
+#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg(test)]
+mod tests;
+
+use codec::{Decode, Encode};
+use frame_support::{decl_event, decl_module, decl_storage};
+use frame_system::ensure_root;
+#[cfg(feature = "std")]
+use serde::{Deserialize, Serialize};
+use sp_runtime::traits::Hash;
+use sp_std::vec::Vec;
+
+pub trait Trait: frame_system::Trait {
+    type Event: From<Event> + Into<<Self as frame_system::Trait>::Event>;
+}
+
+/// Contains constitution text hash and its amendment number.
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
+#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, Default)]
+pub struct ConstitutionInfo {
+    /// Constitution text hash.
+    pub text_hash: Vec<u8>,
+}
+
+decl_storage! {
+    trait Store for Module<T: Trait> as Memo {
+        Constitution get(fn constitution) : ConstitutionInfo;
+    }
+}
+
+decl_event! {
+    pub enum Event {
+        /// Emits on constitution amendment.
+        /// Parameters:
+        /// - constitution text hash
+        ConstutionAmended(Vec<u8>),
+    }
+}
+
+decl_module! {
+    pub struct Module<T: Trait> for enum Call where origin: T::Origin {
+        fn deposit_event() = default;
+
+        /// Sets the current constitution hash. Requires root origin.
+        #[weight = 10_000_000] // TODO: adjust weight
+        fn amend_constitution(origin, constitution_text: Vec<u8>) {
+            ensure_root(origin)?;
+
+            //
+            // == MUTATION SAFE ==
+            //
+
+            let hashed = T::Hashing::hash(&constitution_text);
+            let hash = hashed.as_ref().to_vec();
+
+            let constitution = ConstitutionInfo{
+                text_hash: hash.clone(),
+            };
+
+            Constitution::put(constitution);
+
+            Self::deposit_event(Event::ConstutionAmended(hash));
+        }
+    }
+}

+ 78 - 0
runtime-modules/constitution/src/tests/mocks.rs

@@ -0,0 +1,78 @@
+#![cfg(test)]
+
+use crate::{Module, Trait};
+use frame_support::{impl_outer_event, impl_outer_origin, parameter_types};
+use sp_core::H256;
+use sp_runtime::{
+    testing::Header,
+    traits::{BlakeTwo256, IdentityLookup},
+    Perbill,
+};
+
+impl_outer_origin! {
+    pub enum Origin for Test {}
+}
+
+mod constitution {
+    pub use crate::Event;
+}
+
+impl_outer_event! {
+    pub enum TestEvent for Test {
+        constitution,
+        frame_system<T>,
+    }
+}
+
+// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct Test;
+parameter_types! {
+    pub const BlockHashCount: u64 = 250;
+    pub const MaximumBlockWeight: u32 = 1024;
+    pub const MaximumBlockLength: u32 = 2 * 1024;
+    pub const AvailableBlockRatio: Perbill = Perbill::one();
+}
+
+impl frame_system::Trait for Test {
+    type BaseCallFilter = ();
+    type Origin = Origin;
+    type Call = ();
+    type Index = u64;
+    type BlockNumber = u64;
+    type Hash = H256;
+    type Hashing = BlakeTwo256;
+    type AccountId = u64;
+    type Lookup = IdentityLookup<Self::AccountId>;
+    type Header = Header;
+    type Event = TestEvent;
+    type BlockHashCount = BlockHashCount;
+    type MaximumBlockWeight = MaximumBlockWeight;
+    type DbWeight = ();
+    type BlockExecutionWeight = ();
+    type ExtrinsicBaseWeight = ();
+    type MaximumExtrinsicWeight = ();
+    type MaximumBlockLength = MaximumBlockLength;
+    type AvailableBlockRatio = AvailableBlockRatio;
+    type Version = ();
+    type AccountData = ();
+    type OnNewAccount = ();
+    type OnKilledAccount = ();
+    type PalletInfo = ();
+    type SystemWeightInfo = ();
+}
+
+impl Trait for Test {
+    type Event = TestEvent;
+}
+
+pub fn build_test_externalities() -> sp_io::TestExternalities {
+    let t = frame_system::GenesisConfig::default()
+        .build_storage::<Test>()
+        .unwrap();
+
+    t.into()
+}
+
+pub type System = frame_system::Module<Test>;
+pub type Constitution = Module<Test>;

+ 109 - 0
runtime-modules/constitution/src/tests/mod.rs

@@ -0,0 +1,109 @@
+#![cfg(test)]
+
+mod mocks;
+
+use crate::{ConstitutionInfo, Event};
+use frame_support::dispatch::DispatchResult;
+use frame_support::traits::{OnFinalize, OnInitialize};
+use frame_system::{EventRecord, Phase, RawOrigin};
+use mocks::{build_test_externalities, Constitution, System, Test, TestEvent};
+use sp_runtime::traits::Hash;
+use sp_runtime::DispatchError;
+
+// Recommendation from Parity on testing on_finalize
+// https://substrate.dev/docs/en/next/development/module/tests
+fn run_to_block(n: u64) {
+    while System::block_number() < n {
+        <System as OnFinalize<u64>>::on_finalize(System::block_number());
+        <Constitution as OnFinalize<u64>>::on_finalize(System::block_number());
+        System::set_block_number(System::block_number() + 1);
+        <System as OnInitialize<u64>>::on_initialize(System::block_number());
+        <Constitution as OnInitialize<u64>>::on_initialize(System::block_number());
+    }
+}
+
+pub struct EventFixture;
+impl EventFixture {
+    pub fn assert_last_crate_event(expected_raw_event: Event) {
+        let converted_event = TestEvent::constitution(expected_raw_event);
+
+        Self::assert_last_global_event(converted_event)
+    }
+
+    pub fn assert_last_global_event(expected_event: TestEvent) {
+        let expected_event = EventRecord {
+            phase: Phase::Initialization,
+            event: expected_event,
+            topics: vec![],
+        };
+
+        assert_eq!(System::events().pop().unwrap(), expected_event);
+    }
+}
+
+pub struct AmendConstitutionFixture {
+    origin: RawOrigin<u64>,
+    text: Vec<u8>,
+}
+
+impl AmendConstitutionFixture {
+    pub fn default() -> Self {
+        Self {
+            origin: RawOrigin::Root,
+            text: Vec::new(),
+        }
+    }
+    pub fn with_origin(self, origin: RawOrigin<u64>) -> Self {
+        Self { origin, ..self }
+    }
+
+    pub fn with_text(self, text: Vec<u8>) -> Self {
+        Self { text, ..self }
+    }
+
+    pub fn call_and_assert(&self, expected_result: DispatchResult) {
+        let old_constitution = Constitution::constitution();
+
+        let actual_result =
+            Constitution::amend_constitution(self.origin.clone().into(), self.text.clone());
+
+        assert_eq!(actual_result, expected_result);
+
+        let new_constitution = Constitution::constitution();
+        if actual_result.is_ok() {
+            let hashed = <Test as frame_system::Trait>::Hashing::hash(&self.text);
+            let hash = hashed.as_ref().to_vec();
+
+            assert_eq!(new_constitution, ConstitutionInfo { text_hash: hash });
+        } else {
+            assert_eq!(old_constitution, new_constitution);
+        }
+    }
+}
+
+#[test]
+fn amend_contitution_succeeds() {
+    build_test_externalities().execute_with(|| {
+        let starting_block = 1;
+        run_to_block(starting_block);
+
+        let text = b"Constitution text".to_vec();
+
+        let hashed = <Test as frame_system::Trait>::Hashing::hash(&text);
+        let hash = hashed.as_ref().to_vec();
+
+        let amend_constitution_fixture = AmendConstitutionFixture::default().with_text(text);
+        amend_constitution_fixture.call_and_assert(Ok(()));
+
+        EventFixture::assert_last_crate_event(Event::ConstutionAmended(hash));
+    });
+}
+
+#[test]
+fn amend_contitution_fais_with_invalid_origin() {
+    build_test_externalities().execute_with(|| {
+        let amend_constitution_fixture =
+            AmendConstitutionFixture::default().with_origin(RawOrigin::None);
+        amend_constitution_fixture.call_and_assert(Err(DispatchError::BadOrigin));
+    });
+}

+ 0 - 3
runtime-modules/forum/src/lib.rs

@@ -594,9 +594,6 @@ decl_module! {
 
             Self::ensure_can_create_thread(account_id, &forum_user_id, &category_id)?;
 
-            // Ensure data migration is done
-            Self::ensure_data_migration_done()?;
-
             // Check that thread can be added to category
             Self::ensure_category_is_mutable(&category_id)?;
 

+ 2 - 1
runtime-modules/membership/Cargo.toml

@@ -14,11 +14,11 @@ sp-arithmetic = { package = 'sp-arithmetic', default-features = false, git = 'ht
 sp-runtime = { package = 'sp-runtime', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 pallet-timestamp = { package = 'pallet-timestamp', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 common = { package = 'pallet-common', default-features = false, path = '../common'}
+balances = { package = 'pallet-balances', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 
 [dev-dependencies]
 sp-io = { package = 'sp-io', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 sp-core = { package = 'sp-core', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
-balances = { package = 'pallet-balances', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 
 [features]
 default = ['std']
@@ -32,4 +32,5 @@ std = [
 	'sp-runtime/std',
 	'pallet-timestamp/std',
 	'common/std',
+	'balances/std',
 ]

+ 1 - 0
runtime-modules/membership/src/lib.rs

@@ -7,6 +7,7 @@
 
 pub mod genesis;
 pub(crate) mod mock;
+pub mod staking_handler;
 mod tests;
 
 use codec::{Codec, Decode, Encode};

+ 41 - 0
runtime-modules/membership/src/staking_handler.rs

@@ -0,0 +1,41 @@
+use frame_support::dispatch::DispatchResult;
+
+// Type alias for member id.
+pub type MemberId<T> = <T as crate::Trait>::MemberId;
+
+/// Balance alias for `balances` module.
+pub type BalanceOf<T> = <T as balances::Trait>::Balance;
+
+/// Defines abstract staking handler to manage user stakes for different activities
+/// like adding a proposal. Implementation should use built-in LockableCurrency
+/// and LockIdentifier to lock balance consistently with pallet_staking.
+pub trait StakingHandler<T: frame_system::Trait + crate::Trait + balances::Trait> {
+    /// Locks the specified balance on the account using specific lock identifier.
+    fn lock(account_id: &T::AccountId, amount: BalanceOf<T>);
+
+    /// Removes the specified lock on the account.
+    fn unlock(account_id: &T::AccountId);
+
+    /// Slash the specified balance on the account using specific lock identifier.
+    /// No limits, no actions on zero stake.
+    /// If slashing balance greater than the existing stake - stake is slashed to zero.
+    /// Returns actually slashed balance.
+    fn slash(account_id: &T::AccountId, amount: Option<BalanceOf<T>>) -> BalanceOf<T>;
+
+    /// Sets the new stake to a given amount.
+    fn set_stake(account_id: &T::AccountId, new_stake: BalanceOf<T>) -> DispatchResult;
+
+    /// Verifies that staking account bound to the member.
+    fn is_member_staking_account(member_id: &MemberId<T>, account_id: &T::AccountId) -> bool;
+
+    /// Verifies that there no conflicting stakes on the staking account.
+    fn is_account_free_of_conflicting_stakes(account_id: &T::AccountId) -> bool;
+
+    /// Verifies that staking account balance is sufficient for staking.
+    /// During the balance check we should consider already locked stake. Effective balance to check
+    /// is 'already locked funds' + 'usable funds'.
+    fn is_enough_balance_for_stake(account_id: &T::AccountId, amount: BalanceOf<T>) -> bool;
+
+    /// Returns the current stake on the account.
+    fn current_stake(account_id: &T::AccountId) -> BalanceOf<T>;
+}

+ 3 - 1
runtime-modules/proposals/codex/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = 'pallet-proposals-codex'
-version = '3.1.0'
+version = '4.0.0'
 authors = ['Joystream contributors']
 edition = '2018'
 
@@ -24,6 +24,7 @@ working-group = { package = 'pallet-working-group', default-features = false, pa
 common = { package = 'pallet-common', default-features = false, path = '../../common'}
 proposals-engine = { package = 'pallet-proposals-engine', default-features = false, path = '../engine'}
 proposals-discussion = { package = 'pallet-proposals-discussion', default-features = false, path = '../discussion'}
+constitution = { package = 'pallet-constitution', default-features = false, path = '../../constitution'}
 
 [dev-dependencies]
 sp-io = { package = 'sp-io', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
@@ -55,4 +56,5 @@ std = [
     'common/std',
     'proposals-engine/std',
     'proposals-discussion/std',
+    'constitution/std',
 ]

+ 246 - 423
runtime-modules/proposals/codex/src/lib.rs

@@ -1,5 +1,5 @@
 //! # Proposals codex module
-//! Proposals `codex` module for the Joystream platform. Version 2.
+//! Proposals `codex` module for the Joystream platform. Version 3.
 //! Component of the proposals system. It contains preset proposal types.
 //!
 //! ## Overview
@@ -73,10 +73,13 @@ use sp_std::vec::Vec;
 use common::origin::ActorOriginValidator;
 use common::working_group::WorkingGroup;
 use governance::election_params::ElectionParameters;
-use proposals_engine::ProposalParameters;
+use proposals_discussion::ThreadMode;
+use proposals_engine::{
+    BalanceOf, ProposalCreationParameters, ProposalObserver, ProposalParameters,
+};
 
 pub use crate::proposal_types::{
-    AddOpeningParameters, FillOpeningParameters, ProposalsConfigParameters, TerminateRoleParameters,
+    AddOpeningParameters, FillOpeningParameters, TerminateRoleParameters,
 };
 pub use proposal_types::{ProposalDetails, ProposalDetailsOf, ProposalEncoder};
 
@@ -86,38 +89,6 @@ const WORKING_GROUP_MINT_CAPACITY_MAX_VALUE: u32 = 5_000_000;
 const MAX_SPENDING_PROPOSAL_VALUE: u32 = 5_000_000_u32;
 // Max validator count for the 'set validator count' proposal
 const MAX_VALIDATOR_COUNT: u32 = 100;
-// council_size min value for the 'set election parameters' proposal
-const ELECTION_PARAMETERS_COUNCIL_SIZE_MIN_VALUE: u32 = 4;
-// council_size max value for the 'set election parameters' proposal
-const ELECTION_PARAMETERS_COUNCIL_SIZE_MAX_VALUE: u32 = 20;
-// candidacy_limit min value for the 'set election parameters' proposal
-const ELECTION_PARAMETERS_CANDIDACY_LIMIT_MIN_VALUE: u32 = 25;
-// candidacy_limit max value for the 'set election parameters' proposal
-const ELECTION_PARAMETERS_CANDIDACY_LIMIT_MAX_VALUE: u32 = 100;
-// min_voting_stake min value for the 'set election parameters' proposal
-const ELECTION_PARAMETERS_MIN_STAKE_MIN_VALUE: u32 = 1;
-// min_voting_stake max value for the 'set election parameters' proposal
-const ELECTION_PARAMETERS_MIN_STAKE_MAX_VALUE: u32 = 100_000_u32;
-// new_term_duration min value for the 'set election parameters' proposal
-const ELECTION_PARAMETERS_NEW_TERM_DURATION_MIN_VALUE: u32 = 14400;
-// new_term_duration max value for the 'set election parameters' proposal
-const ELECTION_PARAMETERS_NEW_TERM_DURATION_MAX_VALUE: u32 = 432_000;
-// revealing_period min value for the 'set election parameters' proposal
-const ELECTION_PARAMETERS_REVEALING_PERIOD_MIN_VALUE: u32 = 14400;
-// revealing_period max value for the 'set election parameters' proposal
-const ELECTION_PARAMETERS_REVEALING_PERIOD_MAX_VALUE: u32 = 28800;
-// voting_period min value for the 'set election parameters' proposal
-const ELECTION_PARAMETERS_VOTING_PERIOD_MIN_VALUE: u32 = 14400;
-// voting_period max value for the 'set election parameters' proposal
-const ELECTION_PARAMETERS_VOTING_PERIOD_MAX_VALUE: u32 = 28800;
-// announcing_period min value for the 'set election parameters' proposal
-const ELECTION_PARAMETERS_ANNOUNCING_PERIOD_MIN_VALUE: u32 = 14400;
-// announcing_period max value for the 'set election parameters' proposal
-const ELECTION_PARAMETERS_ANNOUNCING_PERIOD_MAX_VALUE: u32 = 43200;
-// min_council_stake min value for the 'set election parameters' proposal
-const ELECTION_PARAMETERS_MIN_COUNCIL_STAKE_MIN_VALUE: u32 = 1;
-// min_council_stake max value for the 'set election parameters' proposal
-const ELECTION_PARAMETERS_MIN_COUNCIL_STAKE_MAX_VALUE: u32 = 100_000_u32;
 
 // Data container struct to fix linter warning 'too many arguments for the function' for the
 // create_proposal() function.
@@ -126,10 +97,11 @@ struct CreateProposalParameters<T: Trait> {
     pub member_id: MemberId<T>,
     pub title: Vec<u8>,
     pub description: Vec<u8>,
-    pub stake_balance: Option<BalanceOf<T>>,
+    pub staking_account_id: Option<T::AccountId>,
     pub proposal_code: Vec<u8>,
     pub proposal_parameters: ProposalParameters<T::BlockNumber, BalanceOf<T>>,
     pub proposal_details: ProposalDetailsOf<T>,
+    pub exact_execution_block: Option<T::BlockNumber>,
 }
 
 /// 'Proposals codex' substrate module Trait
@@ -148,23 +120,77 @@ pub trait Trait:
     /// Defines max wasm code length of the runtime upgrade proposal.
     type RuntimeUpgradeWasmProposalMaxLength: Get<u32>;
 
-    /// Validates member id and origin combination
+    /// Validates member id and origin combination.
     type MembershipOriginValidator: ActorOriginValidator<
         Self::Origin,
         MemberId<Self>,
         Self::AccountId,
     >;
 
-    /// Encodes the proposal usint its details
+    /// Encodes the proposal usint its details.
     type ProposalEncoder: ProposalEncoder<Self>;
-}
 
-/// Balance alias for `stake` module
-pub type BalanceOf<T> =
-    <<T as stake::Trait>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::Balance;
+    /// 'Set validator count' proposal parameters.
+    type SetValidatorCountProposalParameters: Get<
+        ProposalParameters<Self::BlockNumber, BalanceOf<Self>>,
+    >;
+
+    /// 'Runtime upgrade' proposal parameters.
+    type RuntimeUpgradeProposalParameters: Get<
+        ProposalParameters<Self::BlockNumber, BalanceOf<Self>>,
+    >;
+
+    /// 'Text' proposal parameters.
+    type TextProposalParameters: Get<ProposalParameters<Self::BlockNumber, BalanceOf<Self>>>;
+
+    /// 'Spending' proposal parameters.
+    type SpendingProposalParameters: Get<ProposalParameters<Self::BlockNumber, BalanceOf<Self>>>;
 
-/// Currency alias for `stake` module
-pub type CurrencyOf<T> = <T as stake::Trait>::Currency;
+    /// 'Add working group opening' proposal parameters.
+    type AddWorkingGroupOpeningProposalParameters: Get<
+        ProposalParameters<Self::BlockNumber, BalanceOf<Self>>,
+    >;
+
+    /// 'Begin review working group applications' proposal parameters.
+    type BeginReviewWorkingGroupApplicationsProposalParameters: Get<
+        ProposalParameters<Self::BlockNumber, BalanceOf<Self>>,
+    >;
+
+    /// 'Fill working group opening' proposal parameters.
+    type FillWorkingGroupOpeningProposalParameters: Get<
+        ProposalParameters<Self::BlockNumber, BalanceOf<Self>>,
+    >;
+
+    /// 'Set working group mint capacity' proposal parameters.
+    type SetWorkingGroupMintCapacityProposalParameters: Get<
+        ProposalParameters<Self::BlockNumber, BalanceOf<Self>>,
+    >;
+
+    /// 'Decrease working group leader stake' proposal parameters.
+    type DecreaseWorkingGroupLeaderStakeProposalParameters: Get<
+        ProposalParameters<Self::BlockNumber, BalanceOf<Self>>,
+    >;
+
+    /// 'Slash working group leader stake' proposal parameters.
+    type SlashWorkingGroupLeaderStakeProposalParameters: Get<
+        ProposalParameters<Self::BlockNumber, BalanceOf<Self>>,
+    >;
+
+    /// 'Set working group leader reward' proposal parameters.
+    type SetWorkingGroupLeaderRewardProposalParameters: Get<
+        ProposalParameters<Self::BlockNumber, BalanceOf<Self>>,
+    >;
+
+    /// 'Terminate working group leader role' proposal parameters.
+    type TerminateWorkingGroupLeaderRoleProposalParameters: Get<
+        ProposalParameters<Self::BlockNumber, BalanceOf<Self>>,
+    >;
+
+    /// 'Amend constitution' proposal parameters.
+    type AmendConstitutionProposalParameters: Get<
+        ProposalParameters<Self::BlockNumber, BalanceOf<Self>>,
+    >;
+}
 
 /// Balance alias for GovernanceCurrency from `common` module. TODO: replace with BalanceOf
 pub type BalanceOfGovernanceCurrency<T> =
@@ -176,11 +202,6 @@ pub type BalanceOfGovernanceCurrency<T> =
 pub type BalanceOfMint<T> =
     <<T as minting::Trait>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::Balance;
 
-/// Negative imbalance alias for staking
-pub type NegativeImbalance<T> = <<T as stake::Trait>::Currency as Currency<
-    <T as frame_system::Trait>::AccountId,
->>::NegativeImbalance;
-
 type MemberId<T> = <T as membership::Trait>::MemberId;
 
 decl_error! {
@@ -250,115 +271,73 @@ decl_error! {
 
 // Storage for the proposals codex module
 decl_storage! {
-    pub trait Store for Module<T: Trait> as ProposalCodex{
+    pub trait Store for Module<T: Trait> as ProposalCodex {
         /// Map proposal id to its discussion thread id
         pub ThreadIdByProposalId get(fn thread_id_by_proposal_id):
             map hasher(blake2_128_concat) T::ProposalId => T::ThreadId;
 
         /// Map proposal id to proposal details
         pub ProposalDetailsByProposalId: map hasher(blake2_128_concat) T::ProposalId => ProposalDetailsOf<T>;
+    }
+}
 
-        /// Voting period for the 'set validator count' proposal
-        pub SetValidatorCountProposalVotingPeriod get(fn set_validator_count_proposal_voting_period)
-            config(): T::BlockNumber;
-
-        /// Grace period for the 'set validator count' proposal
-        pub SetValidatorCountProposalGracePeriod get(fn set_validator_count_proposal_grace_period)
-            config(): T::BlockNumber;
-
-        /// Voting period for the 'runtime upgrade' proposal
-        pub RuntimeUpgradeProposalVotingPeriod get(fn runtime_upgrade_proposal_voting_period)
-            config(): T::BlockNumber;
-
-        /// Grace period for the 'runtime upgrade' proposal
-        pub RuntimeUpgradeProposalGracePeriod get(fn runtime_upgrade_proposal_grace_period)
-            config(): T::BlockNumber;
-
-        /// Voting period for the 'set election parameters' proposal
-        pub SetElectionParametersProposalVotingPeriod get(fn set_election_parameters_proposal_voting_period)
-            config(): T::BlockNumber;
-
-        /// Grace period for the 'set election parameters' proposal
-        pub SetElectionParametersProposalGracePeriod get(fn set_election_parameters_proposal_grace_period)
-            config(): T::BlockNumber;
-
-        /// Voting period for the 'text' proposal
-        pub TextProposalVotingPeriod get(fn text_proposal_voting_period) config(): T::BlockNumber;
-
-        /// Grace period for the 'text' proposal
-        pub TextProposalGracePeriod get(fn text_proposal_grace_period) config(): T::BlockNumber;
-
-        /// Voting period for the 'spending' proposal
-        pub SpendingProposalVotingPeriod get(fn spending_proposal_voting_period) config(): T::BlockNumber;
-
-        /// Grace period for the 'spending' proposal
-        pub SpendingProposalGracePeriod get(fn spending_proposal_grace_period) config(): T::BlockNumber;
-
-        /// Voting period for the 'add working group opening' proposal
-        pub AddWorkingGroupOpeningProposalVotingPeriod get(fn add_working_group_opening_proposal_voting_period) config(): T::BlockNumber;
-
-        /// Grace period for the 'add working group opening' proposal
-        pub AddWorkingGroupOpeningProposalGracePeriod get(fn add_working_group_opening_proposal_grace_period) config(): T::BlockNumber;
-
-        /// Voting period for the 'begin review working group leader applications' proposal
-        pub BeginReviewWorkingGroupLeaderApplicationsProposalVotingPeriod get(fn begin_review_working_group_leader_applications_proposal_voting_period) config(): T::BlockNumber;
-
-        /// Grace period for the 'begin review working group leader applications' proposal
-        pub BeginReviewWorkingGroupLeaderApplicationsProposalGracePeriod get(fn begin_review_working_group_leader_applications_proposal_grace_period) config(): T::BlockNumber;
+decl_module! {
+    /// Proposal codex substrate module Call
+    pub struct Module<T: Trait> for enum Call where origin: T::Origin {
+        /// Predefined errors
+        type Error = Error<T>;
 
-        /// Voting period for the 'fill working group leader opening' proposal
-        pub FillWorkingGroupLeaderOpeningProposalVotingPeriod get(fn fill_working_group_leader_opening_proposal_voting_period) config(): T::BlockNumber;
+        /// Exports 'Set validator count' proposal parameters.
+        const SetValidatorCountProposalParameters: ProposalParameters<T::BlockNumber, BalanceOf<T>>
+            = T::SetValidatorCountProposalParameters::get();
 
-        /// Grace period for the 'fill working group leader opening' proposal
-        pub FillWorkingGroupLeaderOpeningProposalGracePeriod get(fn fill_working_group_leader_opening_proposal_grace_period) config(): T::BlockNumber;
+        /// Exports 'Runtime upgrade' proposal parameters.
+        const RuntimeUpgradeProposalParameters: ProposalParameters<T::BlockNumber, BalanceOf<T>>
+            = T::RuntimeUpgradeProposalParameters::get();
 
-        /// Voting period for the 'set working group mint capacity' proposal
-        pub SetWorkingGroupMintCapacityProposalVotingPeriod get(fn set_working_group_mint_capacity_proposal_voting_period)
-            config(): T::BlockNumber;
+        /// Exports 'Text' proposal parameters.
+        const TextProposalParameters: ProposalParameters<T::BlockNumber, BalanceOf<T>>
+            = T::TextProposalParameters::get();
 
-        /// Grace period for the 'set working group mint capacity' proposal
-        pub SetWorkingGroupMintCapacityProposalGracePeriod get(fn set_working_group_mint_capacity_proposal_grace_period)
-            config(): T::BlockNumber;
+        /// Exports 'Spending' proposal parameters.
+        const SpendingProposalParameters: ProposalParameters<T::BlockNumber, BalanceOf<T>>
+            = T::SpendingProposalParameters::get();
 
-        /// Voting period for the 'decrease working group leader stake' proposal
-        pub DecreaseWorkingGroupLeaderStakeProposalVotingPeriod get(fn decrease_working_group_leader_stake_proposal_voting_period)
-            config(): T::BlockNumber;
+        /// Exports 'Add working group opening' proposal parameters.
+        const AddWorkingGroupOpeningProposalParameters: ProposalParameters<T::BlockNumber, BalanceOf<T>>
+            = T::AddWorkingGroupOpeningProposalParameters::get();
 
-        /// Grace period for the 'decrease working group leader stake' proposal
-        pub DecreaseWorkingGroupLeaderStakeProposalGracePeriod get(fn decrease_working_group_leader_stake_proposal_grace_period)
-            config(): T::BlockNumber;
+        /// Exports 'Begin review working group applications' proposal parameters.
+        const BeginReviewWorkingGroupApplicationsProposalParameters: ProposalParameters<T::BlockNumber, BalanceOf<T>>
+            = T::BeginReviewWorkingGroupApplicationsProposalParameters::get();
 
-        /// Voting period for the 'slash working group leader stake' proposal
-        pub SlashWorkingGroupLeaderStakeProposalVotingPeriod get(fn slash_working_group_leader_stake_proposal_voting_period)
-            config(): T::BlockNumber;
+        /// Exports 'Fill working group opening' proposal parameters.
+        const FillWorkingGroupOpeningProposalParameters: ProposalParameters<T::BlockNumber, BalanceOf<T>>
+            = T::FillWorkingGroupOpeningProposalParameters::get();
 
-        /// Grace period for the 'slash working group leader stake' proposal
-        pub SlashWorkingGroupLeaderStakeProposalGracePeriod get(fn slash_working_group_leader_stake_proposal_grace_period)
-            config(): T::BlockNumber;
+        /// Exports 'Set working group mint capacity' proposal parameters.
+        const SetWorkingGroupMintCapacityProposalParameters: ProposalParameters<T::BlockNumber, BalanceOf<T>>
+            = T::SetWorkingGroupMintCapacityProposalParameters::get();
 
-        /// Voting period for the 'set working group leader reward' proposal
-        pub SetWorkingGroupLeaderRewardProposalVotingPeriod get(fn set_working_group_leader_reward_proposal_voting_period)
-            config(): T::BlockNumber;
+        /// Exports 'Decrease working group leader stake' proposal parameters.
+        const DecreaseWorkingGroupLeaderStakeProposalParameters: ProposalParameters<T::BlockNumber, BalanceOf<T>>
+            = T::DecreaseWorkingGroupLeaderStakeProposalParameters::get();
 
-        /// Grace period for the 'set working group leader reward' proposal
-        pub SetWorkingGroupLeaderRewardProposalGracePeriod get(fn set_working_group_leader_reward_proposal_grace_period)
-            config(): T::BlockNumber;
+        /// Exports 'Slash working group leader stake' proposal parameters.
+        const SlashWorkingGroupLeaderStakeProposalParameters: ProposalParameters<T::BlockNumber, BalanceOf<T>>
+            = T::SlashWorkingGroupLeaderStakeProposalParameters::get();
 
-        /// Voting period for the 'terminate working group leader role' proposal
-        pub TerminateWorkingGroupLeaderRoleProposalVotingPeriod get(fn terminate_working_group_leader_role_proposal_voting_period)
-            config(): T::BlockNumber;
+        /// Exports 'Set working group leader reward' proposal parameters.
+        const SetWorkingGroupLeaderRewardProposalParameters: ProposalParameters<T::BlockNumber, BalanceOf<T>>
+            = T::SetWorkingGroupLeaderRewardProposalParameters::get();
 
-        /// Grace period for the 'terminate working group leader role' proposal
-        pub TerminateWorkingGroupLeaderRoleProposalGracePeriod get(fn terminate_working_group_leader_role_proposal_grace_period)
-            config(): T::BlockNumber;
-    }
-}
+        /// Exports 'Terminate working group leader role' proposal parameters.
+        const TerminateWorkingGroupLeaderRoleProposalParameters: ProposalParameters<T::BlockNumber, BalanceOf<T>>
+            = T::TerminateWorkingGroupLeaderRoleProposalParameters::get();
 
-decl_module! {
-    /// Proposal codex substrate module Call
-    pub struct Module<T: Trait> for enum Call where origin: T::Origin {
-        /// Predefined errors
-        type Error = Error<T>;
+        /// Exports 'Amend constitution' proposal parameters.
+        const AmendConstitutionProposalParameters: ProposalParameters<T::BlockNumber, BalanceOf<T>>
+            = T::AmendConstitutionProposalParameters::get();
 
         /// Exports max allowed text proposal length const.
         const TextProposalMaxLength: u32 = T::TextProposalMaxLength::get();
@@ -373,8 +352,9 @@ decl_module! {
             member_id: MemberId<T>,
             title: Vec<u8>,
             description: Vec<u8>,
-            stake_balance: Option<BalanceOf<T>>,
+            staking_account_id: Option<T::AccountId>,
             text: Vec<u8>,
+            exact_execution_block: Option<T::BlockNumber>,
         ) {
             ensure!(!text.is_empty(), Error::<T>::TextProposalIsEmpty);
             ensure!(text.len() as u32 <=  T::TextProposalMaxLength::get(),
@@ -386,10 +366,11 @@ decl_module! {
                 member_id,
                 title,
                 description,
-                stake_balance,
+                staking_account_id,
                 proposal_details: proposal_details.clone(),
-                proposal_parameters: proposal_types::parameters::text_proposal::<T>(),
-                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details)
+                proposal_parameters: T::TextProposalParameters::get(),
+                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details),
+                exact_execution_block
             };
 
             Self::create_proposal(params)?;
@@ -403,8 +384,9 @@ decl_module! {
             member_id: MemberId<T>,
             title: Vec<u8>,
             description: Vec<u8>,
-            stake_balance: Option<BalanceOf<T>>,
+            staking_account_id: Option<T::AccountId>,
             wasm: Vec<u8>,
+            exact_execution_block: Option<T::BlockNumber>,
         ) {
             ensure!(!wasm.is_empty(), Error::<T>::RuntimeProposalIsEmpty);
             ensure!(wasm.len() as u32 <= T::RuntimeUpgradeWasmProposalMaxLength::get(),
@@ -416,40 +398,11 @@ decl_module! {
                 member_id,
                 title,
                 description,
-                stake_balance,
+                staking_account_id,
                 proposal_details: proposal_details.clone(),
-                proposal_parameters: proposal_types::parameters::runtime_upgrade_proposal::<T>(),
-                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details)
-            };
-
-            Self::create_proposal(params)?;
-        }
-
-        /// Create 'Set election parameters' proposal type. This proposal uses `set_election_parameters()`
-        /// extrinsic from the `governance::election module`.
-        #[weight = 10_000_000] // TODO: adjust weight
-        pub fn create_set_election_parameters_proposal(
-            origin,
-            member_id: MemberId<T>,
-            title: Vec<u8>,
-            description: Vec<u8>,
-            stake_balance: Option<BalanceOf<T>>,
-            election_parameters: ElectionParameters<BalanceOfGovernanceCurrency<T>, T::BlockNumber>,
-        ) {
-            election_parameters.ensure_valid()?;
-
-            Self::ensure_council_election_parameters_valid(&election_parameters)?;
-
-            let proposal_details = ProposalDetails::SetElectionParameters(election_parameters);
-            let params = CreateProposalParameters{
-                origin,
-                member_id,
-                title,
-                description,
-                stake_balance,
-                proposal_details: proposal_details.clone(),
-                proposal_parameters: proposal_types::parameters::set_election_parameters_proposal::<T>(),
-                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details)
+                proposal_parameters: T::RuntimeUpgradeProposalParameters::get(),
+                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details),
+                exact_execution_block,
             };
 
             Self::create_proposal(params)?;
@@ -463,9 +416,10 @@ decl_module! {
             member_id: MemberId<T>,
             title: Vec<u8>,
             description: Vec<u8>,
-            stake_balance: Option<BalanceOf<T>>,
+            staking_account_id: Option<T::AccountId>,
             balance: BalanceOfMint<T>,
             destination: T::AccountId,
+            exact_execution_block: Option<T::BlockNumber>,
         ) {
             ensure!(balance != BalanceOfMint::<T>::zero(), Error::<T>::InvalidSpendingProposalBalance);
             ensure!(
@@ -479,10 +433,11 @@ decl_module! {
                 member_id,
                 title,
                 description,
-                stake_balance,
+                staking_account_id,
                 proposal_details: proposal_details.clone(),
-                proposal_parameters: proposal_types::parameters::spending_proposal::<T>(),
-                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details)
+                proposal_parameters: T::SpendingProposalParameters::get(),
+                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details),
+                exact_execution_block,
             };
 
             Self::create_proposal(params)?;
@@ -496,8 +451,9 @@ decl_module! {
             member_id: MemberId<T>,
             title: Vec<u8>,
             description: Vec<u8>,
-            stake_balance: Option<BalanceOf<T>>,
+            staking_account_id: Option<T::AccountId>,
             new_validator_count: u32,
+            exact_execution_block: Option<T::BlockNumber>,
         ) {
             ensure!(
                 new_validator_count >= <staking::Module<T>>::minimum_validator_count(),
@@ -515,10 +471,11 @@ decl_module! {
                 member_id,
                 title,
                 description,
-                stake_balance,
+                staking_account_id,
                 proposal_details: proposal_details.clone(),
-                proposal_parameters: proposal_types::parameters::set_validator_count_proposal::<T>(),
-                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details)
+                proposal_parameters: T::SetValidatorCountProposalParameters::get(),
+                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details),
+                exact_execution_block,
             };
 
             Self::create_proposal(params)?;
@@ -532,20 +489,21 @@ decl_module! {
             member_id: MemberId<T>,
             title: Vec<u8>,
             description: Vec<u8>,
-            stake_balance: Option<BalanceOf<T>>,
+            staking_account_id: Option<T::AccountId>,
             add_opening_parameters: AddOpeningParameters<T::BlockNumber, BalanceOfGovernanceCurrency<T>>,
+            exact_execution_block: Option<T::BlockNumber>,
         ) {
-
             let proposal_details = ProposalDetails::AddWorkingGroupLeaderOpening(add_opening_parameters);
             let params = CreateProposalParameters{
                 origin,
                 member_id,
                 title,
                 description,
-                stake_balance,
+                staking_account_id,
                 proposal_details: proposal_details.clone(),
-                proposal_parameters: proposal_types::parameters::add_working_group_leader_opening_proposal::<T>(),
-                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details)
+                proposal_parameters: T::AddWorkingGroupOpeningProposalParameters::get(),
+                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details),
+                exact_execution_block,
             };
 
             Self::create_proposal(params)?;
@@ -559,21 +517,22 @@ decl_module! {
             member_id: MemberId<T>,
             title: Vec<u8>,
             description: Vec<u8>,
-            stake_balance: Option<BalanceOf<T>>,
+            staking_account_id: Option<T::AccountId>,
             opening_id: working_group::OpeningId<T>,
             working_group: WorkingGroup,
+            exact_execution_block: Option<T::BlockNumber>,
         ) {
-
             let proposal_details = ProposalDetails::BeginReviewWorkingGroupLeaderApplications(opening_id, working_group);
             let params = CreateProposalParameters{
                 origin,
                 member_id,
                 title,
                 description,
-                stake_balance,
+                staking_account_id,
                 proposal_details: proposal_details.clone(),
-                proposal_parameters: proposal_types::parameters::begin_review_working_group_leader_applications_proposal::<T>(),
-                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details)
+                proposal_parameters: T::BeginReviewWorkingGroupApplicationsProposalParameters::get(),
+                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details),
+                exact_execution_block,
             };
 
             Self::create_proposal(params)?;
@@ -587,25 +546,26 @@ decl_module! {
             member_id: MemberId<T>,
             title: Vec<u8>,
             description: Vec<u8>,
-            stake_balance: Option<BalanceOf<T>>,
+            staking_account_id: Option<T::AccountId>,
             fill_opening_parameters: FillOpeningParameters<
                 T::BlockNumber,
                 BalanceOfMint<T>,
                 working_group::OpeningId<T>,
                 working_group::ApplicationId<T>
-            >
+            >,
+            exact_execution_block: Option<T::BlockNumber>,
         ) {
-
             let proposal_details = ProposalDetails::FillWorkingGroupLeaderOpening(fill_opening_parameters);
             let params = CreateProposalParameters{
                 origin,
                 member_id,
                 title,
                 description,
-                stake_balance,
+                staking_account_id,
                 proposal_details: proposal_details.clone(),
-                proposal_parameters: proposal_types::parameters::fill_working_group_leader_opening_proposal::<T>(),
-                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details)
+                proposal_parameters: T::FillWorkingGroupOpeningProposalParameters::get(),
+                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details),
+                exact_execution_block,
             };
 
             Self::create_proposal(params)?;
@@ -619,9 +579,10 @@ decl_module! {
             member_id: MemberId<T>,
             title: Vec<u8>,
             description: Vec<u8>,
-            stake_balance: Option<BalanceOf<T>>,
+            staking_account_id: Option<T::AccountId>,
             mint_balance: BalanceOfMint<T>,
             working_group: WorkingGroup,
+            exact_execution_block: Option<T::BlockNumber>,
         ) {
             ensure!(
                 mint_balance <= <BalanceOfMint<T>>::from(WORKING_GROUP_MINT_CAPACITY_MAX_VALUE),
@@ -634,10 +595,11 @@ decl_module! {
                 member_id,
                 title,
                 description,
-                stake_balance,
+                staking_account_id,
                 proposal_details: proposal_details.clone(),
-                proposal_parameters: proposal_types::parameters::set_working_group_mint_capacity_proposal::<T>(),
-                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details)
+                proposal_parameters: T::SetWorkingGroupMintCapacityProposalParameters::get(),
+                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details),
+                exact_execution_block,
             };
 
             Self::create_proposal(params)?;
@@ -651,12 +613,12 @@ decl_module! {
             member_id: MemberId<T>,
             title: Vec<u8>,
             description: Vec<u8>,
-            stake_balance: Option<BalanceOf<T>>,
+            staking_account_id: Option<T::AccountId>,
             worker_id: working_group::WorkerId<T>,
             decreasing_stake: BalanceOf<T>,
             working_group: WorkingGroup,
+            exact_execution_block: Option<T::BlockNumber>,
         ) {
-
             ensure!(decreasing_stake != Zero::zero(), Error::<T>::DecreasingStakeIsZero);
 
             let proposal_details = ProposalDetails::DecreaseWorkingGroupLeaderStake(
@@ -670,10 +632,11 @@ decl_module! {
                 member_id,
                 title,
                 description,
-                stake_balance,
+                staking_account_id,
                 proposal_details: proposal_details.clone(),
-                proposal_parameters: proposal_types::parameters::decrease_working_group_leader_stake_proposal::<T>(),
-                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details)
+                proposal_parameters: T::DecreaseWorkingGroupLeaderStakeProposalParameters::get(),
+                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details),
+                exact_execution_block,
             };
 
             Self::create_proposal(params)?;
@@ -687,12 +650,12 @@ decl_module! {
             member_id: MemberId<T>,
             title: Vec<u8>,
             description: Vec<u8>,
-            stake_balance: Option<BalanceOf<T>>,
+            staking_account_id: Option<T::AccountId>,
             worker_id: working_group::WorkerId<T>,
             slashing_stake: BalanceOf<T>,
             working_group: WorkingGroup,
+            exact_execution_block: Option<T::BlockNumber>,
         ) {
-
             ensure!(slashing_stake != Zero::zero(), Error::<T>::SlashingStakeIsZero);
 
             let proposal_details = ProposalDetails::SlashWorkingGroupLeaderStake(
@@ -706,10 +669,11 @@ decl_module! {
                 member_id,
                 title,
                 description,
-                stake_balance,
+                staking_account_id,
                 proposal_details: proposal_details.clone(),
-                proposal_parameters: proposal_types::parameters::slash_working_group_leader_stake_proposal::<T>(),
-                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details)
+                proposal_parameters: T::SlashWorkingGroupLeaderStakeProposalParameters::get(),
+                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details),
+                exact_execution_block,
             };
 
             Self::create_proposal(params)?;
@@ -723,12 +687,12 @@ decl_module! {
             member_id: MemberId<T>,
             title: Vec<u8>,
             description: Vec<u8>,
-            stake_balance: Option<BalanceOf<T>>,
+            staking_account_id: Option<T::AccountId>,
             worker_id: working_group::WorkerId<T>,
             reward_amount: BalanceOfMint<T>,
             working_group: WorkingGroup,
+            exact_execution_block: Option<T::BlockNumber>,
         ) {
-
             let proposal_details = ProposalDetails::SetWorkingGroupLeaderReward(
                 worker_id,
                 reward_amount,
@@ -740,16 +704,17 @@ decl_module! {
                 member_id,
                 title,
                 description,
-                stake_balance,
+                staking_account_id,
                 proposal_details: proposal_details.clone(),
-                proposal_parameters: proposal_types::parameters::set_working_group_leader_reward_proposal::<T>(),
-                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details)
+                proposal_parameters: T::SetWorkingGroupLeaderRewardProposalParameters::get(),
+                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details),
+                exact_execution_block,
             };
 
             Self::create_proposal(params)?;
         }
 
-        /// Create 'terminate working group leader rolw' proposal type.
+        /// Create 'terminate working group leader role' proposal type.
         /// This proposal uses `terminate_role()` extrinsic from the `working-group`  module.
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn create_terminate_working_group_leader_role_proposal(
@@ -757,8 +722,9 @@ decl_module! {
             member_id: MemberId<T>,
             title: Vec<u8>,
             description: Vec<u8>,
-            stake_balance: Option<BalanceOf<T>>,
+            staking_account_id: Option<T::AccountId>,
             terminate_role_parameters: TerminateRoleParameters<working_group::WorkerId<T>>,
+            exact_execution_block: Option<T::BlockNumber>,
         ) {
             let proposal_details = ProposalDetails::TerminateWorkingGroupLeaderRole(terminate_role_parameters);
 
@@ -767,10 +733,40 @@ decl_module! {
                 member_id,
                 title,
                 description,
-                stake_balance,
+                staking_account_id,
+                proposal_details: proposal_details.clone(),
+                proposal_parameters: T::TerminateWorkingGroupLeaderRoleProposalParameters::get(),
+                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details),
+                exact_execution_block,
+            };
+
+            Self::create_proposal(params)?;
+        }
+
+        /// Create 'amend constitution' proposal type.
+        /// This proposal uses `amend_constitution()` extrinsic from the `constitution`  module.
+        #[weight = 10_000_000] // TODO: adjust weight
+        pub fn create_amend_constitution_proposal(
+            origin,
+            member_id: MemberId<T>,
+            title: Vec<u8>,
+            description: Vec<u8>,
+            staking_account_id: Option<T::AccountId>,
+            constitution_text: Vec<u8>,
+            exact_execution_block: Option<T::BlockNumber>,
+        ) {
+            let proposal_details = ProposalDetails::AmendConstitution(constitution_text);
+
+            let params = CreateProposalParameters{
+                origin,
+                member_id,
+                title,
+                description,
+                staking_account_id,
                 proposal_details: proposal_details.clone(),
-                proposal_parameters: proposal_types::parameters::terminate_working_group_leader_role_proposal::<T>(),
-                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details)
+                proposal_parameters: T::AmendConstitutionProposalParameters::get(),
+                proposal_code: T::ProposalEncoder::encode_proposal(proposal_details),
+                exact_execution_block,
             };
 
             Self::create_proposal(params)?;
@@ -800,12 +796,11 @@ decl_module! {
             origin,
             wasm: Vec<u8>,
         ) {
-            let (cloned_origin1, cloned_origin2) = common::origin::double_origin::<T>(origin);
-            ensure_root(cloned_origin1)?;
+            ensure_root(origin.clone())?;
 
             print("Runtime upgrade proposal execution started.");
 
-            <frame_system::Module<T>>::set_code(cloned_origin2, wasm)?;
+            <frame_system::Module<T>>::set_code(origin, wasm)?;
 
             print("Runtime upgrade proposal execution finished.");
         }
@@ -822,218 +817,46 @@ impl<T: Trait> Module<T> {
             &params.proposal_parameters,
             &params.title,
             &params.description,
-            params.stake_balance,
+            params.staking_account_id.clone(),
+            params.exact_execution_block,
         )?;
 
-        <proposals_discussion::Module<T>>::ensure_can_create_thread(
-            params.member_id,
-            &params.title,
-        )?;
+        let initial_thread_mode = ThreadMode::Open;
+        <proposals_discussion::Module<T>>::ensure_can_create_thread(&initial_thread_mode)?;
 
         let discussion_thread_id = <proposals_discussion::Module<T>>::create_thread(
             params.member_id,
-            params.title.clone(),
+            initial_thread_mode,
         )?;
 
-        let proposal_id = <proposals_engine::Module<T>>::create_proposal(
+        let proposal_creation_params = ProposalCreationParameters {
             account_id,
-            params.member_id,
-            params.proposal_parameters,
-            params.title,
-            params.description,
-            params.stake_balance,
-            params.proposal_code,
-        )?;
+            proposer_id: params.member_id,
+            proposal_parameters: params.proposal_parameters,
+            title: params.title,
+            description: params.description,
+            staking_account_id: params.staking_account_id,
+            encoded_dispatchable_call_code: params.proposal_code,
+            exact_execution_block: params.exact_execution_block,
+        };
+
+        let proposal_id = <proposals_engine::Module<T>>::create_proposal(proposal_creation_params)?;
 
         <ThreadIdByProposalId<T>>::insert(proposal_id, discussion_thread_id);
         <ProposalDetailsByProposalId<T>>::insert(proposal_id, params.proposal_details);
 
         Ok(())
     }
+}
 
-    // validates council election parameters for the 'Set election parameters' proposal
-    pub(crate) fn ensure_council_election_parameters_valid(
-        election_parameters: &ElectionParameters<BalanceOfGovernanceCurrency<T>, T::BlockNumber>,
-    ) -> DispatchResult {
-        ensure!(
-            election_parameters.council_size >= ELECTION_PARAMETERS_COUNCIL_SIZE_MIN_VALUE,
-            Error::<T>::InvalidCouncilElectionParameterCouncilSize
-        );
-
-        ensure!(
-            election_parameters.council_size <= ELECTION_PARAMETERS_COUNCIL_SIZE_MAX_VALUE,
-            Error::<T>::InvalidCouncilElectionParameterCouncilSize
-        );
-
-        ensure!(
-            election_parameters.candidacy_limit >= ELECTION_PARAMETERS_CANDIDACY_LIMIT_MIN_VALUE,
-            Error::<T>::InvalidCouncilElectionParameterCandidacyLimit
-        );
-
-        ensure!(
-            election_parameters.candidacy_limit <= ELECTION_PARAMETERS_CANDIDACY_LIMIT_MAX_VALUE,
-            Error::<T>::InvalidCouncilElectionParameterCandidacyLimit
-        );
-
-        ensure!(
-            election_parameters.min_voting_stake
-                >= <BalanceOfGovernanceCurrency<T>>::from(ELECTION_PARAMETERS_MIN_STAKE_MIN_VALUE),
-            Error::<T>::InvalidCouncilElectionParameterMinVotingStake
-        );
-
-        ensure!(
-            election_parameters.min_voting_stake
-                <= <BalanceOfGovernanceCurrency<T>>::from(ELECTION_PARAMETERS_MIN_STAKE_MAX_VALUE),
-            Error::<T>::InvalidCouncilElectionParameterMinVotingStake
-        );
-
-        ensure!(
-            election_parameters.new_term_duration
-                >= T::BlockNumber::from(ELECTION_PARAMETERS_NEW_TERM_DURATION_MIN_VALUE),
-            Error::<T>::InvalidCouncilElectionParameterNewTermDuration
-        );
-
-        ensure!(
-            election_parameters.new_term_duration
-                <= T::BlockNumber::from(ELECTION_PARAMETERS_NEW_TERM_DURATION_MAX_VALUE),
-            Error::<T>::InvalidCouncilElectionParameterNewTermDuration
-        );
-
-        ensure!(
-            election_parameters.revealing_period
-                >= T::BlockNumber::from(ELECTION_PARAMETERS_REVEALING_PERIOD_MIN_VALUE),
-            Error::<T>::InvalidCouncilElectionParameterRevealingPeriod
-        );
-
-        ensure!(
-            election_parameters.revealing_period
-                <= T::BlockNumber::from(ELECTION_PARAMETERS_REVEALING_PERIOD_MAX_VALUE),
-            Error::<T>::InvalidCouncilElectionParameterRevealingPeriod
-        );
-
-        ensure!(
-            election_parameters.voting_period
-                >= T::BlockNumber::from(ELECTION_PARAMETERS_VOTING_PERIOD_MIN_VALUE),
-            Error::<T>::InvalidCouncilElectionParameterVotingPeriod
-        );
-
-        ensure!(
-            election_parameters.voting_period
-                <= T::BlockNumber::from(ELECTION_PARAMETERS_VOTING_PERIOD_MAX_VALUE),
-            Error::<T>::InvalidCouncilElectionParameterVotingPeriod
-        );
-
-        ensure!(
-            election_parameters.announcing_period
-                >= T::BlockNumber::from(ELECTION_PARAMETERS_ANNOUNCING_PERIOD_MIN_VALUE),
-            Error::<T>::InvalidCouncilElectionParameterAnnouncingPeriod
-        );
-
-        ensure!(
-            election_parameters.announcing_period
-                <= T::BlockNumber::from(ELECTION_PARAMETERS_ANNOUNCING_PERIOD_MAX_VALUE),
-            Error::<T>::InvalidCouncilElectionParameterAnnouncingPeriod
-        );
-
-        ensure!(
-            election_parameters.min_council_stake
-                >= <BalanceOfGovernanceCurrency<T>>::from(
-                    ELECTION_PARAMETERS_MIN_COUNCIL_STAKE_MIN_VALUE
-                ),
-            Error::<T>::InvalidCouncilElectionParameterMinCouncilStake
-        );
-
-        ensure!(
-            election_parameters.min_council_stake
-                <= <BalanceOfGovernanceCurrency<T>>::from(
-                    ELECTION_PARAMETERS_MIN_COUNCIL_STAKE_MAX_VALUE
-                ),
-            Error::<T>::InvalidCouncilElectionParameterMinCouncilStake
-        );
+impl<T: Trait> ProposalObserver<T> for Module<T> {
+    fn proposal_removed(proposal_id: &<T as proposals_engine::Trait>::ProposalId) {
+        <ThreadIdByProposalId<T>>::remove(proposal_id);
+        <ProposalDetailsByProposalId<T>>::remove(proposal_id);
 
-        Ok(())
-    }
+        let thread_id = Self::thread_id_by_proposal_id(proposal_id);
 
-    /// Sets config values for the proposals.
-    /// Should be called on the migration to the new runtime version.
-    pub fn set_config_values(p: ProposalsConfigParameters) {
-        <SetValidatorCountProposalVotingPeriod<T>>::put(T::BlockNumber::from(
-            p.set_validator_count_proposal_voting_period,
-        ));
-        <SetValidatorCountProposalGracePeriod<T>>::put(T::BlockNumber::from(
-            p.set_validator_count_proposal_grace_period,
-        ));
-        <RuntimeUpgradeProposalVotingPeriod<T>>::put(T::BlockNumber::from(
-            p.runtime_upgrade_proposal_voting_period,
-        ));
-        <RuntimeUpgradeProposalGracePeriod<T>>::put(T::BlockNumber::from(
-            p.runtime_upgrade_proposal_grace_period,
-        ));
-        <TextProposalVotingPeriod<T>>::put(T::BlockNumber::from(p.text_proposal_voting_period));
-        <TextProposalGracePeriod<T>>::put(T::BlockNumber::from(p.text_proposal_grace_period));
-        <SetElectionParametersProposalVotingPeriod<T>>::put(T::BlockNumber::from(
-            p.set_election_parameters_proposal_voting_period,
-        ));
-        <SetElectionParametersProposalGracePeriod<T>>::put(T::BlockNumber::from(
-            p.set_election_parameters_proposal_grace_period,
-        ));
-        <SpendingProposalVotingPeriod<T>>::put(T::BlockNumber::from(
-            p.spending_proposal_voting_period,
-        ));
-        <SpendingProposalGracePeriod<T>>::put(T::BlockNumber::from(
-            p.spending_proposal_grace_period,
-        ));
-        <AddWorkingGroupOpeningProposalVotingPeriod<T>>::put(T::BlockNumber::from(
-            p.add_working_group_opening_proposal_voting_period,
-        ));
-        <AddWorkingGroupOpeningProposalGracePeriod<T>>::put(T::BlockNumber::from(
-            p.add_working_group_opening_proposal_grace_period,
-        ));
-        <BeginReviewWorkingGroupLeaderApplicationsProposalVotingPeriod<T>>::put(
-            T::BlockNumber::from(
-                p.begin_review_working_group_leader_applications_proposal_voting_period,
-            ),
-        );
-        <BeginReviewWorkingGroupLeaderApplicationsProposalGracePeriod<T>>::put(
-            T::BlockNumber::from(
-                p.begin_review_working_group_leader_applications_proposal_grace_period,
-            ),
-        );
-        <FillWorkingGroupLeaderOpeningProposalVotingPeriod<T>>::put(T::BlockNumber::from(
-            p.fill_working_group_leader_opening_proposal_voting_period,
-        ));
-        <FillWorkingGroupLeaderOpeningProposalGracePeriod<T>>::put(T::BlockNumber::from(
-            p.fill_working_group_leader_opening_proposal_grace_period,
-        ));
-        <SetWorkingGroupMintCapacityProposalVotingPeriod<T>>::put(T::BlockNumber::from(
-            p.set_working_group_mint_capacity_proposal_voting_period,
-        ));
-        <SetWorkingGroupMintCapacityProposalGracePeriod<T>>::put(T::BlockNumber::from(
-            p.set_working_group_mint_capacity_proposal_grace_period,
-        ));
-        <DecreaseWorkingGroupLeaderStakeProposalVotingPeriod<T>>::put(T::BlockNumber::from(
-            p.decrease_working_group_leader_stake_proposal_voting_period,
-        ));
-        <DecreaseWorkingGroupLeaderStakeProposalGracePeriod<T>>::put(T::BlockNumber::from(
-            p.decrease_working_group_leader_stake_proposal_grace_period,
-        ));
-        <SlashWorkingGroupLeaderStakeProposalVotingPeriod<T>>::put(T::BlockNumber::from(
-            p.slash_working_group_leader_stake_proposal_voting_period,
-        ));
-        <SlashWorkingGroupLeaderStakeProposalGracePeriod<T>>::put(T::BlockNumber::from(
-            p.slash_working_group_leader_stake_proposal_grace_period,
-        ));
-        <SetWorkingGroupLeaderRewardProposalVotingPeriod<T>>::put(T::BlockNumber::from(
-            p.set_working_group_leader_reward_proposal_voting_period,
-        ));
-        <SetWorkingGroupLeaderRewardProposalGracePeriod<T>>::put(T::BlockNumber::from(
-            p.set_working_group_leader_reward_proposal_grace_period,
-        ));
-        <TerminateWorkingGroupLeaderRoleProposalVotingPeriod<T>>::put(T::BlockNumber::from(
-            p.terminate_working_group_leader_role_proposal_voting_period,
-        ));
-        <TerminateWorkingGroupLeaderRoleProposalGracePeriod<T>>::put(T::BlockNumber::from(
-            p.terminate_working_group_leader_role_proposal_grace_period,
-        ));
+        proposals_discussion::ThreadById::<T>::remove(thread_id);
+        proposals_discussion::PostThreadIdByPostId::<T>::remove_prefix(thread_id);
     }
 }

+ 5 - 163
runtime-modules/proposals/codex/src/proposal_types/mod.rs

@@ -1,7 +1,5 @@
 #![warn(missing_docs)]
 
-pub(crate) mod parameters;
-
 use codec::{Decode, Encode};
 #[cfg(feature = "std")]
 use serde::{Deserialize, Serialize};
@@ -49,6 +47,8 @@ pub enum ProposalDetails<
     /// The wasm code for the `runtime upgrade` proposal
     RuntimeUpgrade(Vec<u8>),
 
+    /// ********** Deprecated.
+    /// It is kept only for backward compatibility in the Pioneer. **********
     /// Election parameters for the `set election parameters` proposal
     SetElectionParameters(ElectionParameters<CurrencyBalance, BlockNumber>),
 
@@ -103,6 +103,9 @@ pub enum ProposalDetails<
 
     /// Fire the working group leader with possible slashing.
     TerminateWorkingGroupLeaderRole(TerminateRoleParameters<WorkerId>),
+
+    /// Amend constitution.
+    AmendConstitution(Vec<u8>),
 }
 
 impl<
@@ -222,164 +225,3 @@ pub struct RoleParameters<Balance, BlockNumber> {
     /// Small fee burned to make a request to enter role.
     pub entry_request_fee: Balance,
 }
-
-/// Contains proposal config parameters. Default values are used by migration and genesis config.
-#[derive(Copy, Clone)]
-pub struct ProposalsConfigParameters {
-    /// 'Set validator count' proposal voting period
-    pub set_validator_count_proposal_voting_period: u32,
-
-    /// 'Set validator count' proposal grace period
-    pub set_validator_count_proposal_grace_period: u32,
-
-    /// 'Runtime upgrade' proposal voting period
-    pub runtime_upgrade_proposal_voting_period: u32,
-
-    /// 'Runtime upgrade' proposal grace period
-    pub runtime_upgrade_proposal_grace_period: u32,
-
-    /// 'Text' proposal voting period
-    pub text_proposal_voting_period: u32,
-
-    /// 'Text' proposal grace period
-    pub text_proposal_grace_period: u32,
-
-    /// 'Set election parameters' proposal voting period
-    pub set_election_parameters_proposal_voting_period: u32,
-
-    /// 'Set election parameters' proposal grace period
-    pub set_election_parameters_proposal_grace_period: u32,
-
-    /// 'Set lead' proposal voting period
-    pub set_lead_proposal_voting_period: u32,
-
-    /// 'Set lead' proposal grace period
-    pub set_lead_proposal_grace_period: u32,
-
-    /// 'Spending' proposal voting period
-    pub spending_proposal_voting_period: u32,
-
-    /// 'Spending' proposal grace period
-    pub spending_proposal_grace_period: u32,
-
-    /// 'Add working group opening' proposal voting period
-    pub add_working_group_opening_proposal_voting_period: u32,
-
-    /// 'Add working group opening' proposal grace period
-    pub add_working_group_opening_proposal_grace_period: u32,
-
-    /// 'Begin review working group leader applications' proposal voting period
-    pub begin_review_working_group_leader_applications_proposal_voting_period: u32,
-
-    /// 'Begin review working group leader applications' proposal grace period
-    pub begin_review_working_group_leader_applications_proposal_grace_period: u32,
-
-    /// 'Fill working group leader opening' proposal voting period
-    pub fill_working_group_leader_opening_proposal_voting_period: u32,
-
-    /// 'Fill working group leader opening' proposal grace period
-    pub fill_working_group_leader_opening_proposal_grace_period: u32,
-
-    /// 'Set working group mint capacity' proposal voting period
-    pub set_working_group_mint_capacity_proposal_voting_period: u32,
-
-    /// 'Set working group mint capacity' proposal grace period
-    pub set_working_group_mint_capacity_proposal_grace_period: u32,
-
-    /// 'Decrease working group leader stake' proposal voting period
-    pub decrease_working_group_leader_stake_proposal_voting_period: u32,
-
-    /// 'Decrease working group leader stake' proposal grace period
-    pub decrease_working_group_leader_stake_proposal_grace_period: u32,
-
-    /// 'Slash working group leader stake' proposal voting period
-    pub slash_working_group_leader_stake_proposal_voting_period: u32,
-
-    /// 'Slash working group leader stake' proposal grace period
-    pub slash_working_group_leader_stake_proposal_grace_period: u32,
-
-    /// 'Set working group leader reward' proposal voting period
-    pub set_working_group_leader_reward_proposal_voting_period: u32,
-
-    /// 'Set working group leader reward' proposal grace period
-    pub set_working_group_leader_reward_proposal_grace_period: u32,
-
-    /// 'Terminate working group leader role' proposal voting period
-    pub terminate_working_group_leader_role_proposal_voting_period: u32,
-
-    /// 'Terminate working group leader role' proposal grace period
-    pub terminate_working_group_leader_role_proposal_grace_period: u32,
-}
-
-impl Default for ProposalsConfigParameters {
-    fn default() -> Self {
-        ProposalsConfigParameters {
-            set_validator_count_proposal_voting_period: 43200u32,
-            set_validator_count_proposal_grace_period: 0u32,
-            runtime_upgrade_proposal_voting_period: 72000u32,
-            runtime_upgrade_proposal_grace_period: 72000u32,
-            text_proposal_voting_period: 72000u32,
-            text_proposal_grace_period: 0u32,
-            set_election_parameters_proposal_voting_period: 72000u32,
-            set_election_parameters_proposal_grace_period: 201_601_u32,
-            set_lead_proposal_voting_period: 43200u32,
-            set_lead_proposal_grace_period: 0u32,
-            spending_proposal_voting_period: 72000u32,
-            spending_proposal_grace_period: 14400u32,
-            add_working_group_opening_proposal_voting_period: 72000u32,
-            add_working_group_opening_proposal_grace_period: 0u32,
-            begin_review_working_group_leader_applications_proposal_voting_period: 43200u32,
-            begin_review_working_group_leader_applications_proposal_grace_period: 14400u32,
-            fill_working_group_leader_opening_proposal_voting_period: 43200u32,
-            fill_working_group_leader_opening_proposal_grace_period: 0u32,
-            set_working_group_mint_capacity_proposal_voting_period: 43200u32,
-            set_working_group_mint_capacity_proposal_grace_period: 0u32,
-            decrease_working_group_leader_stake_proposal_voting_period: 43200u32,
-            decrease_working_group_leader_stake_proposal_grace_period: 0u32,
-            slash_working_group_leader_stake_proposal_voting_period: 43200u32,
-            slash_working_group_leader_stake_proposal_grace_period: 0u32,
-            set_working_group_leader_reward_proposal_voting_period: 43200u32,
-            set_working_group_leader_reward_proposal_grace_period: 0u32,
-            terminate_working_group_leader_role_proposal_voting_period: 72200u32,
-            terminate_working_group_leader_role_proposal_grace_period: 0u32,
-        }
-    }
-}
-
-impl ProposalsConfigParameters {
-    /// Set same voting_period for all proposals. For proposals
-    /// that by default have 0 grace period remain with 0 grace period.
-    /// All remaining proposals get assigned grace_period.
-    pub fn with_grace_and_voting_periods(grace_period: u32, voting_period: u32) -> Self {
-        ProposalsConfigParameters {
-            set_validator_count_proposal_voting_period: voting_period,
-            set_validator_count_proposal_grace_period: 0,
-            runtime_upgrade_proposal_voting_period: voting_period,
-            runtime_upgrade_proposal_grace_period: grace_period,
-            text_proposal_voting_period: voting_period,
-            text_proposal_grace_period: 0,
-            set_election_parameters_proposal_voting_period: voting_period,
-            set_election_parameters_proposal_grace_period: grace_period,
-            set_lead_proposal_voting_period: voting_period,
-            set_lead_proposal_grace_period: 0,
-            spending_proposal_voting_period: voting_period,
-            spending_proposal_grace_period: grace_period,
-            add_working_group_opening_proposal_voting_period: voting_period,
-            add_working_group_opening_proposal_grace_period: 0,
-            begin_review_working_group_leader_applications_proposal_voting_period: voting_period,
-            begin_review_working_group_leader_applications_proposal_grace_period: grace_period,
-            fill_working_group_leader_opening_proposal_voting_period: voting_period,
-            fill_working_group_leader_opening_proposal_grace_period: 0,
-            set_working_group_mint_capacity_proposal_voting_period: voting_period,
-            set_working_group_mint_capacity_proposal_grace_period: 0,
-            decrease_working_group_leader_stake_proposal_voting_period: voting_period,
-            decrease_working_group_leader_stake_proposal_grace_period: 0,
-            slash_working_group_leader_stake_proposal_voting_period: voting_period,
-            slash_working_group_leader_stake_proposal_grace_period: 0,
-            set_working_group_leader_reward_proposal_voting_period: voting_period,
-            set_working_group_leader_reward_proposal_grace_period: 0,
-            terminate_working_group_leader_role_proposal_voting_period: voting_period,
-            terminate_working_group_leader_role_proposal_grace_period: 0,
-        }
-    }
-}

+ 0 - 184
runtime-modules/proposals/codex/src/proposal_types/parameters.rs

@@ -1,184 +0,0 @@
-use crate::{BalanceOf, Module, ProposalParameters};
-
-// Proposal parameters for the 'Set validator count' proposal
-pub(crate) fn set_validator_count_proposal<T: crate::Trait>(
-) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
-    ProposalParameters {
-        voting_period: <Module<T>>::set_validator_count_proposal_voting_period(),
-        grace_period: <Module<T>>::set_validator_count_proposal_grace_period(),
-        approval_quorum_percentage: 66,
-        approval_threshold_percentage: 80,
-        slashing_quorum_percentage: 60,
-        slashing_threshold_percentage: 80,
-        required_stake: Some(<BalanceOf<T>>::from(100_000_u32)),
-    }
-}
-
-// Proposal parameters for the upgrade runtime proposal
-pub(crate) fn runtime_upgrade_proposal<T: crate::Trait>(
-) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
-    ProposalParameters {
-        voting_period: <Module<T>>::runtime_upgrade_proposal_voting_period(),
-        grace_period: <Module<T>>::runtime_upgrade_proposal_grace_period(),
-        approval_quorum_percentage: 80,
-        approval_threshold_percentage: 100,
-        slashing_quorum_percentage: 60,
-        slashing_threshold_percentage: 80,
-        required_stake: Some(<BalanceOf<T>>::from(1_000_000_u32)),
-    }
-}
-
-// Proposal parameters for the text proposal
-pub(crate) fn text_proposal<T: crate::Trait>() -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
-    ProposalParameters {
-        voting_period: <Module<T>>::text_proposal_voting_period(),
-        grace_period: <Module<T>>::text_proposal_grace_period(),
-        approval_quorum_percentage: 60,
-        approval_threshold_percentage: 80,
-        slashing_quorum_percentage: 60,
-        slashing_threshold_percentage: 80,
-        required_stake: Some(<BalanceOf<T>>::from(25000u32)),
-    }
-}
-
-// Proposal parameters for the 'Set Election Parameters' proposal
-pub(crate) fn set_election_parameters_proposal<T: crate::Trait>(
-) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
-    ProposalParameters {
-        voting_period: <Module<T>>::set_election_parameters_proposal_voting_period(),
-        grace_period: <Module<T>>::set_election_parameters_proposal_grace_period(),
-        approval_quorum_percentage: 66,
-        approval_threshold_percentage: 80,
-        slashing_quorum_percentage: 60,
-        slashing_threshold_percentage: 80,
-        required_stake: Some(<BalanceOf<T>>::from(200_000_u32)),
-    }
-}
-
-// Proposal parameters for the 'Spending' proposal
-pub(crate) fn spending_proposal<T: crate::Trait>(
-) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
-    ProposalParameters {
-        voting_period: <Module<T>>::spending_proposal_voting_period(),
-        grace_period: <Module<T>>::spending_proposal_grace_period(),
-        approval_quorum_percentage: 60,
-        approval_threshold_percentage: 80,
-        slashing_quorum_percentage: 60,
-        slashing_threshold_percentage: 80,
-        required_stake: Some(<BalanceOf<T>>::from(25000u32)),
-    }
-}
-
-// Proposal parameters for the 'Add working group leader' proposal
-pub(crate) fn add_working_group_leader_opening_proposal<T: crate::Trait>(
-) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
-    ProposalParameters {
-        voting_period: <Module<T>>::add_working_group_opening_proposal_voting_period(),
-        grace_period: <Module<T>>::add_working_group_opening_proposal_grace_period(),
-        approval_quorum_percentage: 60,
-        approval_threshold_percentage: 80,
-        slashing_quorum_percentage: 60,
-        slashing_threshold_percentage: 80,
-        required_stake: Some(<BalanceOf<T>>::from(100_000_u32)),
-    }
-}
-
-// Proposal parameters for the 'Begin review working group leader applications' proposal
-pub(crate) fn begin_review_working_group_leader_applications_proposal<T: crate::Trait>(
-) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
-    ProposalParameters {
-        voting_period:
-            <Module<T>>::begin_review_working_group_leader_applications_proposal_voting_period(),
-        grace_period:
-            <Module<T>>::begin_review_working_group_leader_applications_proposal_grace_period(),
-        approval_quorum_percentage: 60,
-        approval_threshold_percentage: 75,
-        slashing_quorum_percentage: 60,
-        slashing_threshold_percentage: 80,
-        required_stake: Some(<BalanceOf<T>>::from(25000u32)),
-    }
-}
-
-// Proposal parameters for the 'Fill working group leader opening' proposal
-pub(crate) fn fill_working_group_leader_opening_proposal<T: crate::Trait>(
-) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
-    ProposalParameters {
-        voting_period: <Module<T>>::fill_working_group_leader_opening_proposal_voting_period(),
-        grace_period: <Module<T>>::fill_working_group_leader_opening_proposal_grace_period(),
-        approval_quorum_percentage: 60,
-        approval_threshold_percentage: 75,
-        slashing_quorum_percentage: 60,
-        slashing_threshold_percentage: 80,
-        required_stake: Some(<BalanceOf<T>>::from(50000u32)),
-    }
-}
-
-// Proposal parameters for the 'Set working group mint capacity' proposal
-pub(crate) fn set_working_group_mint_capacity_proposal<T: crate::Trait>(
-) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
-    ProposalParameters {
-        voting_period: <Module<T>>::set_working_group_mint_capacity_proposal_voting_period(),
-        grace_period: <Module<T>>::set_working_group_mint_capacity_proposal_grace_period(),
-        approval_quorum_percentage: 60,
-        approval_threshold_percentage: 75,
-        slashing_quorum_percentage: 60,
-        slashing_threshold_percentage: 80,
-        required_stake: Some(<BalanceOf<T>>::from(50000u32)),
-    }
-}
-
-// Proposal parameters for the 'Decrease working group leader stake' proposal
-pub(crate) fn decrease_working_group_leader_stake_proposal<T: crate::Trait>(
-) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
-    ProposalParameters {
-        voting_period: <Module<T>>::decrease_working_group_leader_stake_proposal_voting_period(),
-        grace_period: <Module<T>>::decrease_working_group_leader_stake_proposal_grace_period(),
-        approval_quorum_percentage: 60,
-        approval_threshold_percentage: 75,
-        slashing_quorum_percentage: 60,
-        slashing_threshold_percentage: 80,
-        required_stake: Some(<BalanceOf<T>>::from(50000u32)),
-    }
-}
-
-// Proposal parameters for the 'Slash working group leader stake' proposal
-pub(crate) fn slash_working_group_leader_stake_proposal<T: crate::Trait>(
-) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
-    ProposalParameters {
-        voting_period: <Module<T>>::slash_working_group_leader_stake_proposal_voting_period(),
-        grace_period: <Module<T>>::slash_working_group_leader_stake_proposal_grace_period(),
-        approval_quorum_percentage: 60,
-        approval_threshold_percentage: 75,
-        slashing_quorum_percentage: 60,
-        slashing_threshold_percentage: 80,
-        required_stake: Some(<BalanceOf<T>>::from(50000u32)),
-    }
-}
-
-// Proposal parameters for the 'Set working group leader reward' proposal
-pub(crate) fn set_working_group_leader_reward_proposal<T: crate::Trait>(
-) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
-    ProposalParameters {
-        voting_period: <Module<T>>::set_working_group_leader_reward_proposal_voting_period(),
-        grace_period: <Module<T>>::set_working_group_leader_reward_proposal_grace_period(),
-        approval_quorum_percentage: 60,
-        approval_threshold_percentage: 75,
-        slashing_quorum_percentage: 60,
-        slashing_threshold_percentage: 80,
-        required_stake: Some(<BalanceOf<T>>::from(50000u32)),
-    }
-}
-
-// Proposal parameters for the 'Terminate working group leader role' proposal
-pub(crate) fn terminate_working_group_leader_role_proposal<T: crate::Trait>(
-) -> ProposalParameters<T::BlockNumber, BalanceOf<T>> {
-    ProposalParameters {
-        voting_period: <Module<T>>::terminate_working_group_leader_role_proposal_voting_period(),
-        grace_period: <Module<T>>::terminate_working_group_leader_role_proposal_grace_period(),
-        approval_quorum_percentage: 66,
-        approval_threshold_percentage: 80,
-        slashing_quorum_percentage: 60,
-        slashing_threshold_percentage: 80,
-        required_stake: Some(<BalanceOf<T>>::from(100_000_u32)),
-    }
-}

+ 41 - 9
runtime-modules/proposals/codex/src/tests/mock.rs → runtime-modules/proposals/codex/src/tests/mock/mod.rs

@@ -1,5 +1,6 @@
 #![cfg(test)]
 
+use frame_support::traits::LockIdentifier;
 use frame_support::{impl_outer_dispatch, impl_outer_origin, parameter_types};
 pub use frame_system;
 use sp_core::H256;
@@ -11,10 +12,12 @@ use sp_runtime::{
 };
 use sp_staking::SessionIndex;
 
-use crate::{ProposalDetailsOf, ProposalEncoder};
+use crate::{ProposalDetailsOf, ProposalEncoder, ProposalParameters};
 use proposals_engine::VotersParameters;
 use sp_runtime::testing::TestXt;
 
+mod staking_handler;
+
 impl_outer_origin! {
     pub enum Origin for Test {}
 }
@@ -80,6 +83,7 @@ parameter_types! {
     pub const TitleMaxLength: u32 = 100;
     pub const DescriptionMaxLength: u32 = 10000;
     pub const MaxActiveProposalLimit: u32 = 100;
+    pub const LockId: LockIdentifier = [2; 8];
 }
 
 impl proposals_engine::Trait for Test {
@@ -88,13 +92,14 @@ impl proposals_engine::Trait for Test {
     type VoterOriginValidator = ();
     type TotalVotersCounter = MockVotersParameters;
     type ProposalId = u32;
-    type StakeHandlerProvider = proposals_engine::DefaultStakeHandlerProvider;
+    type StakingHandler = staking_handler::StakingManager<Test, LockId>;
     type CancellationFee = CancellationFee;
     type RejectionFee = RejectionFee;
     type TitleMaxLength = TitleMaxLength;
     type DescriptionMaxLength = DescriptionMaxLength;
     type MaxActiveProposalLimit = MaxActiveProposalLimit;
     type DispatchableCallCode = crate::Call<Test>;
+    type ProposalObserver = crate::Module<Test>;
 }
 
 impl Default for crate::Call<Test> {
@@ -122,21 +127,18 @@ impl common::origin::ActorOriginValidator<Origin, u64, u64> for () {
 }
 
 parameter_types! {
-    pub const MaxPostEditionNumber: u32 = 5;
-    pub const MaxThreadInARowNumber: u32 = 3;
     pub const ThreadTitleLengthLimit: u32 = 200;
     pub const PostLengthLimit: u32 = 2000;
+    pub const MaxWhiteListSize: u32 = 20;
 }
 
 impl proposals_discussion::Trait for Test {
     type Event = ();
-    type PostAuthorOriginValidator = ();
+    type AuthorOriginValidator = ();
+    type CouncilOriginValidator = ();
     type ThreadId = u64;
     type PostId = u64;
-    type MaxPostEditionNumber = MaxPostEditionNumber;
-    type ThreadTitleLengthLimit = ThreadTitleLengthLimit;
-    type PostLengthLimit = PostLengthLimit;
-    type MaxThreadInARowNumber = MaxThreadInARowNumber;
+    type MaxWhiteListSize = MaxWhiteListSize;
 }
 
 pub struct MockVotersParameters;
@@ -253,11 +255,41 @@ impl staking::SessionInterface<u64> for Test {
     }
 }
 
+parameter_types! {
+    pub DefaultProposalParameters: ProposalParameters<u64, u64> = default_proposal_parameters();
+}
+
+pub(crate) fn default_proposal_parameters() -> ProposalParameters<u64, u64> {
+    ProposalParameters {
+        voting_period: 43200,
+        grace_period: 0,
+        approval_quorum_percentage: 66,
+        approval_threshold_percentage: 80,
+        slashing_quorum_percentage: 60,
+        slashing_threshold_percentage: 80,
+        required_stake: Some(100_000),
+        constitutionality: 1,
+    }
+}
+
 impl crate::Trait for Test {
     type TextProposalMaxLength = TextProposalMaxLength;
     type RuntimeUpgradeWasmProposalMaxLength = RuntimeUpgradeWasmProposalMaxLength;
     type MembershipOriginValidator = ();
     type ProposalEncoder = ();
+    type SetValidatorCountProposalParameters = DefaultProposalParameters;
+    type RuntimeUpgradeProposalParameters = DefaultProposalParameters;
+    type TextProposalParameters = DefaultProposalParameters;
+    type SpendingProposalParameters = DefaultProposalParameters;
+    type AddWorkingGroupOpeningProposalParameters = DefaultProposalParameters;
+    type BeginReviewWorkingGroupApplicationsProposalParameters = DefaultProposalParameters;
+    type FillWorkingGroupOpeningProposalParameters = DefaultProposalParameters;
+    type SetWorkingGroupMintCapacityProposalParameters = DefaultProposalParameters;
+    type DecreaseWorkingGroupLeaderStakeProposalParameters = DefaultProposalParameters;
+    type SlashWorkingGroupLeaderStakeProposalParameters = DefaultProposalParameters;
+    type SetWorkingGroupLeaderRewardProposalParameters = DefaultProposalParameters;
+    type TerminateWorkingGroupLeaderRoleProposalParameters = DefaultProposalParameters;
+    type AmendConstitutionProposalParameters = DefaultProposalParameters;
 }
 
 impl ProposalEncoder<Test> for () {

+ 98 - 0
runtime-modules/proposals/codex/src/tests/mock/staking_handler.rs

@@ -0,0 +1,98 @@
+use frame_support::dispatch::{DispatchError, DispatchResult};
+use frame_support::traits::{Currency, Get, LockIdentifier, LockableCurrency, WithdrawReasons};
+use membership::staking_handler::{BalanceOf, MemberId, StakingHandler};
+use sp_arithmetic::traits::Zero;
+use sp_std::marker::PhantomData;
+
+/// Implementation of the StakingHandler.
+pub struct StakingManager<
+    T: frame_system::Trait + membership::Trait + balances::Trait,
+    LockId: Get<LockIdentifier>,
+> {
+    trait_marker: PhantomData<T>,
+    lock_id_marker: PhantomData<LockId>,
+}
+
+impl<T: frame_system::Trait + membership::Trait + balances::Trait, LockId: Get<LockIdentifier>>
+    StakingHandler<T> for StakingManager<T, LockId>
+{
+    fn lock(account_id: &T::AccountId, amount: BalanceOf<T>) {
+        <balances::Module<T>>::set_lock(LockId::get(), &account_id, amount, WithdrawReasons::all())
+    }
+
+    fn unlock(account_id: &T::AccountId) {
+        T::Currency::remove_lock(LockId::get(), &account_id);
+    }
+
+    fn slash(account_id: &T::AccountId, amount: Option<BalanceOf<T>>) -> BalanceOf<T> {
+        let locks = <balances::Module<T>>::locks(&account_id);
+
+        let existing_lock = locks.iter().find(|lock| lock.id == LockId::get());
+
+        let mut actually_slashed_balance = Default::default();
+        if let Some(existing_lock) = existing_lock {
+            Self::unlock(&account_id);
+
+            let mut slashable_amount = existing_lock.amount;
+            if let Some(amount) = amount {
+                if existing_lock.amount > amount {
+                    let new_amount = existing_lock.amount - amount;
+                    Self::lock(&account_id, new_amount);
+
+                    slashable_amount = amount;
+                }
+            }
+
+            let _ = <balances::Module<T>>::slash(&account_id, slashable_amount);
+
+            actually_slashed_balance = slashable_amount
+        }
+
+        actually_slashed_balance
+    }
+
+    fn set_stake(account_id: &T::AccountId, new_stake: BalanceOf<T>) -> DispatchResult {
+        let current_stake = Self::current_stake(account_id);
+
+        //Unlock previous stake if its not zero.
+        if current_stake > Zero::zero() {
+            Self::unlock(account_id);
+        }
+
+        if !Self::is_enough_balance_for_stake(account_id, new_stake) {
+            //Restore previous stake if its not zero.
+            if current_stake > Zero::zero() {
+                Self::lock(account_id, current_stake);
+            }
+            return Err(DispatchError::Other("Not enough balance for a new stake."));
+        }
+
+        Self::lock(account_id, new_stake);
+
+        Ok(())
+    }
+
+    fn is_member_staking_account(_member_id: &MemberId<T>, _account_id: &T::AccountId) -> bool {
+        true
+    }
+
+    fn is_account_free_of_conflicting_stakes(account_id: &T::AccountId) -> bool {
+        let locks = <balances::Module<T>>::locks(&account_id);
+
+        let existing_lock = locks.iter().find(|lock| lock.id == LockId::get());
+
+        existing_lock.is_none()
+    }
+
+    fn is_enough_balance_for_stake(account_id: &T::AccountId, amount: BalanceOf<T>) -> bool {
+        <balances::Module<T>>::usable_balance(account_id) >= amount
+    }
+
+    fn current_stake(account_id: &T::AccountId) -> BalanceOf<T> {
+        let locks = <balances::Module<T>>::locks(&account_id);
+
+        let existing_lock = locks.iter().find(|lock| lock.id == LockId::get());
+
+        existing_lock.map_or(Zero::zero(), |lock| lock.amount)
+    }
+}

Разлика између датотеке није приказан због своје велике величине
+ 88 - 507
runtime-modules/proposals/codex/src/tests/mod.rs


+ 3 - 1
runtime-modules/proposals/discussion/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = 'pallet-proposals-discussion'
-version = '3.1.0'
+version = '4.0.0'
 authors = ['Joystream contributors']
 edition = '2018'
 
@@ -12,6 +12,7 @@ frame-support = { package = 'frame-support', default-features = false, git = 'ht
 frame-system = { package = 'frame-system', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 membership = { package = 'pallet-membership', default-features = false, path = '../../membership'}
 common = { package = 'pallet-common', default-features = false, path = '../../common'}
+frame-benchmarking = { package = 'frame-benchmarking', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca', optional = true}
 
 [dev-dependencies]
 sp-io = { package = 'sp-io', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
@@ -22,6 +23,7 @@ balances = { package = 'pallet-balances', default-features = false, git = 'https
 
 [features]
 default = ['std']
+runtime-benchmarks = ['frame-benchmarking']
 std = [
 	'serde',
 	'codec/std',

+ 222 - 0
runtime-modules/proposals/discussion/src/benchmarking.rs

@@ -0,0 +1,222 @@
+#![cfg(feature = "runtime-benchmarks")]
+use super::*;
+use crate::Module as ProposalsDiscussion;
+use core::convert::TryInto;
+use frame_benchmarking::{account, benchmarks};
+use membership::Module as Membership;
+use sp_std::cmp::min;
+use sp_std::prelude::*;
+use system as frame_system;
+use system::EventRecord;
+use system::Module as System;
+use system::RawOrigin;
+
+const SEED: u32 = 0;
+
+fn get_byte(num: u32, byte_number: u8) -> u8 {
+    ((num & (0xff << (8 * byte_number))) >> 8 * byte_number) as u8
+}
+
+// Method to generate a distintic valid handle
+// for a membership. For each index.
+fn handle_from_id<T: membership::Trait>(id: u32) -> Vec<u8> {
+    let min_handle_length = Membership::<T>::min_handle_length();
+
+    let mut handle = vec![];
+
+    for i in 0..min(Membership::<T>::max_handle_length().try_into().unwrap(), 4) {
+        handle.push(get_byte(id, i));
+    }
+
+    while handle.len() < (min_handle_length as usize) {
+        handle.push(0u8);
+    }
+
+    handle
+}
+
+fn assert_last_event<T: Trait>(generic_event: <T as Trait>::Event) {
+    let events = System::<T>::events();
+    let system_event: <T as frame_system::Trait>::Event = generic_event.into();
+    // compare to the last event record
+    let EventRecord { event, .. } = &events[events.len() - 1];
+    assert_eq!(event, &system_event);
+}
+
+fn member_account<T: membership::Trait>(
+    name: &'static str,
+    id: u32,
+) -> (T::AccountId, T::MemberId) {
+    let account_id = account::<T::AccountId>(name, id, SEED);
+    let handle = handle_from_id::<T>(id);
+
+    let authority_account = account::<T::AccountId>(name, 0, SEED);
+
+    Membership::<T>::set_screening_authority(RawOrigin::Root.into(), authority_account.clone())
+        .unwrap();
+
+    Membership::<T>::add_screened_member(
+        RawOrigin::Signed(authority_account.clone()).into(),
+        account_id.clone(),
+        Some(handle),
+        None,
+        None,
+    )
+    .unwrap();
+
+    (account_id, T::MemberId::from(id.try_into().unwrap()))
+}
+
+const MAX_BYTES: u32 = 16384;
+
+benchmarks! {
+    _ { }
+
+    add_post {
+        let i in 1 .. T::MaxWhiteListSize::get();
+
+        let j in 0 .. MAX_BYTES;
+
+        // We do this to ignore the id 0 because the `Test` runtime
+        // returns 0 as an invalid id but 1 as a valid one
+        let (_, _) = member_account::<T>("member", 0);
+        let (account_id, caller_member_id) = member_account::<T>("caller_member", 1);
+
+        let mut whitelisted_members = vec![caller_member_id];
+
+        // We start from 2 since we have previously created id 0 and not used it
+        // and used id 1 for the caller (see comment above)
+        for id in 2 .. i + 1 {
+            let (_, member_id) = member_account::<T>("member", id);
+            whitelisted_members.push(member_id);
+        }
+
+        let thread_id = ProposalsDiscussion::<T>::create_thread(
+            caller_member_id,
+            ThreadMode::Closed(whitelisted_members)
+        ).unwrap();
+
+        assert!(ThreadById::<T>::contains_key(thread_id), "Thread not created");
+
+        let text = vec![0u8; j.try_into().unwrap()];
+
+    }: _ (RawOrigin::Signed(account_id), caller_member_id, thread_id, text)
+    verify {
+        let post_id = T::PostId::from(1);
+
+        assert!(PostThreadIdByPostId::<T>::contains_key(thread_id, post_id), "Post not created");
+        assert_eq!(
+            PostThreadIdByPostId::<T>::get(thread_id, post_id).author_id,
+            caller_member_id,
+            "Post author isn't correct"
+        );
+
+        assert_last_event::<T>(RawEvent::PostCreated(post_id, caller_member_id).into());
+    }
+
+    update_post {
+        // TODO: this parameter doesn't affect the running time
+        // maybe we should bound it here with the UI limit?
+        let j in 0 .. MAX_BYTES;
+
+        // We do this to ignore the id 0 because the `Test` runtime
+        // returns 0 as an invalid id but 1 as a valid one
+        let (_, _) = member_account::<T>("caller_member", 0);
+        let (account_id, caller_member_id) = member_account::<T>("caller_member", 1);
+
+        let thread_id = ProposalsDiscussion::<T>::create_thread(
+            caller_member_id,
+            ThreadMode::Open
+        ).unwrap();
+
+        assert!(ThreadById::<T>::contains_key(thread_id), "Thread not created");
+
+        ProposalsDiscussion::<T>::add_post(
+            RawOrigin::Signed(account_id.clone()).into(),
+            caller_member_id,
+            thread_id,
+            vec![0u8]
+        ).unwrap();
+
+        let post_id = T::PostId::from(1);
+
+        assert!(PostThreadIdByPostId::<T>::contains_key(thread_id, post_id), "Post not created");
+
+        let new_text = vec![0u8; j.try_into().unwrap()];
+    }: _ (RawOrigin::Signed(account_id), caller_member_id, thread_id, post_id, new_text)
+    verify {
+        assert_last_event::<T>(RawEvent::PostUpdated(post_id, caller_member_id).into());
+    }
+
+    // TODO: Review this after changes to the governance/council are merged:
+    // this extrinsic uses `T::CouncilOriginValidator::ensure_actor_origin`
+    // this is a hook to the runtime. Since the pallet implementation shouldn't have any
+    // information on the runtime this hooks should be constant.
+    // However, the implementation in the runtime is linear in the number of council members.
+    // But since the size of the council should be completely filled over time we could
+    // always use the worst case scenario, still this would require to create an artificial
+    // dependency with the `governance` pallet to correctly benchmark this.
+    change_thread_mode {
+        let i in 1 .. T::MaxWhiteListSize::get();
+
+        // We do this to ignore the id 0 because the `Test` runtime
+        // returns 0 as an invalid id but 1 as a valid one
+        let (_, _) = member_account::<T>("member", 0);
+        let (account_id, caller_member_id) = member_account::<T>("caller_member", 1);
+
+        let thread_id = ProposalsDiscussion::<T>::create_thread(
+            caller_member_id,
+            ThreadMode::Open
+        ).unwrap();
+
+        assert!(ThreadById::<T>::contains_key(thread_id), "Thread not created");
+
+        let mut whitelisted_members = vec![caller_member_id];
+
+        // We start from 2 since we have previously created id 0 and not used it
+        // and used id 1 for the caller (see comment above)
+        for id in 2 .. i + 1 {
+            let (_, member_id) = member_account::<T>("member", id);
+            whitelisted_members.push(member_id);
+        }
+
+        let mode = ThreadMode::Closed(whitelisted_members);
+    }: _ (RawOrigin::Signed(account_id), caller_member_id, thread_id, mode.clone())
+    verify {
+        assert_eq!(
+            ProposalsDiscussion::<T>::thread_by_id(thread_id).mode,
+            mode.clone(),
+            "Thread not correctly updated"
+        );
+
+        assert_last_event::<T>(RawEvent::ThreadModeChanged(thread_id, mode).into());
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::tests::{initial_test_ext, Test};
+    use frame_support::assert_ok;
+
+    #[test]
+    fn test_add_post() {
+        initial_test_ext().execute_with(|| {
+            assert_ok!(test_benchmark_add_post::<Test>());
+        });
+    }
+
+    #[test]
+    fn test_update_post() {
+        initial_test_ext().execute_with(|| {
+            assert_ok!(test_benchmark_update_post::<Test>());
+        });
+    }
+
+    #[test]
+    fn test_change_thread_mode() {
+        initial_test_ext().execute_with(|| {
+            assert_ok!(test_benchmark_change_thread_mode::<Test>());
+        });
+    }
+}

+ 115 - 122
runtime-modules/proposals/discussion/src/lib.rs

@@ -1,5 +1,5 @@
 //! # Proposals discussion module
-//! Proposals `discussion` module for the Joystream platform. Version 2.
+//! Proposals `discussion` module for the Joystream platform. Version 3.
 //! It contains discussion subsystem of the proposals.
 //!
 //! ## Overview
@@ -11,6 +11,7 @@
 //! ## Supported extrinsics
 //! - [add_post](./struct.Module.html#method.add_post) - adds a post to an existing discussion thread
 //! - [update_post](./struct.Module.html#method.update_post) - updates existing post
+//! - [change_thread_mode](./struct.Module.html#method.change_thread_mode) - changes thread permission mode
 //!
 //! ## Public API methods
 //! - [create_thread](./struct.Module.html#method.create_thread) - creates a discussion thread
@@ -21,7 +22,7 @@
 //! ```
 //! use frame_support::decl_module;
 //! use frame_system::ensure_root;
-//! use pallet_proposals_discussion::{self as discussions};
+//! use pallet_proposals_discussion::{self as discussions, ThreadMode};
 //!
 //! pub trait Trait: discussions::Trait + membership::Trait {}
 //!
@@ -30,8 +31,9 @@
 //!         #[weight = 10_000_000]
 //!         pub fn create_discussion(origin, title: Vec<u8>, author_id : T::MemberId) {
 //!             ensure_root(origin)?;
-//!             <discussions::Module<T>>::ensure_can_create_thread(author_id, &title)?;
-//!             <discussions::Module<T>>::create_thread(author_id, title)?;
+//!             let thread_mode = ThreadMode::Open;
+//!             <discussions::Module<T>>::ensure_can_create_thread(&thread_mode)?;
+//!             <discussions::Module<T>>::create_thread(author_id, thread_mode)?;
 //!         }
 //!     }
 //! }
@@ -44,18 +46,22 @@
 // Do not delete! Cannot be uncommented by default, because of Parity decl_module! issue.
 //#![warn(missing_docs)]
 
+mod benchmarking;
 #[cfg(test)]
 mod tests;
 mod types;
 
 use frame_support::dispatch::{DispatchError, DispatchResult};
+use frame_support::sp_runtime::SaturatedConversion;
 use frame_support::traits::Get;
 use frame_support::{decl_error, decl_event, decl_module, decl_storage, ensure, Parameter};
 use sp_std::clone::Clone;
 use sp_std::vec::Vec;
 
 use common::origin::ActorOriginValidator;
-use types::{DiscussionPost, DiscussionThread, ThreadCounter};
+use types::{DiscussionPost, DiscussionThread};
+
+pub use types::ThreadMode;
 
 type MemberId<T> = <T as membership::Trait>::MemberId;
 
@@ -75,20 +81,28 @@ decl_event!(
 
         /// Emits on post update.
         PostUpdated(PostId, MemberId),
+
+        /// Emits on thread mode change.
+        ThreadModeChanged(ThreadId, ThreadMode<MemberId>),
     }
 );
 
+/// Defines whether the member is an active councilor.
+pub trait CouncilMembership<AccountId, MemberId> {
+    /// Defines whether the member is an active councilor.
+    fn is_council_member(account_id: &AccountId, member_id: &MemberId) -> bool;
+}
+
 /// 'Proposal discussion' substrate module Trait
 pub trait Trait: frame_system::Trait + membership::Trait {
     /// Discussion event type.
     type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
 
     /// Validates post author id and origin combination
-    type PostAuthorOriginValidator: ActorOriginValidator<
-        Self::Origin,
-        MemberId<Self>,
-        Self::AccountId,
-    >;
+    type AuthorOriginValidator: ActorOriginValidator<Self::Origin, MemberId<Self>, Self::AccountId>;
+
+    /// Defines whether the member is an active councilor.
+    type CouncilOriginValidator: ActorOriginValidator<Self::Origin, MemberId<Self>, Self::AccountId>;
 
     /// Discussion thread Id type
     type ThreadId: From<u64> + Into<u64> + Parameter + Default + Copy;
@@ -96,17 +110,8 @@ pub trait Trait: frame_system::Trait + membership::Trait {
     /// Post Id type
     type PostId: From<u64> + Parameter + Default + Copy;
 
-    /// Defines post edition number limit.
-    type MaxPostEditionNumber: Get<u32>;
-
-    /// Defines thread title length limit.
-    type ThreadTitleLengthLimit: Get<u32>;
-
-    /// Defines post length limit.
-    type PostLengthLimit: Get<u32>;
-
-    /// Defines max thread by same author in a row number limit.
-    type MaxThreadInARowNumber: Get<u32>;
+    /// Defines author list size limit for the Closed discussion.
+    type MaxWhiteListSize: Get<u32>;
 }
 
 decl_error! {
@@ -115,32 +120,23 @@ decl_error! {
         /// Author should match the post creator
         NotAuthor,
 
-        ///  Post edition limit reached
-        PostEditionNumberExceeded,
-
-        /// Discussion cannot have an empty title
-        EmptyTitleProvided,
-
-        /// Title is too long
-        TitleIsTooLong,
-
         /// Thread doesn't exist
         ThreadDoesntExist,
 
         /// Post doesn't exist
         PostDoesntExist,
 
-        /// Post cannot be empty
-        EmptyPostProvided,
+        /// Require root origin in extrinsics
+        RequireRootOrigin,
 
-        /// Post is too long
-        PostIsTooLong,
+        /// The thread has Closed mode. And post author doesn't belong to council or allowed members.
+        CannotPostOnClosedThread,
 
-        /// Max number of threads by same author in a row limit exceeded
-        MaxThreadInARowLimitExceeded,
+        /// Should be thread author or councilor.
+        NotAuthorOrCouncilor,
 
-        /// Require root origin in extrinsics
-        RequireRootOrigin,
+        /// Max allowed authors list limit exceeded.
+        MaxWhiteListSizeExceeded,
     }
 }
 
@@ -149,7 +145,7 @@ decl_storage! {
     pub trait Store for Module<T: Trait> as ProposalDiscussion {
         /// Map thread identifier to corresponding thread.
         pub ThreadById get(fn thread_by_id): map hasher(blake2_128_concat)
-            T::ThreadId => DiscussionThread<MemberId<T>, T::BlockNumber>;
+            T::ThreadId => DiscussionThread<MemberId<T>, T::BlockNumber, MemberId<T>>;
 
         /// Count of all threads that have been created.
         pub ThreadCount get(fn thread_count): u64;
@@ -157,14 +153,10 @@ decl_storage! {
         /// Map thread id and post id to corresponding post.
         pub PostThreadIdByPostId:
             double_map hasher(blake2_128_concat) T::ThreadId, hasher(blake2_128_concat) T::PostId =>
-                DiscussionPost<MemberId<T>, T::BlockNumber, T::ThreadId>;
+                DiscussionPost<MemberId<T>>;
 
         /// Count of all posts that have been created.
         pub PostCount get(fn post_count): u64;
-
-        /// Last author thread counter (part of the antispam mechanism)
-        pub LastThreadAuthorCounter get(fn last_thread_author_counter):
-            Option<ThreadCounter<MemberId<T>>>;
     }
 }
 
@@ -177,37 +169,22 @@ decl_module! {
         /// Emits an event. Default substrate implementation.
         fn deposit_event() = default;
 
-        /// Exports post edition number limit const.
-        const MaxPostEditionNumber: u32 = T::MaxPostEditionNumber::get();
-
-        /// Exports thread title length limit const.
-        const ThreadTitleLengthLimit: u32 = T::ThreadTitleLengthLimit::get();
-
-        /// Exports post length limit const.
-        const PostLengthLimit: u32 = T::PostLengthLimit::get();
-
-        /// Exports max thread by same author in a row number limit const.
-        const MaxThreadInARowNumber: u32 = T::MaxThreadInARowNumber::get();
-
         /// Adds a post with author origin check.
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn add_post(
             origin,
             post_author_id: MemberId<T>,
             thread_id : T::ThreadId,
-            text : Vec<u8>
+            _text : Vec<u8>
         ) {
-            T::PostAuthorOriginValidator::ensure_actor_origin(
-                origin,
+            T::AuthorOriginValidator::ensure_actor_origin(
+                origin.clone(),
                 post_author_id,
             )?;
+
             ensure!(<ThreadById<T>>::contains_key(thread_id), Error::<T>::ThreadDoesntExist);
 
-            ensure!(!text.is_empty(),Error::<T>::EmptyPostProvided);
-            ensure!(
-                text.len() as u32 <= T::PostLengthLimit::get(),
-                Error::<T>::PostIsTooLong
-            );
+            Self::ensure_thread_mode(origin, post_author_id, thread_id)?;
 
             // mutation
 
@@ -215,12 +192,7 @@ decl_module! {
             let new_post_id = next_post_count_value;
 
             let new_post = DiscussionPost {
-                text,
-                created_at: Self::current_block(),
-                updated_at: Self::current_block(),
                 author_id: post_author_id,
-                edition_number : 0,
-                thread_id,
             };
 
             let post_id = T::PostId::from(new_post_id);
@@ -236,9 +208,9 @@ decl_module! {
             post_author_id: MemberId<T>,
             thread_id: T::ThreadId,
             post_id : T::PostId,
-            text : Vec<u8>
+            _text : Vec<u8>
         ){
-            T::PostAuthorOriginValidator::ensure_actor_origin(
+            T::AuthorOriginValidator::ensure_actor_origin(
                 origin,
                 post_author_id,
             )?;
@@ -246,60 +218,76 @@ decl_module! {
             ensure!(<ThreadById<T>>::contains_key(thread_id), Error::<T>::ThreadDoesntExist);
             ensure!(<PostThreadIdByPostId<T>>::contains_key(thread_id, post_id), Error::<T>::PostDoesntExist);
 
-            ensure!(!text.is_empty(), Error::<T>::EmptyPostProvided);
-            ensure!(
-                text.len() as u32 <= T::PostLengthLimit::get(),
-                Error::<T>::PostIsTooLong
-            );
-
             let post = <PostThreadIdByPostId<T>>::get(&thread_id, &post_id);
 
             ensure!(post.author_id == post_author_id, Error::<T>::NotAuthor);
-            ensure!(post.edition_number < T::MaxPostEditionNumber::get(),
-                Error::<T>::PostEditionNumberExceeded);
-
-            let new_post = DiscussionPost {
-                text,
-                updated_at: Self::current_block(),
-                edition_number: post.edition_number + 1,
-                ..post
-            };
 
             // mutation
 
-            <PostThreadIdByPostId<T>>::insert(thread_id, post_id, new_post);
             Self::deposit_event(RawEvent::PostUpdated(post_id, post_author_id));
        }
+
+        /// Changes thread permission mode.
+        #[weight = 10_000_000] // TODO: adjust weight
+        pub fn change_thread_mode(
+            origin,
+            member_id: MemberId<T>,
+            thread_id : T::ThreadId,
+            mode : ThreadMode<MemberId<T>>
+        ) {
+            T::AuthorOriginValidator::ensure_actor_origin(origin.clone(), member_id)?;
+
+            ensure!(<ThreadById<T>>::contains_key(thread_id), Error::<T>::ThreadDoesntExist);
+
+            if let ThreadMode::Closed(ref list) = mode{
+                ensure!(
+                    list.len() <= (T::MaxWhiteListSize::get()).saturated_into(),
+                    Error::<T>::MaxWhiteListSizeExceeded
+                );
+            }
+
+            let thread = Self::thread_by_id(&thread_id);
+
+            let is_councilor =
+                    T::CouncilOriginValidator::ensure_actor_origin(origin, member_id)
+                        .is_ok();
+            let is_thread_author = thread.author_id == member_id;
+
+            ensure!(is_thread_author || is_councilor, Error::<T>::NotAuthorOrCouncilor);
+
+            // mutation
+
+            <ThreadById<T>>::mutate(thread_id, |thread| {
+                thread.mode = mode.clone();
+            });
+            Self::deposit_event(RawEvent::ThreadModeChanged(thread_id, mode));
+       }
     }
 }
 
 impl<T: Trait> Module<T> {
-    /// Create the discussion thread. Cannot add more threads than 'predefined limit = MaxThreadInARowNumber'
+    /// Create the discussion thread.
     /// times in a row by the same author.
     pub fn create_thread(
         thread_author_id: MemberId<T>,
-        title: Vec<u8>,
+        mode: ThreadMode<MemberId<T>>,
     ) -> Result<T::ThreadId, DispatchError> {
-        Self::ensure_can_create_thread(thread_author_id, &title)?;
+        Self::ensure_can_create_thread(&mode)?;
 
         let next_thread_count_value = Self::thread_count() + 1;
         let new_thread_id = next_thread_count_value;
 
         let new_thread = DiscussionThread {
-            title,
-            created_at: Self::current_block(),
+            activated_at: Self::current_block(),
             author_id: thread_author_id,
+            mode,
         };
 
-        // get new 'threads in a row' counter for the author
-        let current_thread_counter = Self::get_updated_thread_counter(thread_author_id);
-
         // mutation
 
         let thread_id = T::ThreadId::from(new_thread_id);
         <ThreadById<T>>::insert(thread_id, new_thread);
         ThreadCount::put(next_thread_count_value);
-        <LastThreadAuthorCounter<T>>::put(current_thread_counter);
         Self::deposit_event(RawEvent::ThreadCreated(thread_id, thread_author_id));
 
         Ok(thread_id)
@@ -307,22 +295,14 @@ impl<T: Trait> Module<T> {
 
     /// Ensures thread can be created.
     /// Checks:
-    /// - title is valid
-    /// - max thread in a row by the same author
-    pub fn ensure_can_create_thread(thread_author_id: MemberId<T>, title: &[u8]) -> DispatchResult {
-        ensure!(!title.is_empty(), Error::<T>::EmptyTitleProvided);
-        ensure!(
-            title.len() as u32 <= T::ThreadTitleLengthLimit::get(),
-            Error::<T>::TitleIsTooLong
-        );
-
-        // get new 'threads in a row' counter for the author
-        let current_thread_counter = Self::get_updated_thread_counter(thread_author_id);
-
-        ensure!(
-            current_thread_counter.counter as u32 <= T::MaxThreadInARowNumber::get(),
-            Error::<T>::MaxThreadInARowLimitExceeded
-        );
+    /// - max allowed authors for the Closed thread mode
+    pub fn ensure_can_create_thread(mode: &ThreadMode<MemberId<T>>) -> DispatchResult {
+        if let ThreadMode::Closed(list) = mode {
+            ensure!(
+                list.len() <= (T::MaxWhiteListSize::get()).saturated_into(),
+                Error::<T>::MaxWhiteListSizeExceeded
+            );
+        }
 
         Ok(())
     }
@@ -334,17 +314,30 @@ impl<T: Trait> Module<T> {
         <frame_system::Module<T>>::block_number()
     }
 
-    // returns incremented thread counter if last thread author equals with provided parameter
-    fn get_updated_thread_counter(author_id: MemberId<T>) -> ThreadCounter<MemberId<T>> {
-        // if thread counter exists
-        if let Some(last_thread_author_counter) = Self::last_thread_author_counter() {
-            // if last(previous) author is the same as current author
-            if last_thread_author_counter.author_id == author_id {
-                return last_thread_author_counter.increment();
+    fn ensure_thread_mode(
+        origin: T::Origin,
+        thread_author_id: MemberId<T>,
+        thread_id: T::ThreadId,
+    ) -> DispatchResult {
+        let thread = Self::thread_by_id(thread_id);
+
+        match thread.mode {
+            ThreadMode::Open => Ok(()),
+            ThreadMode::Closed(members) => {
+                let is_thread_author = thread_author_id == thread.author_id;
+                let is_councilor =
+                    T::CouncilOriginValidator::ensure_actor_origin(origin, thread_author_id)
+                        .is_ok();
+                let is_allowed_member = members
+                    .iter()
+                    .any(|member_id| *member_id == thread_author_id);
+
+                if is_thread_author || is_councilor || is_allowed_member {
+                    Ok(())
+                } else {
+                    Err(Error::<T>::CannotPostOnClosedThread.into())
+                }
             }
         }
-
-        // else return new counter (set with 1 thread number)
-        ThreadCounter::new(author_id)
     }
 }

+ 28 - 8
runtime-modules/proposals/discussion/src/tests/mock.rs

@@ -30,8 +30,6 @@ parameter_types! {
 }
 
 parameter_types! {
-    pub const MaxPostEditionNumber: u32 = 5;
-    pub const MaxThreadInARowNumber: u32 = 3;
     pub const ThreadTitleLengthLimit: u32 = 200;
     pub const PostLengthLimit: u32 = 2000;
 }
@@ -57,6 +55,7 @@ parameter_types! {
     pub const ExistentialDeposit: u32 = 0;
     pub const TransferFee: u32 = 0;
     pub const CreationFee: u32 = 0;
+    pub const MaxWhiteListSize: u32 = 4;
 }
 
 impl balances::Trait for Test {
@@ -83,18 +82,16 @@ impl membership::Trait for Test {
 
 impl crate::Trait for Test {
     type Event = TestEvent;
-    type PostAuthorOriginValidator = ();
+    type AuthorOriginValidator = ();
+    type CouncilOriginValidator = CouncilMock;
     type ThreadId = u64;
     type PostId = u64;
-    type MaxPostEditionNumber = MaxPostEditionNumber;
-    type ThreadTitleLengthLimit = ThreadTitleLengthLimit;
-    type PostLengthLimit = PostLengthLimit;
-    type MaxThreadInARowNumber = MaxThreadInARowNumber;
+    type MaxWhiteListSize = MaxWhiteListSize;
 }
 
 impl ActorOriginValidator<Origin, u64, u64> for () {
     fn ensure_actor_origin(origin: Origin, actor_id: u64) -> Result<u64, &'static str> {
-        if frame_system::ensure_none(origin).is_ok() {
+        if frame_system::ensure_none(origin.clone()).is_ok() {
             return Ok(1);
         }
 
@@ -102,10 +99,33 @@ impl ActorOriginValidator<Origin, u64, u64> for () {
             return Ok(1);
         }
 
+        if actor_id == 2 {
+            return Ok(2);
+        }
+
+        if actor_id == 11 {
+            return Ok(11);
+        }
+
+        if actor_id == 12 && frame_system::ensure_signed(origin).unwrap_or_default() == 12 {
+            return Ok(12);
+        }
+
         Err("Invalid author")
     }
 }
 
+pub struct CouncilMock;
+impl ActorOriginValidator<Origin, u64, u64> for CouncilMock {
+    fn ensure_actor_origin(origin: Origin, actor_id: u64) -> Result<u64, &'static str> {
+        if actor_id == 2 && frame_system::ensure_signed(origin).unwrap_or_default() == 2 {
+            return Ok(2);
+        }
+
+        Err("Not a council")
+    }
+}
+
 impl frame_system::Trait for Test {
     type BaseCallFilter = ();
     type Origin = Origin;

+ 213 - 78
runtime-modules/proposals/discussion/src/tests/mod.rs

@@ -5,7 +5,8 @@ use frame_system::RawOrigin;
 use frame_system::{EventRecord, Phase};
 
 use crate::*;
-use mock::*;
+
+pub(crate) use mock::*;
 
 struct EventFixture;
 impl EventFixture {
@@ -39,23 +40,16 @@ fn assert_thread_content(thread_entry: TestThreadEntry, post_entries: Vec<TestPo
 
     let actual_thread = <ThreadById<Test>>::get(thread_entry.thread_id);
     let expected_thread = DiscussionThread {
-        title: thread_entry.title,
-        created_at: 0,
+        activated_at: 0,
         author_id: 1,
+        mode: Default::default(),
     };
     assert_eq!(actual_thread, expected_thread);
 
     for post_entry in post_entries {
         let actual_post =
             <PostThreadIdByPostId<Test>>::get(thread_entry.thread_id, post_entry.post_id);
-        let expected_post = DiscussionPost {
-            text: post_entry.text,
-            created_at: 0,
-            updated_at: 0,
-            author_id: 1,
-            thread_id: thread_entry.thread_id,
-            edition_number: post_entry.edition_number,
-        };
+        let expected_post = DiscussionPost { author_id: 1 };
 
         assert_eq!(actual_post, expected_post);
     }
@@ -65,6 +59,7 @@ struct DiscussionFixture {
     pub title: Vec<u8>,
     pub origin: RawOrigin<u64>,
     pub author_id: u64,
+    pub mode: ThreadMode<u64>,
 }
 
 impl Default for DiscussionFixture {
@@ -73,18 +68,19 @@ impl Default for DiscussionFixture {
             title: b"title".to_vec(),
             origin: RawOrigin::Signed(1),
             author_id: 1,
+            mode: ThreadMode::Open,
         }
     }
 }
 
 impl DiscussionFixture {
-    fn with_title(self, title: Vec<u8>) -> Self {
-        DiscussionFixture { title, ..self }
+    fn with_mode(self, mode: ThreadMode<u64>) -> Self {
+        Self { mode, ..self }
     }
 
     fn create_discussion_and_assert(&self, result: Result<u64, DispatchError>) -> Option<u64> {
         let create_discussion_result =
-            Discussions::create_thread(self.author_id, self.title.clone());
+            Discussions::create_thread(self.author_id, self.mode.clone());
 
         assert_eq!(create_discussion_result, result);
 
@@ -111,10 +107,6 @@ impl PostFixture {
         }
     }
 
-    fn with_text(self, text: Vec<u8>) -> Self {
-        PostFixture { text, ..self }
-    }
-
     fn with_origin(self, origin: RawOrigin<u64>) -> Self {
         PostFixture { origin, ..self }
     }
@@ -192,6 +184,47 @@ fn create_post_call_succeeds() {
     });
 }
 
+struct ChangeThreadModeFixture {
+    pub origin: RawOrigin<u64>,
+    pub thread_id: u64,
+    pub member_id: u64,
+    pub mode: ThreadMode<u64>,
+}
+
+impl ChangeThreadModeFixture {
+    fn default_for_thread_id(thread_id: u64) -> Self {
+        Self {
+            origin: RawOrigin::Signed(1),
+            thread_id,
+            member_id: 1,
+            mode: ThreadMode::Open,
+        }
+    }
+
+    fn with_mode(self, mode: ThreadMode<u64>) -> Self {
+        Self { mode, ..self }
+    }
+
+    fn with_member_id(self, member_id: u64) -> Self {
+        Self { member_id, ..self }
+    }
+
+    fn with_origin(self, origin: RawOrigin<u64>) -> Self {
+        Self { origin, ..self }
+    }
+
+    fn call_and_assert(&self, expected_result: DispatchResult) {
+        let actual_result = Discussions::change_thread_mode(
+            self.origin.clone().into(),
+            self.member_id,
+            self.thread_id,
+            self.mode.clone(),
+        );
+
+        assert_eq!(actual_result, expected_result);
+    }
+}
+
 #[test]
 fn update_post_call_succeeds() {
     initial_test_ext().execute_with(|| {
@@ -221,27 +254,6 @@ fn update_post_call_succeeds() {
     });
 }
 
-#[test]
-fn update_post_call_fails_because_of_post_edition_limit() {
-    initial_test_ext().execute_with(|| {
-        let discussion_fixture = DiscussionFixture::default();
-
-        let thread_id = discussion_fixture
-            .create_discussion_and_assert(Ok(1))
-            .unwrap();
-
-        let mut post_fixture = PostFixture::default_for_thread(thread_id);
-
-        post_fixture.add_post_and_assert(Ok(()));
-
-        for _ in 1..6 {
-            post_fixture.update_post_and_assert(Ok(()));
-        }
-
-        post_fixture.update_post_and_assert(Err(Error::<Test>::PostEditionNumberExceeded.into()));
-    });
-}
-
 #[test]
 fn update_post_call_fails_because_of_the_wrong_author() {
     initial_test_ext().execute_with(|| {
@@ -255,7 +267,7 @@ fn update_post_call_fails_because_of_the_wrong_author() {
 
         post_fixture.add_post_and_assert(Ok(()));
 
-        post_fixture = post_fixture.with_author(2);
+        post_fixture = post_fixture.with_author(5);
 
         post_fixture.update_post_and_assert(Err(DispatchError::Other("Invalid author")));
 
@@ -302,18 +314,6 @@ fn thread_content_check_succeeded() {
     });
 }
 
-#[test]
-fn create_discussion_call_with_bad_title_failed() {
-    initial_test_ext().execute_with(|| {
-        let mut discussion_fixture = DiscussionFixture::default().with_title(Vec::new());
-        discussion_fixture
-            .create_discussion_and_assert(Err(Error::<Test>::EmptyTitleProvided.into()));
-
-        discussion_fixture = DiscussionFixture::default().with_title([0; 201].to_vec());
-        discussion_fixture.create_discussion_and_assert(Err(Error::<Test>::TitleIsTooLong.into()));
-    });
-}
-
 #[test]
 fn add_post_call_with_invalid_thread_failed() {
     initial_test_ext().execute_with(|| {
@@ -360,68 +360,203 @@ fn update_post_call_with_invalid_thread_failed() {
 }
 
 #[test]
-fn add_post_call_with_invalid_text_failed() {
+fn discussion_thread_and_post_counters_are_valid() {
+    initial_test_ext().execute_with(|| {
+        let discussion_fixture = DiscussionFixture::default();
+        let thread_id = discussion_fixture
+            .create_discussion_and_assert(Ok(1))
+            .unwrap();
+
+        let mut post_fixture1 = PostFixture::default_for_thread(thread_id);
+        let _ = post_fixture1.add_post_and_assert(Ok(())).unwrap();
+
+        assert_eq!(Discussions::thread_count(), 1);
+        assert_eq!(Discussions::post_count(), 1);
+    });
+}
+
+#[test]
+fn change_thread_mode_succeeds() {
     initial_test_ext().execute_with(|| {
+        /*
+           Events are not emitted on block 0.
+           So any dispatchable calls made during genesis block formation will have no events emitted.
+           https://substrate.dev/recipes/2-appetizers/4-events.html
+        */
+        run_to_block(1);
+
         let discussion_fixture = DiscussionFixture::default();
+
         let thread_id = discussion_fixture
             .create_discussion_and_assert(Ok(1))
             .unwrap();
 
-        let mut post_fixture1 = PostFixture::default_for_thread(thread_id).with_text(Vec::new());
-        post_fixture1.add_post_and_assert(Err(Error::<Test>::EmptyPostProvided.into()));
+        let thread_mode = ThreadMode::Closed(vec![2, 3]);
+        let change_thread_mode_fixture = ChangeThreadModeFixture::default_for_thread_id(thread_id)
+            .with_mode(thread_mode.clone());
+        change_thread_mode_fixture.call_and_assert(Ok(()));
 
-        let mut post_fixture2 =
-            PostFixture::default_for_thread(thread_id).with_text([0; 2001].to_vec());
-        post_fixture2.add_post_and_assert(Err(Error::<Test>::PostIsTooLong.into()));
+        EventFixture::assert_events(vec![
+            RawEvent::ThreadCreated(1, 1),
+            RawEvent::ThreadModeChanged(1, thread_mode),
+        ]);
     });
 }
 
 #[test]
-fn update_post_call_with_invalid_text_failed() {
+fn change_mode_failed_with_invalid_origin() {
     initial_test_ext().execute_with(|| {
         let discussion_fixture = DiscussionFixture::default();
+
         let thread_id = discussion_fixture
             .create_discussion_and_assert(Ok(1))
             .unwrap();
 
-        let mut post_fixture1 = PostFixture::default_for_thread(thread_id);
-        post_fixture1.add_post_and_assert(Ok(()));
+        let change_thread_mode_fixture = ChangeThreadModeFixture::default_for_thread_id(thread_id)
+            .with_origin(RawOrigin::Root)
+            .with_member_id(12);
+        change_thread_mode_fixture.call_and_assert(Err(DispatchError::Other("Invalid author")));
+    });
+}
 
-        let mut post_fixture2 = post_fixture1.with_text(Vec::new());
-        post_fixture2.update_post_and_assert(Err(Error::<Test>::EmptyPostProvided.into()));
+#[test]
+fn change_mode_failed_with_invalid_thread_id() {
+    initial_test_ext().execute_with(|| {
+        let invalid_thread_id = 12;
 
-        let mut post_fixture3 = post_fixture2.with_text([0; 2001].to_vec());
-        post_fixture3.update_post_and_assert(Err(Error::<Test>::PostIsTooLong.into()));
+        let change_thread_mode_fixture =
+            ChangeThreadModeFixture::default_for_thread_id(invalid_thread_id);
+        change_thread_mode_fixture.call_and_assert(Err(Error::<Test>::ThreadDoesntExist.into()));
     });
 }
 
 #[test]
-fn add_discussion_thread_fails_because_of_max_thread_by_same_author_in_a_row_limit_exceeded() {
+fn change_mode_failed_with_not_thread_author_or_councilor() {
     initial_test_ext().execute_with(|| {
         let discussion_fixture = DiscussionFixture::default();
-        for idx in 1..=3 {
-            discussion_fixture
-                .create_discussion_and_assert(Ok(idx))
-                .unwrap();
-        }
 
-        discussion_fixture
-            .create_discussion_and_assert(Err(Error::<Test>::MaxThreadInARowLimitExceeded.into()));
+        let thread_id = discussion_fixture
+            .create_discussion_and_assert(Ok(1))
+            .unwrap();
+
+        let change_thread_mode_fixture = ChangeThreadModeFixture::default_for_thread_id(thread_id)
+            .with_origin(RawOrigin::Signed(12))
+            .with_member_id(12);
+        change_thread_mode_fixture.call_and_assert(Err(Error::<Test>::NotAuthorOrCouncilor.into()));
     });
 }
 
 #[test]
-fn discussion_thread_and_post_counters_are_valid() {
+fn change_thread_mode_succeeds_with_councilor() {
     initial_test_ext().execute_with(|| {
         let discussion_fixture = DiscussionFixture::default();
+
         let thread_id = discussion_fixture
             .create_discussion_and_assert(Ok(1))
             .unwrap();
 
-        let mut post_fixture1 = PostFixture::default_for_thread(thread_id);
-        let _ = post_fixture1.add_post_and_assert(Ok(())).unwrap();
+        let change_thread_mode_fixture = ChangeThreadModeFixture::default_for_thread_id(thread_id)
+            .with_member_id(2)
+            .with_origin(RawOrigin::Signed(2));
+        change_thread_mode_fixture.call_and_assert(Ok(()));
+    });
+}
 
-        assert_eq!(Discussions::thread_count(), 1);
-        assert_eq!(Discussions::post_count(), 1);
+#[test]
+fn create_post_call_succeeds_with_closed_mode_by_author() {
+    initial_test_ext().execute_with(|| {
+        let mode = ThreadMode::Closed(vec![2, 11]);
+        let discussion_fixture = DiscussionFixture::default().with_mode(mode);
+
+        let thread_id = discussion_fixture
+            .create_discussion_and_assert(Ok(1))
+            .unwrap();
+
+        let mut post_fixture = PostFixture::default_for_thread(thread_id)
+            .with_origin(RawOrigin::Signed(1))
+            .with_author(1);
+
+        post_fixture.add_post_and_assert(Ok(()));
+    });
+}
+
+#[test]
+fn create_post_call_succeeds_with_closed_mode_by_councilor() {
+    initial_test_ext().execute_with(|| {
+        let mode = ThreadMode::Closed(vec![2, 11]);
+        let discussion_fixture = DiscussionFixture::default().with_mode(mode);
+
+        let thread_id = discussion_fixture
+            .create_discussion_and_assert(Ok(1))
+            .unwrap();
+
+        let mut post_fixture = PostFixture::default_for_thread(thread_id)
+            .with_origin(RawOrigin::Signed(2))
+            .with_author(2);
+
+        post_fixture.add_post_and_assert(Ok(()));
+    });
+}
+
+#[test]
+fn create_post_call_succeeds_with_closed_mode_by_white_listed_member() {
+    initial_test_ext().execute_with(|| {
+        let mode = ThreadMode::Closed(vec![2, 11]);
+        let discussion_fixture = DiscussionFixture::default().with_mode(mode);
+
+        let thread_id = discussion_fixture
+            .create_discussion_and_assert(Ok(1))
+            .unwrap();
+
+        let mut post_fixture = PostFixture::default_for_thread(thread_id)
+            .with_origin(RawOrigin::Signed(11))
+            .with_author(11);
+
+        post_fixture.add_post_and_assert(Ok(()));
+    });
+}
+
+#[test]
+fn create_post_call_fails_with_closed_mode_by_not_allowed_member() {
+    initial_test_ext().execute_with(|| {
+        let mode = ThreadMode::Closed(vec![2, 10]);
+        let discussion_fixture = DiscussionFixture::default().with_mode(mode);
+
+        let thread_id = discussion_fixture
+            .create_discussion_and_assert(Ok(1))
+            .unwrap();
+
+        let mut post_fixture = PostFixture::default_for_thread(thread_id)
+            .with_origin(RawOrigin::Signed(11))
+            .with_author(11);
+
+        post_fixture.add_post_and_assert(Err(Error::<Test>::CannotPostOnClosedThread.into()));
+    });
+}
+
+#[test]
+fn change_thread_mode_fails_with_exceeded_max_author_list_size() {
+    initial_test_ext().execute_with(|| {
+        let discussion_fixture = DiscussionFixture::default();
+
+        let thread_id = discussion_fixture
+            .create_discussion_and_assert(Ok(1))
+            .unwrap();
+
+        let change_thread_mode_fixture = ChangeThreadModeFixture::default_for_thread_id(thread_id)
+            .with_mode(ThreadMode::Closed(vec![2, 3, 4, 5, 6]));
+        change_thread_mode_fixture
+            .call_and_assert(Err(Error::<Test>::MaxWhiteListSizeExceeded.into()));
+    });
+}
+
+#[test]
+fn create_discussion_call_fails_with_exceeded_max_author_list_size() {
+    initial_test_ext().execute_with(|| {
+        let discussion_fixture =
+            DiscussionFixture::default().with_mode(ThreadMode::Closed(vec![2, 3, 4, 5, 6]));
+
+        discussion_fixture
+            .create_discussion_and_assert(Err(Error::<Test>::MaxWhiteListSizeExceeded.into()));
     });
 }

+ 17 - 73
runtime-modules/proposals/discussion/src/types.rs

@@ -8,94 +8,38 @@ use sp_std::vec::Vec;
 /// Represents a discussion thread
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
 #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
-pub struct DiscussionThread<ThreadAuthorId, BlockNumber> {
-    /// Title
-    pub title: Vec<u8>,
-
+pub struct DiscussionThread<ThreadAuthorId, BlockNumber, MemberId> {
     /// When thread was established.
-    pub created_at: BlockNumber,
+    pub activated_at: BlockNumber,
 
     /// Author of the thread.
     pub author_id: ThreadAuthorId,
+
+    /// Thread permission mode.
+    pub mode: ThreadMode<MemberId>,
 }
 
 /// Post for the discussion thread
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
 #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
-pub struct DiscussionPost<PostAuthorId, BlockNumber, ThreadId> {
-    /// Text
-    pub text: Vec<u8>,
-
-    /// When post was added.
-    pub created_at: BlockNumber,
-
-    /// When post was updated last time.
-    pub updated_at: BlockNumber,
-
+pub struct DiscussionPost<PostAuthorId> {
     /// Author of the post.
     pub author_id: PostAuthorId,
-
-    /// Parent thread id for this post
-    pub thread_id: ThreadId,
-
-    /// Defines how many times this post was edited. Zero on creation.
-    pub edition_number: u32,
-}
-
-/// Post for the discussion thread
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
-#[derive(Encode, Decode, Default, Clone, Copy, PartialEq, Eq)]
-pub struct ThreadCounter<ThreadAuthorId> {
-    /// Author of the threads.
-    pub author_id: ThreadAuthorId,
-
-    /// ThreadCount
-    pub counter: u32,
 }
 
-impl<ThreadAuthorId: Clone> ThreadCounter<ThreadAuthorId> {
-    /// Increments existing counter
-    pub fn increment(&self) -> Self {
-        ThreadCounter {
-            counter: self.counter + 1,
-            author_id: self.author_id.clone(),
-        }
-    }
+/// Discussion thread permission modes.
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
+#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
+pub enum ThreadMode<MemberId> {
+    /// Every member can post on the thread.
+    Open,
 
-    /// Creates new counter by author_id. Counter instantiated with 1.
-    pub fn new(author_id: ThreadAuthorId) -> Self {
-        ThreadCounter {
-            author_id,
-            counter: 1,
-        }
-    }
+    /// Only author, councilor or white member list could post on the thread.
+    Closed(Vec<MemberId>),
 }
 
-#[cfg(test)]
-mod tests {
-    use crate::types::ThreadCounter;
-
-    #[test]
-    fn thread_counter_increment_works() {
-        let test = ThreadCounter {
-            author_id: 56,
-            counter: 56,
-        };
-        let expected = ThreadCounter {
-            author_id: 56,
-            counter: 57,
-        };
-
-        assert_eq!(expected, test.increment());
-    }
-
-    #[test]
-    fn thread_counter_new_works() {
-        let expected = ThreadCounter {
-            author_id: 56,
-            counter: 1,
-        };
-
-        assert_eq!(expected, ThreadCounter::new(56));
+impl<MemberId> Default for ThreadMode<MemberId> {
+    fn default() -> Self {
+        Self::Open
     }
 }

+ 3 - 5
runtime-modules/proposals/engine/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = 'pallet-proposals-engine'
-version = '3.1.0'
+version = '4.0.0'
 authors = ['Joystream contributors']
 edition = '2018'
 
@@ -13,15 +13,13 @@ frame-system = { package = 'frame-system', default-features = false, git = 'http
 pallet-timestamp = { package = 'pallet-timestamp', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 sp-arithmetic = { package = 'sp-arithmetic', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 sp-runtime = { package = 'sp-runtime', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
+balances = { package = 'pallet-balances', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 membership = { package = 'pallet-membership', default-features = false, path = '../../membership'}
-stake = { package = 'pallet-stake', default-features = false, path = '../../stake'}
 common = { package = 'pallet-common', default-features = false, path = '../../common'}
 
 [dev-dependencies]
-mockall = "0.7.1"
 sp-io = { package = 'sp-io', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 sp-core = { package = 'sp-core', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
-balances = { package = 'pallet-balances', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 
 [features]
 default = ['std']
@@ -34,7 +32,7 @@ std = [
 	'pallet-timestamp/std',
 	'sp-arithmetic/std',
 	'sp-runtime/std',
+	'balances/std',
     'membership/std',
-    'stake/std',
     'common/std',
 ]

+ 302 - 351
runtime-modules/proposals/engine/src/lib.rs

@@ -1,5 +1,5 @@
 //! # Proposals engine module
-//! Proposals `engine` module for the Joystream platform. Version 2.
+//! Proposals `engine` module for the Joystream platform. Version 3.
 //! The main component of the proposals system. Provides methods and extrinsics to create and
 //! vote for proposals, inspired by Parity **Democracy module**.
 //!
@@ -12,24 +12,21 @@
 //! ## Proposal lifecycle
 //! When a proposal passes [checks](./struct.Module.html#method.ensure_create_proposal_parameters_are_valid)
 //! for its [parameters](./struct.ProposalParameters.html) - it can be [created](./struct.Module.html#method.create_proposal).
-//! The newly created proposal has _Active_ status. The proposal can be voted on or canceled during its
+//! The newly created proposal has _Active_ status. The proposal can be voted on, vetoed or canceled during its
 //! _voting period_. Votes can be [different](./enum.VoteKind.html). When the proposal gets enough votes
-//! to be slashed or approved or _voting period_ ends - the proposal becomes _Finalized_. If the proposal
-//! got approved and _grace period_ passed - the  `engine` module tries to execute the proposal.
-//! The final [approved status](./enum.ApprovedProposalStatus.html) of the proposal defines
-//! an overall proposal outcome.
+//! to be approved - the proposal becomes _PendingExecution_ or _PendingConstitutionality_. The proposal
+//! could also be slashed or rejected. If the _voting period_ ends with no decision it becomes expired.
+//! If the proposal got approved and _grace period_ passed - the  `engine` module tries to execute the proposal.
 //!
 //! ### Notes
 //!
 //! - The proposal can be [vetoed](./struct.Module.html#method.veto_proposal)
 //! anytime before the proposal execution by the _sudo_.
-//! - When the proposal is created with some stake - refunding on proposal finalization with
-//! different statuses should be accomplished from the external handler from the _stake module_
-//! (_StakingEventsHandler_). Such a handler should call
-//! [refund_proposal_stake](./struct.Module.html#method.refund_proposal_stake) callback function.
 //! - If the _council_ got reelected during the proposal _voting period_ the external handler calls
-//! [reset_active_proposals](./trait.Module.html#method.reset_active_proposals) function and
-//! all voting results get cleared.
+//! [reject_active_proposals](./trait.Module.html#method.reject_active_proposals) function and
+//! all active proposals got rejected and it also calls [reactivate_pending_constitutionality_proposals](./trait.Module.html#method.reactivate_pending_constitutionality_proposals)
+//! and proposals with pending constitutionality become active again.
+//! - There are different fees to apply for slashed, rejected, expired or cancelled proposals.
 //!
 //! ### Important abstract types to be implemented
 //! Proposals `engine` module has several abstractions to be implemented in order to work correctly.
@@ -39,7 +36,7 @@
 //! the council size
 //! - _ProposerOriginValidator_ - ensure valid proposer identity. Proposers should have permissions
 //! to create a proposal: they should be members of the Joystream.
-//! - [StakeHandlerProvider](./trait.StakeHandlerProvider.html) - defines an interface for the staking.
+//! - [StakingHandler](./trait.StakingHandler.html) - defines an interface for the staking.
 //!
 //! A full list of the abstractions can be found [here](./trait.Trait.html).
 //!
@@ -51,8 +48,8 @@
 //! ### Public API
 //! - [create_proposal](./struct.Module.html#method.create_proposal) - creates proposal using provided parameters
 //! - [ensure_create_proposal_parameters_are_valid](./struct.Module.html#method.ensure_create_proposal_parameters_are_valid) - ensures that we can create the proposal
-//! - [refund_proposal_stake](./struct.Module.html#method.refund_proposal_stake) - a callback for _StakingHandlerEvents_
-//! - [reset_active_proposals](./trait.Module.html#method.reset_active_proposals) - resets voting results for active proposals
+//! - [reject_active_proposals](./trait.Module.html#method.reject_active_proposals) - rejects all active proposals.
+//! - [reactivate_pending_constitutionality_proposals](./trait.Module.html#method.reactivate_pending_constitutionality_proposals) - reactivate proposals with pending constitutionality.
 //!
 //! ## Usage
 //!
@@ -60,7 +57,7 @@
 //! use frame_support::{decl_module, print};
 //! use frame_system::ensure_signed;
 //! use codec::Encode;
-//! use pallet_proposals_engine::{self as engine, ProposalParameters};
+//! use pallet_proposals_engine::{self as engine, ProposalParameters, ProposalCreationParameters};
 //!
 //! pub trait Trait: engine::Trait + membership::Trait {}
 //!
@@ -87,17 +84,22 @@
 //!                 &parameters,
 //!                 &title,
 //!                 &description,
-//!                 None
+//!                 None,
+//!                 None,
 //!             )?;
-//!             <engine::Module<T>>::create_proposal(
+//!
+//!             let creation_parameters = ProposalCreationParameters {
 //!                 account_id,
 //!                 proposer_id,
-//!                 parameters,
+//!                 proposal_parameters : parameters,
 //!                 title,
 //!                 description,
-//!                 None,
-//!                 encoded_proposal_code
-//!             )?;
+//!                 staking_account_id: None,
+//!                 encoded_dispatchable_call_code: encoded_proposal_code,
+//!                 exact_execution_block: None,
+//!             };
+//!
+//!             <engine::Module<T>>::create_proposal(creation_parameters)?;
 //!         }
 //!     }
 //! }
@@ -107,20 +109,13 @@
 // Ensure we're `no_std` when compiling for Wasm.
 #![cfg_attr(not(feature = "std"), no_std)]
 
-// Do not delete! Cannot be uncommented by default, because of Parity decl_module! issue.
-//#![warn(missing_docs)]
+use types::{MemberId, ProposalOf};
 
-use crate::types::ApprovedProposalData;
-use types::FinalizedProposalData;
-use types::ProposalStakeManager;
 pub use types::{
-    ActiveStake, ApprovedProposalStatus, FinalizationData, Proposal, ProposalDecisionStatus,
-    ProposalParameters, ProposalStatus, VotingResults,
+    ApprovedProposalDecision, BalanceOf, ExecutionStatus, Proposal, ProposalCodeDecoder,
+    ProposalCreationParameters, ProposalDecision, ProposalExecutable, ProposalParameters,
+    ProposalStatus, VoteKind, VotersParameters, VotingResults,
 };
-pub use types::{BalanceOf, CurrencyOf, NegativeImbalance};
-pub use types::{DefaultStakeHandlerProvider, StakeHandler, StakeHandlerProvider};
-pub use types::{ProposalCodeDecoder, ProposalExecutable};
-pub use types::{VoteKind, VotersParameters};
 
 pub(crate) mod types;
 
@@ -130,21 +125,20 @@ mod tests;
 use codec::Decode;
 use frame_support::dispatch::{DispatchError, DispatchResult, UnfilteredDispatchable};
 use frame_support::storage::IterableStorageMap;
-use frame_support::traits::{Currency, Get};
+use frame_support::traits::Get;
 use frame_support::{
-    decl_error, decl_event, decl_module, decl_storage, ensure, print, Parameter, StorageDoubleMap,
+    decl_error, decl_event, decl_module, decl_storage, ensure, Parameter, StorageDoubleMap,
 };
 use frame_system::{ensure_root, RawOrigin};
 use sp_arithmetic::traits::Zero;
 use sp_std::vec::Vec;
 
 use common::origin::ActorOriginValidator;
-
-type MemberId<T> = <T as membership::Trait>::MemberId;
+use membership::staking_handler::StakingHandler;
 
 /// Proposals engine trait.
 pub trait Trait:
-    frame_system::Trait + pallet_timestamp::Trait + stake::Trait + membership::Trait
+    frame_system::Trait + pallet_timestamp::Trait + membership::Trait + balances::Trait
 {
     /// Engine event type.
     type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
@@ -165,8 +159,8 @@ pub trait Trait:
     /// Proposal Id type
     type ProposalId: From<u32> + Parameter + Default + Copy;
 
-    /// Provides stake logic implementation. Can be used to mock stake logic.
-    type StakeHandlerProvider: StakeHandlerProvider<Self>;
+    /// Provides stake logic implementation.
+    type StakingHandler: StakingHandler<Self>;
 
     /// The fee is applied when cancel the proposal. A fee would be slashed (burned).
     type CancellationFee: Get<BalanceOf<Self>>;
@@ -185,6 +179,23 @@ pub trait Trait:
 
     /// Proposals executable code. Can be instantiated by external module Call enum members.
     type DispatchableCallCode: Parameter + UnfilteredDispatchable<Origin = Self::Origin> + Default;
+
+    /// Proposal state change observer.
+    type ProposalObserver: ProposalObserver<Self>;
+}
+
+/// Proposal state change observer.
+pub trait ProposalObserver<T: Trait> {
+    /// Should be called on proposal removing.
+    fn proposal_removed(proposal_id: &T::ProposalId);
+}
+
+/// Nesting implementation.
+impl<T: Trait, X: ProposalObserver<T>, Y: ProposalObserver<T>> ProposalObserver<T> for (X, Y) {
+    fn proposal_removed(proposal_id: &<T as Trait>::ProposalId) {
+        X::proposal_removed(proposal_id);
+        Y::proposal_removed(proposal_id);
+    }
 }
 
 decl_event!(
@@ -194,8 +205,6 @@ decl_event!(
         <T as Trait>::ProposalId,
         MemberId = MemberId<T>,
         <T as frame_system::Trait>::BlockNumber,
-        <T as frame_system::Trait>::AccountId,
-        <T as stake::Trait>::StakeId,
     {
         /// Emits on proposal creation.
         /// Params:
@@ -203,11 +212,23 @@ decl_event!(
         /// - Id of a newly created proposal after it was saved in storage.
         ProposalCreated(MemberId, ProposalId),
 
-        /// Emits on proposal status change.
+        /// Emits on proposal creation.
+        /// Params:
+        /// - Id of a proposal.
+        /// - New proposal status.
+        ProposalStatusUpdated(ProposalId, ProposalStatus<BlockNumber>),
+
+        /// Emits on getting a proposal status decision.
+        /// Params:
+        /// - Id of a proposal.
+        /// - Proposal decision
+        ProposalDecisionMade(ProposalId, ProposalDecision),
+
+        /// Emits on proposal execution.
         /// Params:
         /// - Id of a updated proposal.
-        /// - New proposal status
-        ProposalStatusUpdated(ProposalId, ProposalStatus<BlockNumber, StakeId, AccountId>),
+        /// - Proposal execution status.
+        ProposalExecuted(ProposalId, ExecutionStatus),
 
         /// Emits on voting for the proposal
         /// Params:
@@ -265,6 +286,18 @@ decl_error! {
 
         /// Require root origin in extrinsics
         RequireRootOrigin,
+
+        /// Disallow to cancel the proposal if there are any votes on it.
+        ProposalHasVotes,
+
+        /// Exact execution block cannot be zero.
+        ZeroExactExecutionBlock,
+
+        /// Exact execution block cannot be less than current_block.
+        InvalidExactExecutionBlock,
+
+        /// There is not enough balance for a stake.
+        InsufficientBalanceForStake,
     }
 }
 
@@ -280,26 +313,14 @@ decl_storage! {
 
         /// Map proposal executable code by proposal id.
         pub DispatchableCallCode get(fn proposal_codes): map hasher(blake2_128_concat)
-            T::ProposalId =>  Vec<u8>;
+            T::ProposalId => Vec<u8>;
 
         /// Count of active proposals.
         pub ActiveProposalCount get(fn active_proposal_count): u32;
 
-        /// Ids of proposals that are open for voting (have not been finalized yet).
-        pub ActiveProposalIds get(fn active_proposal_ids): map hasher(blake2_128_concat)
-            T::ProposalId=> ();
-
-        /// Ids of proposals that were approved and theirs grace period was not expired.
-        pub PendingExecutionProposalIds get(fn pending_proposal_ids): map hasher(blake2_128_concat)
-            T::ProposalId=> ();
-
         /// Double map for preventing duplicate votes. Should be cleaned after usage.
         pub VoteExistsByProposalByVoter get(fn vote_by_proposal_by_voter):
-            double_map hasher(blake2_128_concat)  T::ProposalId, hasher(blake2_128_concat) MemberId<T> => VoteKind;
-
-        /// Map proposal id by stake id. Required by StakingEventsHandler callback call
-        pub StakesProposals get(fn stakes_proposals): map hasher(blake2_128_concat)
-            T::StakeId =>  T::ProposalId;
+            double_map hasher(blake2_128_concat) T::ProposalId, hasher(blake2_128_concat) MemberId<T> => VoteKind;
     }
 }
 
@@ -329,11 +350,14 @@ decl_module! {
 
         /// Vote extrinsic. Conditions:  origin must allow votes.
         #[weight = 10_000_000] // TODO: adjust weight
-        pub fn vote(origin, voter_id: MemberId<T>, proposal_id: T::ProposalId, vote: VoteKind)  {
-            T::VoterOriginValidator::ensure_actor_origin(
-                origin,
-                voter_id,
-            )?;
+        pub fn vote(
+            origin,
+            voter_id: MemberId<T>,
+            proposal_id: T::ProposalId,
+            vote: VoteKind,
+            _rationale: Vec<u8>, // we use it on the query node side.
+        ) {
+            T::VoterOriginValidator::ensure_actor_origin(origin, voter_id)?;
 
             ensure!(<Proposals<T>>::contains_key(proposal_id), Error::<T>::ProposalNotFound);
             let mut proposal = Self::proposals(proposal_id);
@@ -359,20 +383,18 @@ decl_module! {
         /// Cancel a proposal by its original proposer.
         #[weight = 10_000_000] // TODO: adjust weight
         pub fn cancel_proposal(origin, proposer_id: MemberId<T>, proposal_id: T::ProposalId) {
-            T::ProposerOriginValidator::ensure_actor_origin(
-                origin,
-                proposer_id,
-            )?;
+            T::ProposerOriginValidator::ensure_actor_origin(origin, proposer_id)?;
 
             ensure!(<Proposals<T>>::contains_key(proposal_id), Error::<T>::ProposalNotFound);
             let proposal = Self::proposals(proposal_id);
 
             ensure!(proposer_id == proposal.proposer_id, Error::<T>::NotAuthor);
             ensure!(matches!(proposal.status, ProposalStatus::Active{..}), Error::<T>::ProposalFinalized);
+            ensure!(proposal.voting_results.no_votes_yet(), Error::<T>::ProposalHasVotes);
 
             // mutation
 
-            Self::finalize_proposal(proposal_id, ProposalDecisionStatus::Canceled);
+            Self::finalize_proposal(proposal_id, proposal, ProposalDecision::Canceled);
         }
 
         /// Veto a proposal. Must be root.
@@ -383,37 +405,20 @@ decl_module! {
             ensure!(<Proposals<T>>::contains_key(proposal_id), Error::<T>::ProposalNotFound);
             let proposal = Self::proposals(proposal_id);
 
+            ensure!(
+                proposal.status.is_active_or_pending_execution(),
+                Error::<T>::ProposalFinalized
+            );
+
             // mutation
 
-            if <PendingExecutionProposalIds<T>>::contains_key(proposal_id) {
-                Self::veto_pending_execution_proposal(proposal_id, proposal);
-            } else {
-                ensure!(matches!(proposal.status, ProposalStatus::Active{..}), Error::<T>::ProposalFinalized);
-                Self::finalize_proposal(proposal_id, ProposalDecisionStatus::Vetoed);
-            }
+            Self::finalize_proposal(proposal_id, proposal, ProposalDecision::Vetoed);
         }
 
         /// Block finalization. Perform voting period check, vote result tally, approved proposals
         /// grace period checks, and proposal execution.
         fn on_finalize(_n: T::BlockNumber) {
-            let finalized_proposals = Self::get_finalized_proposals();
-
-            // mutation
-
-            // Check vote results. Approved proposals with zero grace period will be
-            // transitioned to the PendingExecution status.
-            for  proposal_data in finalized_proposals {
-                <Proposals<T>>::insert(proposal_data.proposal_id, proposal_data.proposal);
-                Self::finalize_proposal(proposal_data.proposal_id, proposal_data.status);
-            }
-
-            let executable_proposals =
-                Self::get_approved_proposal_with_expired_grace_period();
-
-            // Execute approved proposals with expired grace period
-            for approved_proosal in executable_proposals {
-                Self::execute_proposal(approved_proosal);
-            }
+            Self::process_proposals();
         }
     }
 }
@@ -421,19 +426,19 @@ decl_module! {
 impl<T: Trait> Module<T> {
     /// Create proposal. Requires 'proposal origin' membership.
     pub fn create_proposal(
-        account_id: T::AccountId,
-        proposer_id: MemberId<T>,
-        parameters: ProposalParameters<T::BlockNumber, types::BalanceOf<T>>,
-        title: Vec<u8>,
-        description: Vec<u8>,
-        stake_balance: Option<types::BalanceOf<T>>,
-        encoded_dispatchable_call_code: Vec<u8>,
+        creation_params: ProposalCreationParameters<
+            T::BlockNumber,
+            BalanceOf<T>,
+            MemberId<T>,
+            T::AccountId,
+        >,
     ) -> Result<T::ProposalId, DispatchError> {
         Self::ensure_create_proposal_parameters_are_valid(
-            &parameters,
-            &title,
-            &description,
-            stake_balance,
+            &creation_params.proposal_parameters,
+            &creation_params.title,
+            &creation_params.description,
+            creation_params.staking_account_id.clone(),
+            creation_params.exact_execution_block,
         )?;
 
         // checks passed
@@ -443,41 +448,39 @@ impl<T: Trait> Module<T> {
         let new_proposal_id = next_proposal_count_value;
         let proposal_id = T::ProposalId::from(new_proposal_id);
 
-        // Check stake_balance for value and create stake if value exists, else take None
-        // If create_stake() returns error - return error from extrinsic
-        let stake_id_result = stake_balance
-            .map(|stake_amount| {
-                ProposalStakeManager::<T>::create_stake(stake_amount, account_id.clone())
-            })
-            .transpose()?;
-
-        let mut stake_data = None;
-        if let Some(stake_id) = stake_id_result {
-            stake_data = Some(ActiveStake {
-                stake_id,
-                source_account_id: account_id,
-            });
-
-            <StakesProposals<T>>::insert(stake_id, proposal_id);
-        }
+        // Lock stake balance for proposal if the stake is required.
+        if let Some(stake_balance) = creation_params.proposal_parameters.required_stake {
+            if let Some(staking_account_id) = creation_params.staking_account_id.clone() {
+                T::StakingHandler::lock(&staking_account_id, stake_balance);
+            } else {
+                // Return an error if no staking account provided.
+                return Err(Error::<T>::EmptyStake.into());
+            }
+        };
 
         let new_proposal = Proposal {
-            created_at: Self::current_block(),
-            parameters,
-            title,
-            description,
-            proposer_id,
-            status: ProposalStatus::Active(stake_data),
+            activated_at: Self::current_block(),
+            parameters: creation_params.proposal_parameters,
+            proposer_id: creation_params.proposer_id,
+            status: ProposalStatus::Active,
             voting_results: VotingResults::default(),
+            exact_execution_block: creation_params.exact_execution_block,
+            current_constitutionality_level: 0,
+            staking_account_id: creation_params.staking_account_id,
         };
 
         <Proposals<T>>::insert(proposal_id, new_proposal);
-        <DispatchableCallCode<T>>::insert(proposal_id, encoded_dispatchable_call_code);
-        <ActiveProposalIds<T>>::insert(proposal_id, ());
+        <DispatchableCallCode<T>>::insert(
+            proposal_id,
+            creation_params.encoded_dispatchable_call_code,
+        );
         ProposalCount::put(next_proposal_count_value);
         Self::increase_active_proposal_counter();
 
-        Self::deposit_event(RawEvent::ProposalCreated(proposer_id, proposal_id));
+        Self::deposit_event(RawEvent::ProposalCreated(
+            creation_params.proposer_id,
+            proposal_id,
+        ));
 
         Ok(proposal_id)
     }
@@ -488,10 +491,11 @@ impl<T: Trait> Module<T> {
     /// - provided parameters: approval_threshold_percentage and slashing_threshold_percentage > 0
     /// - provided stake balance and parameters.required_stake are valid
     pub fn ensure_create_proposal_parameters_are_valid(
-        parameters: &ProposalParameters<T::BlockNumber, types::BalanceOf<T>>,
+        parameters: &ProposalParameters<T::BlockNumber, BalanceOf<T>>,
         title: &[u8],
         description: &[u8],
-        stake_balance: Option<types::BalanceOf<T>>,
+        staking_account_id: Option<T::AccountId>,
+        exact_execution_block: Option<T::BlockNumber>,
     ) -> DispatchResult {
         ensure!(!title.is_empty(), Error::<T>::EmptyTitleProvided);
         ensure!(
@@ -523,66 +527,84 @@ impl<T: Trait> Module<T> {
             Error::<T>::InvalidParameterSlashingThreshold
         );
 
-        // check stake parameters
-        if let Some(required_stake) = parameters.required_stake {
-            if let Some(staked_balance) = stake_balance {
+        // Check stake parameters.
+        if staking_account_id.is_some() && parameters.required_stake.is_none() {
+            return Err(Error::<T>::StakeShouldBeEmpty.into());
+        }
+
+        if let Some(stake_balance) = parameters.required_stake {
+            if let Some(staking_account_id) = staking_account_id {
                 ensure!(
-                    required_stake == staked_balance,
-                    Error::<T>::StakeDiffersFromRequired
+                    T::StakingHandler::is_enough_balance_for_stake(
+                        &staking_account_id,
+                        stake_balance
+                    ),
+                    Error::<T>::InsufficientBalanceForStake
                 );
             } else {
                 return Err(Error::<T>::EmptyStake.into());
             }
         }
 
-        if stake_balance.is_some() && parameters.required_stake.is_none() {
-            return Err(Error::<T>::StakeShouldBeEmpty.into());
+        // Check execution block.
+        if let Some(execution_block) = exact_execution_block {
+            if execution_block == Zero::zero() {
+                return Err(Error::<T>::ZeroExactExecutionBlock.into());
+            }
+
+            let now = Self::current_block();
+            if execution_block < now + parameters.grace_period + parameters.voting_period {
+                return Err(Error::<T>::InvalidExactExecutionBlock.into());
+            }
         }
 
         Ok(())
     }
 
-    /// Callback from StakingEventsHandler. Refunds unstaked imbalance back to the source account.
-    /// There can be a lot of invariant breaks in the scope of this proposal.
-    /// Such situations are handled by adding error messages to the log.
-    pub fn refund_proposal_stake(stake_id: T::StakeId, imbalance: NegativeImbalance<T>) {
-        if <StakesProposals<T>>::contains_key(stake_id) {
-            let proposal_id = Self::stakes_proposals(stake_id);
-
-            if <Proposals<T>>::contains_key(proposal_id) {
-                let proposal = Self::proposals(proposal_id);
-
-                if let ProposalStatus::Active(active_stake_result) = proposal.status {
-                    if let Some(active_stake) = active_stake_result {
-                        let refunding_result = CurrencyOf::<T>::resolve_into_existing(
-                            &active_stake.source_account_id,
-                            imbalance,
-                        );
-
-                        if refunding_result.is_err() {
-                            print("Broken invariant: cannot refund");
-                        }
-                    }
-                } else {
-                    print("Broken invariant: proposal status is not Active");
+    /// Rejects all active proposals.
+    /// Possible application includes new council elections.
+    pub fn reject_active_proposals() {
+        // Filter active proposals and reject them.
+        <Proposals<T>>::iter()
+            .filter_map(|(proposal_id, proposal)| {
+                if proposal.status.is_active_proposal() {
+                    return Some((proposal_id, proposal));
                 }
-            } else {
-                print("Broken invariant: proposal doesn't exist");
-            }
-        } else {
-            print("Broken invariant: stake doesn't exist");
-        }
+
+                None
+            })
+            .for_each(|(proposal_id, proposal)| {
+                Self::finalize_proposal(proposal_id, proposal, ProposalDecision::Rejected);
+            });
     }
 
-    /// Resets voting results for active proposals.
+    /// Reactivate proposals with pending constitutionality.
     /// Possible application includes new council elections.
-    pub fn reset_active_proposals() {
-        <ActiveProposalIds<T>>::iter().for_each(|(proposal_id, _)| {
-            <Proposals<T>>::mutate(proposal_id, |proposal| {
-                proposal.reset_proposal();
+    pub fn reactivate_pending_constitutionality_proposals() {
+        // Filter pending constitutionality proposals, calculate new proposals and update the state.
+        <Proposals<T>>::iter()
+            .filter_map(|(proposal_id, mut proposal)| {
+                if proposal.status.is_pending_constitutionality_proposal() {
+                    proposal.activated_at = Self::current_block();
+                    proposal.status = ProposalStatus::Active;
+                    // Resets votes for a proposal.
+                    proposal.reset_proposal_votes();
+
+                    return Some((proposal_id, proposal));
+                }
+
+                None
+            })
+            .for_each(|(proposal_id, proposal)| {
                 <VoteExistsByProposalByVoter<T>>::remove_prefix(&proposal_id);
+                <Proposals<T>>::insert(proposal_id, proposal.clone());
+
+                // fire the proposal status update event
+                Self::deposit_event(RawEvent::ProposalStatusUpdated(
+                    proposal_id,
+                    proposal.status,
+                ));
             });
-        });
     }
 }
 
@@ -592,199 +614,115 @@ impl<T: Trait> Module<T> {
         <frame_system::Module<T>>::block_number()
     }
 
-    // Enumerates through active proposals. Tally Voting results.
-    // Returns proposals with finalized status and id
-    fn get_finalized_proposals() -> Vec<FinalizedProposal<T>> {
-        // Enumerate active proposals id and gather finalization data.
-        // Skip proposals with unfinished voting.
-        <ActiveProposalIds<T>>::iter()
-            .filter_map(|(proposal_id, _)| {
-                // load current proposal
-                let proposal = Self::proposals(proposal_id);
-
-                // Calculates votes, takes in account voting period expiration.
-                // If voting process is in progress, then decision status is None.
-                let decision_status = proposal.define_proposal_decision_status(
-                    T::TotalVotersCounter::total_voters_count(),
-                    Self::current_block(),
-                );
-
-                // map to FinalizedProposalData if decision for the proposal is made or return None
-                decision_status.map(|status| FinalizedProposalData {
-                    proposal_id,
-                    proposal,
-                    status,
-                    finalized_at: Self::current_block(),
-                })
-            })
-            .collect() // compose output vector
-    }
-
-    // Veto approved proposal during its grace period. Saves a new proposal status and removes
-    // proposal id from the 'PendingExecutionProposalIds'
-    fn veto_pending_execution_proposal(proposal_id: T::ProposalId, proposal: ProposalOf<T>) {
-        <PendingExecutionProposalIds<T>>::remove(proposal_id);
-
-        let vetoed_proposal_status = ProposalStatus::finalized(
-            ProposalDecisionStatus::Vetoed,
-            None,
-            None,
-            Self::current_block(),
-        );
-
-        <Proposals<T>>::insert(
-            proposal_id,
-            Proposal {
-                status: vetoed_proposal_status,
-                ..proposal
-            },
-        );
-    }
-
-    // Executes approved proposal code
-    fn execute_proposal(approved_proposal: ApprovedProposal<T>) {
-        let proposal_code = Self::proposal_codes(approved_proposal.proposal_id);
+    // Executes proposal code.
+    fn execute_proposal(proposal_id: T::ProposalId) {
+        let proposal_code = Self::proposal_codes(proposal_id);
 
         let proposal_code_result = T::DispatchableCallCode::decode(&mut &proposal_code[..]);
 
-        let approved_proposal_status = match proposal_code_result {
+        let execution_status = match proposal_code_result {
             Ok(proposal_code) => {
                 if let Err(dispatch_error) =
                     proposal_code.dispatch_bypass_filter(T::Origin::from(RawOrigin::Root))
                 {
-                    ApprovedProposalStatus::failed_execution(Self::parse_dispatch_error(
+                    ExecutionStatus::failed_execution(Self::parse_dispatch_error(
                         dispatch_error.error,
                     ))
                 } else {
-                    ApprovedProposalStatus::Executed
+                    ExecutionStatus::Executed
                 }
             }
-            Err(error) => ApprovedProposalStatus::failed_execution(error.what()),
+            Err(error) => ExecutionStatus::failed_execution(error.what()),
         };
 
-        let proposal_execution_status = approved_proposal
-            .finalisation_status_data
-            .create_approved_proposal_status(approved_proposal_status);
+        Self::deposit_event(RawEvent::ProposalExecuted(proposal_id, execution_status));
 
-        let mut proposal = approved_proposal.proposal;
-        proposal.status = proposal_execution_status.clone();
-        <Proposals<T>>::insert(approved_proposal.proposal_id, proposal);
+        Self::remove_proposal_data(&proposal_id);
+    }
 
-        Self::deposit_event(RawEvent::ProposalStatusUpdated(
-            approved_proposal.proposal_id,
-            proposal_execution_status,
+    // Computes a finalized proposal:
+    // - update proposal status fields (status, finalized_at),
+    // - increment constitutionality level of the proposal.
+    // Performs all side-effect actions on proposal finalization:
+    // - slash and unstake proposal stake if stake exists,
+    // - fire an event,
+    // - update or delete proposal state.
+    // Executes the proposal if it ready.
+    fn finalize_proposal(
+        proposal_id: T::ProposalId,
+        proposal: ProposalOf<T>,
+        proposal_decision: ProposalDecision,
+    ) {
+        // fire the proposal decision event
+        Self::deposit_event(RawEvent::ProposalDecisionMade(
+            proposal_id,
+            proposal_decision.clone(),
         ));
 
-        <PendingExecutionProposalIds<T>>::remove(&approved_proposal.proposal_id);
-    }
+        // deal with stakes if necessary
+        if proposal_decision
+            != ProposalDecision::Approved(ApprovedProposalDecision::PendingConstitutionality)
+        {
+            let slash_balance =
+                Self::calculate_slash_balance(&proposal_decision, &proposal.parameters);
+            Self::slash_and_unstake(proposal.staking_account_id.clone(), slash_balance);
+        }
 
-    // Performs all actions on proposal finalization:
-    // - clean active proposal cache
-    // - update proposal status fields (status, finalized_at)
-    // - add to pending execution proposal cache if approved
-    // - slash and unstake proposal stake if stake exists
-    // - decrease active proposal counter
-    // - fire an event
-    // It prints an error message in case of an attempt to finalize the non-active proposal.
-    fn finalize_proposal(proposal_id: T::ProposalId, decision_status: ProposalDecisionStatus) {
-        Self::decrease_active_proposal_counter();
-        <ActiveProposalIds<T>>::remove(&proposal_id.clone());
+        // update approved proposal or remove otherwise
+        if let ProposalDecision::Approved(approved_proposal_decision) = proposal_decision {
+            let now = Self::current_block();
 
-        let mut proposal = Self::proposals(proposal_id);
+            let mut finalized_proposal = proposal;
 
-        if let ProposalStatus::Active(active_stake) = proposal.status.clone() {
-            if let ProposalDecisionStatus::Approved { .. } = decision_status {
-                <PendingExecutionProposalIds<T>>::insert(proposal_id, ());
-            }
-
-            // deal with stakes if necessary
-            let slash_balance =
-                Self::calculate_slash_balance(&decision_status, &proposal.parameters);
-            let slash_and_unstake_result =
-                Self::slash_and_unstake(active_stake.clone(), slash_balance);
-
-            // create finalized proposal status with error if any
-            let new_proposal_status = ProposalStatus::finalized(
-                decision_status,
-                slash_and_unstake_result.err(),
-                active_stake,
-                Self::current_block(),
-            );
-
-            proposal.status = new_proposal_status.clone();
-            <Proposals<T>>::insert(proposal_id, proposal);
+            finalized_proposal.increase_constitutionality_level();
+            finalized_proposal.status = ProposalStatus::approved(approved_proposal_decision, now);
 
+            // fire the proposal status update event
             Self::deposit_event(RawEvent::ProposalStatusUpdated(
                 proposal_id,
-                new_proposal_status,
+                finalized_proposal.status.clone(),
             ));
+
+            // immediately execute proposal if it ready for execution or save it for the future otherwise.
+            if finalized_proposal.is_ready_for_execution(now) {
+                Self::execute_proposal(proposal_id);
+            } else {
+                <Proposals<T>>::insert(proposal_id, finalized_proposal);
+            }
         } else {
-            print("Broken invariant: proposal cannot be non-active during the finalisation");
+            Self::remove_proposal_data(&proposal_id);
         }
     }
 
-    // Slashes the stake and perform unstake only in case of existing stake
-    fn slash_and_unstake(
-        current_stake_data: Option<ActiveStake<T::StakeId, T::AccountId>>,
-        slash_balance: BalanceOf<T>,
-    ) -> Result<(), &'static str> {
+    // Slashes the stake and perform unstake only in case of existing stake.
+    fn slash_and_unstake(staking_account_id: Option<T::AccountId>, slash_balance: BalanceOf<T>) {
         // only if stake exists
-        if let Some(stake_data) = current_stake_data {
+        if let Some(staking_account_id) = staking_account_id {
             if !slash_balance.is_zero() {
-                ProposalStakeManager::<T>::slash(stake_data.stake_id, slash_balance)?;
+                T::StakingHandler::slash(&staking_account_id, Some(slash_balance));
             }
 
-            ProposalStakeManager::<T>::remove_stake(stake_data.stake_id)?;
+            T::StakingHandler::unlock(&staking_account_id);
         }
-
-        Ok(())
     }
 
     // Calculates required slash based on finalization ProposalDecisionStatus and proposal parameters.
     // Method visibility allows testing.
     pub(crate) fn calculate_slash_balance(
-        decision_status: &ProposalDecisionStatus,
-        proposal_parameters: &ProposalParameters<T::BlockNumber, types::BalanceOf<T>>,
-    ) -> types::BalanceOf<T> {
-        match decision_status {
-            ProposalDecisionStatus::Rejected | ProposalDecisionStatus::Expired => {
-                T::RejectionFee::get()
-            }
-            ProposalDecisionStatus::Approved { .. } | ProposalDecisionStatus::Vetoed => {
-                BalanceOf::<T>::zero()
-            }
-            ProposalDecisionStatus::Canceled => T::CancellationFee::get(),
-            ProposalDecisionStatus::Slashed => proposal_parameters
+        proposal_decision: &ProposalDecision,
+        proposal_parameters: &ProposalParameters<T::BlockNumber, BalanceOf<T>>,
+    ) -> BalanceOf<T> {
+        match proposal_decision {
+            ProposalDecision::Rejected | ProposalDecision::Expired => T::RejectionFee::get(),
+            ProposalDecision::Approved { .. } | ProposalDecision::Vetoed => BalanceOf::<T>::zero(),
+            ProposalDecision::Canceled => T::CancellationFee::get(),
+            ProposalDecision::Slashed => proposal_parameters
                 .required_stake
                 .clone()
                 .unwrap_or_else(BalanceOf::<T>::zero), // stake if set or zero
         }
     }
 
-    // Enumerates approved proposals and checks their grace period expiration
-    fn get_approved_proposal_with_expired_grace_period() -> Vec<ApprovedProposal<T>> {
-        <PendingExecutionProposalIds<T>>::iter()
-            .filter_map(|(proposal_id, _)| {
-                let proposal = Self::proposals(proposal_id);
-
-                if proposal.is_grace_period_expired(Self::current_block()) {
-                    // this should be true, because it was tested inside is_grace_period_expired()
-                    if let ProposalStatus::Finalized(finalisation_data) = proposal.status.clone() {
-                        Some(ApprovedProposalData {
-                            proposal_id,
-                            proposal,
-                            finalisation_status_data: finalisation_data,
-                        })
-                    } else {
-                        None
-                    }
-                } else {
-                    None
-                }
-            })
-            .collect()
-    }
-
     // Increases active proposal counter.
     fn increase_active_proposal_counter() {
         let next_active_proposal_count_value = Self::active_proposal_count() + 1;
@@ -814,33 +752,46 @@ impl<T: Trait> Module<T> {
             } => msg.unwrap_or("Dispatch error."),
         }
     }
-}
 
-// Simplification of the 'FinalizedProposalData' type
-type FinalizedProposal<T> = FinalizedProposalData<
-    <T as Trait>::ProposalId,
-    <T as frame_system::Trait>::BlockNumber,
-    MemberId<T>,
-    types::BalanceOf<T>,
-    <T as stake::Trait>::StakeId,
-    <T as frame_system::Trait>::AccountId,
->;
-
-// Simplification of the 'ApprovedProposalData' type
-type ApprovedProposal<T> = ApprovedProposalData<
-    <T as Trait>::ProposalId,
-    <T as frame_system::Trait>::BlockNumber,
-    MemberId<T>,
-    types::BalanceOf<T>,
-    <T as stake::Trait>::StakeId,
-    <T as frame_system::Trait>::AccountId,
->;
-
-// Simplification of the 'Proposal' type
-type ProposalOf<T> = Proposal<
-    <T as frame_system::Trait>::BlockNumber,
-    MemberId<T>,
-    types::BalanceOf<T>,
-    <T as stake::Trait>::StakeId,
-    <T as frame_system::Trait>::AccountId,
->;
+    // Clean proposal data. Remove proposal, votes from the storage.
+    fn remove_proposal_data(proposal_id: &T::ProposalId) {
+        <Proposals<T>>::remove(proposal_id);
+        <DispatchableCallCode<T>>::remove(proposal_id);
+        <VoteExistsByProposalByVoter<T>>::remove_prefix(&proposal_id);
+
+        Self::decrease_active_proposal_counter();
+
+        T::ProposalObserver::proposal_removed(proposal_id);
+    }
+
+    /// Perform voting period check, vote result tally, approved proposals
+    /// grace period checks, and proposal execution.
+    fn process_proposals() {
+        // Collect all proposals.
+        let proposals = <Proposals<T>>::iter().collect::<Vec<_>>();
+        let now = Self::current_block();
+
+        for (proposal_id, proposal) in proposals {
+            match proposal.status {
+                // Try to determine a decision for an active proposal.
+                ProposalStatus::Active => {
+                    let decision_status = proposal
+                        .define_proposal_decision(T::TotalVotersCounter::total_voters_count(), now);
+
+                    // If decision is calculated for a proposal - finalize it.
+                    if let Some(decision_status) = decision_status {
+                        Self::finalize_proposal(proposal_id, proposal, decision_status);
+                    }
+                }
+                // Execute the proposal code if the proposal is ready for execution.
+                ProposalStatus::PendingExecution(_) => {
+                    if proposal.is_ready_for_execution(now) {
+                        Self::execute_proposal(proposal_id);
+                    }
+                }
+                // Skip the proposal until it gets reactivated.
+                ProposalStatus::PendingConstitutionality => {}
+            }
+        }
+    }
+}

+ 0 - 33
runtime-modules/proposals/engine/src/tests/mock/balance_manager.rs

@@ -1,33 +0,0 @@
-#![cfg(test)]
-
-use frame_support::traits::{Currency, Imbalance};
-pub use sp_arithmetic::traits::Zero;
-
-use super::*;
-
-/// StakingEventsHandler implementation for the stake::Trait. Restores balances after the unstaking
-/// and slashes balances if necessary.
-pub struct BalanceManagerStakingEventsHandler;
-impl stake::StakingEventsHandler<Test> for BalanceManagerStakingEventsHandler {
-    fn unstaked(
-        _id: &u64,
-        _unstaked_amount: stake::BalanceOf<Test>,
-        imbalance: stake::NegativeImbalance<Test>,
-    ) -> stake::NegativeImbalance<Test> {
-        let default_account_id = 1;
-
-        <Test as stake::Trait>::Currency::resolve_creating(&default_account_id, imbalance);
-
-        stake::NegativeImbalance::<Test>::zero()
-    }
-
-    fn slashed(
-        _id: &u64,
-        _slash_id: Option<<Test as stake::Trait>::SlashId>,
-        _slashed_amount: stake::BalanceOf<Test>,
-        _remaining_stake: stake::BalanceOf<Test>,
-        imbalance: stake::NegativeImbalance<Test>,
-    ) -> stake::NegativeImbalance<Test> {
-        imbalance
-    }
-}

+ 10 - 15
runtime-modules/proposals/engine/src/tests/mock/mod.rs

@@ -1,13 +1,12 @@
 //! Mock runtime for the module testing.
 //!
 //! Submodules:
-//! - stakes: contains support for mocking external 'stake' module
-//! - balance_restorator: restores balances after unstaking
 //! - proposals: provides types for proposal execution tests
 //!
 
 #![cfg(test)]
 
+use frame_support::traits::LockIdentifier;
 use frame_support::{impl_outer_event, impl_outer_origin, parameter_types};
 pub use frame_system;
 use sp_core::H256;
@@ -17,13 +16,11 @@ use sp_runtime::{
     Perbill,
 };
 
-mod balance_manager;
 pub(crate) mod proposals;
-mod stakes;
+pub(crate) mod staking_handler;
 
-use balance_manager::*;
+use crate::ProposalObserver;
 pub use proposals::*;
-pub use stakes::*;
 
 // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
 #[derive(Clone, PartialEq, Eq, Debug)]
@@ -70,20 +67,13 @@ impl common::currency::GovernanceCurrency for Test {
 
 impl proposals::Trait for Test {}
 
-impl stake::Trait for Test {
-    type Currency = Balances;
-    type StakePoolId = StakePoolId;
-    type StakingEventsHandler = BalanceManagerStakingEventsHandler;
-    type StakeId = u64;
-    type SlashId = u64;
-}
-
 parameter_types! {
     pub const CancellationFee: u64 = 5;
     pub const RejectionFee: u64 = 3;
     pub const TitleMaxLength: u32 = 100;
     pub const DescriptionMaxLength: u32 = 10000;
     pub const MaxActiveProposalLimit: u32 = 100;
+    pub const LockId: LockIdentifier = [1; 8];
 }
 
 impl membership::Trait for Test {
@@ -100,13 +90,18 @@ impl crate::Trait for Test {
     type VoterOriginValidator = ();
     type TotalVotersCounter = ();
     type ProposalId = u32;
-    type StakeHandlerProvider = stakes::TestStakeHandlerProvider;
+    type StakingHandler = staking_handler::StakingManager<Test, LockId>;
     type CancellationFee = CancellationFee;
     type RejectionFee = RejectionFee;
     type TitleMaxLength = TitleMaxLength;
     type DescriptionMaxLength = DescriptionMaxLength;
     type MaxActiveProposalLimit = MaxActiveProposalLimit;
     type DispatchableCallCode = proposals::Call<Test>;
+    type ProposalObserver = ();
+}
+
+impl ProposalObserver<Test> for () {
+    fn proposal_removed(_proposal_id: &u32) {}
 }
 
 impl Default for proposals::Call<Test> {

+ 0 - 66
runtime-modules/proposals/engine/src/tests/mock/stakes.rs

@@ -1,66 +0,0 @@
-#![cfg(test)]
-
-use sp_std::marker::PhantomData;
-use std::cell::RefCell;
-use std::panic;
-use std::rc::Rc;
-
-use super::Test;
-
-// Intercepts panic method
-// Returns: whether panic occurred
-pub(crate) fn panics<F: std::panic::RefUnwindSafe + Fn()>(could_panic_func: F) -> bool {
-    {
-        let default_hook = panic::take_hook();
-        panic::set_hook(Box::new(|info| {
-            println!("{}", info);
-        }));
-
-        // intercept panic
-        let result = panic::catch_unwind(|| could_panic_func());
-
-        //restore default behaviour
-        panic::set_hook(default_hook);
-
-        result.is_err()
-    }
-}
-
-// Test StakeHandlerProvider implementation based on local thread static variables
-pub struct TestStakeHandlerProvider;
-impl crate::StakeHandlerProvider<Test> for TestStakeHandlerProvider {
-    /// Returns StakeHandler. Mock entry point for stake module.
-    fn stakes() -> Rc<dyn crate::StakeHandler<Test>> {
-        THREAD_LOCAL_STAKE_HANDLER.with(|f| f.borrow().clone())
-    }
-}
-
-// 1. RefCell - thread_local! mutation pattern
-// 2. Rc - ability to have multiple references
-thread_local! {
-    pub static THREAD_LOCAL_STAKE_HANDLER:
-      RefCell<Rc<dyn crate::StakeHandler<Test>>> = RefCell::new(Rc::new(crate::types::DefaultStakeHandler{marker: PhantomData::<Test>}));
-}
-
-// Sets stake handler implementation. Mockall framework integration.
-pub(crate) fn set_stake_handler_impl(mock: Rc<dyn crate::StakeHandler<Test>>) {
-    THREAD_LOCAL_STAKE_HANDLER.with(|f| {
-        *f.borrow_mut() = mock.clone();
-    });
-}
-
-// Tests mock expectation and restores default behaviour
-pub(crate) fn test_expectation_and_clear_mock() {
-    set_stake_handler_impl(Rc::new(crate::types::DefaultStakeHandler {
-        marker: PhantomData::<Test>,
-    }));
-}
-
-// Intercepts panic in provided function, test mock expectation and restores default behaviour
-pub(crate) fn handle_mock<F: std::panic::RefUnwindSafe + Fn()>(func: F) {
-    let panicked = panics(func);
-
-    test_expectation_and_clear_mock();
-
-    assert!(!panicked);
-}

+ 98 - 0
runtime-modules/proposals/engine/src/tests/mock/staking_handler.rs

@@ -0,0 +1,98 @@
+use frame_support::dispatch::{DispatchError, DispatchResult};
+use frame_support::traits::{Currency, Get, LockIdentifier, LockableCurrency, WithdrawReasons};
+use membership::staking_handler::{BalanceOf, MemberId, StakingHandler};
+use sp_arithmetic::traits::Zero;
+use sp_std::marker::PhantomData;
+
+/// Implementation of the StakingHandler.
+pub struct StakingManager<
+    T: frame_system::Trait + membership::Trait + balances::Trait,
+    LockId: Get<LockIdentifier>,
+> {
+    trait_marker: PhantomData<T>,
+    lock_id_marker: PhantomData<LockId>,
+}
+
+impl<T: frame_system::Trait + membership::Trait + balances::Trait, LockId: Get<LockIdentifier>>
+    StakingHandler<T> for StakingManager<T, LockId>
+{
+    fn lock(account_id: &T::AccountId, amount: BalanceOf<T>) {
+        <balances::Module<T>>::set_lock(LockId::get(), &account_id, amount, WithdrawReasons::all())
+    }
+
+    fn unlock(account_id: &T::AccountId) {
+        T::Currency::remove_lock(LockId::get(), &account_id);
+    }
+
+    fn slash(account_id: &T::AccountId, amount: Option<BalanceOf<T>>) -> BalanceOf<T> {
+        let locks = <balances::Module<T>>::locks(&account_id);
+
+        let existing_lock = locks.iter().find(|lock| lock.id == LockId::get());
+
+        let mut actually_slashed_balance = Default::default();
+        if let Some(existing_lock) = existing_lock {
+            Self::unlock(&account_id);
+
+            let mut slashable_amount = existing_lock.amount;
+            if let Some(amount) = amount {
+                if existing_lock.amount > amount {
+                    let new_amount = existing_lock.amount - amount;
+                    Self::lock(&account_id, new_amount);
+
+                    slashable_amount = amount;
+                }
+            }
+
+            let _ = <balances::Module<T>>::slash(&account_id, slashable_amount);
+
+            actually_slashed_balance = slashable_amount
+        }
+
+        actually_slashed_balance
+    }
+
+    fn set_stake(account_id: &T::AccountId, new_stake: BalanceOf<T>) -> DispatchResult {
+        let current_stake = Self::current_stake(account_id);
+
+        //Unlock previous stake if its not zero.
+        if current_stake > Zero::zero() {
+            Self::unlock(account_id);
+        }
+
+        if !Self::is_enough_balance_for_stake(account_id, new_stake) {
+            //Restore previous stake if its not zero.
+            if current_stake > Zero::zero() {
+                Self::lock(account_id, current_stake);
+            }
+            return Err(DispatchError::Other("Not enough balance for a new stake."));
+        }
+
+        Self::lock(account_id, new_stake);
+
+        Ok(())
+    }
+
+    fn is_member_staking_account(_member_id: &MemberId<T>, _account_id: &T::AccountId) -> bool {
+        true
+    }
+
+    fn is_account_free_of_conflicting_stakes(account_id: &T::AccountId) -> bool {
+        let locks = <balances::Module<T>>::locks(&account_id);
+
+        let existing_lock = locks.iter().find(|lock| lock.id == LockId::get());
+
+        existing_lock.is_none()
+    }
+
+    fn is_enough_balance_for_stake(account_id: &T::AccountId, amount: BalanceOf<T>) -> bool {
+        <balances::Module<T>>::usable_balance(account_id) >= amount
+    }
+
+    fn current_stake(account_id: &T::AccountId) -> BalanceOf<T> {
+        let locks = <balances::Module<T>>::locks(&account_id);
+
+        let existing_lock = locks.iter().find(|lock| lock.id == LockId::get());
+
+        existing_lock.map_or(Zero::zero(), |lock| lock.amount)
+    }
+}

Разлика између датотеке није приказан због своје велике величине
+ 300 - 322
runtime-modules/proposals/engine/src/tests/mod.rs


+ 157 - 529
runtime-modules/proposals/engine/src/types/mod.rs

@@ -5,7 +5,6 @@
 
 use codec::{Decode, Encode};
 use frame_support::dispatch::DispatchResult;
-use frame_support::traits::Currency;
 #[cfg(feature = "std")]
 use serde::{Deserialize, Serialize};
 use sp_runtime::Perbill;
@@ -15,19 +14,10 @@ use sp_std::ops::Add;
 use sp_std::vec::Vec;
 
 mod proposal_statuses;
-mod stakes;
 
 pub use proposal_statuses::{
-    ApprovedProposalStatus, FinalizationData, ProposalDecisionStatus, ProposalStatus,
+    ApprovedProposalDecision, ExecutionStatus, ProposalDecision, ProposalStatus,
 };
-pub(crate) use stakes::ProposalStakeManager;
-pub use stakes::{DefaultStakeHandlerProvider, StakeHandler, StakeHandlerProvider};
-
-#[cfg(test)]
-pub(crate) use stakes::DefaultStakeHandler;
-
-#[cfg(test)]
-pub(crate) use stakes::MockStakeHandler;
 
 /// Vote kind for the proposal. Sum of all votes defines proposal status.
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
@@ -78,6 +68,10 @@ pub struct ProposalParameters<BlockNumber, Balance> {
 
     /// Proposal stake
     pub required_stake: Option<Balance>,
+
+    /// The number of councils in that must approve the proposal in a row before it has its
+    /// intended effect. Integer no less than 1.
+    pub constitutionality: u32,
 }
 
 /// Contains current voting results
@@ -112,80 +106,96 @@ impl VotingResults {
     pub fn votes_number(&self) -> u32 {
         self.abstentions + self.approvals + self.rejections + self.slashes
     }
-}
 
-/// Contains created stake id and source account for the stake balance
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Default, Clone, Copy, PartialEq, Eq, Debug)]
-pub struct ActiveStake<StakeId, AccountId> {
-    /// Created stake id for the proposal
-    pub stake_id: StakeId,
-
-    /// Source account of the stake balance. Refund if any will be provided using this account
-    pub source_account_id: AccountId,
+    /// Returns True if there were no votes. False otherwise.
+    pub fn no_votes_yet(&self) -> bool {
+        self.votes_number() == 0
+    }
 }
 
 /// 'Proposal' contains information necessary for the proposal system functioning.
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
-pub struct Proposal<BlockNumber, ProposerId, Balance, StakeId, AccountId> {
+pub struct Proposal<BlockNumber, ProposerId, Balance, AccountId> {
     /// Proposals parameter, characterize different proposal types.
     pub parameters: ProposalParameters<BlockNumber, Balance>,
 
     /// Identifier of member proposing.
     pub proposer_id: ProposerId,
 
-    /// Proposal description
-    pub title: Vec<u8>,
-
-    /// Proposal body
-    pub description: Vec<u8>,
-
-    /// When it was created.
-    pub created_at: BlockNumber,
+    /// It contains the block number when it was first created or the beginning of a new council
+    /// where the proposal was automatically activated due to constitutionality.
+    pub activated_at: BlockNumber,
 
     /// Current proposal status
-    pub status: ProposalStatus<BlockNumber, StakeId, AccountId>,
+    pub status: ProposalStatus<BlockNumber>,
 
     /// Curring voting result for the proposal
     pub voting_results: VotingResults,
+
+    /// Optional exact block height which triggers the execution.
+    pub exact_execution_block: Option<BlockNumber>,
+
+    /// The number of councils in that must approve the proposal in a row before it has its
+    /// intended effect.
+    pub current_constitutionality_level: u32,
+
+    /// Optional account id for staking.
+    pub staking_account_id: Option<AccountId>,
 }
 
-impl<BlockNumber, ProposerId, Balance, StakeId, AccountId>
-    Proposal<BlockNumber, ProposerId, Balance, StakeId, AccountId>
+impl<BlockNumber, ProposerId, Balance, AccountId>
+    Proposal<BlockNumber, ProposerId, Balance, AccountId>
 where
     BlockNumber: Add<Output = BlockNumber> + PartialOrd + Copy,
-    StakeId: Clone,
     AccountId: Clone,
 {
+    /// Increases proposal constitutionality level.
+    pub fn increase_constitutionality_level(&mut self) {
+        self.current_constitutionality_level += 1;
+    }
+
     /// Returns whether voting period expired by now
     pub fn is_voting_period_expired(&self, now: BlockNumber) -> bool {
-        now >= self.created_at + self.parameters.voting_period
+        now >= self.activated_at + self.parameters.voting_period
     }
 
     /// Returns whether grace period expired by now.
     /// Grace period can be expired only if proposal is finalized with Approved status.
     /// Returns false otherwise.
     pub fn is_grace_period_expired(&self, now: BlockNumber) -> bool {
-        if let ProposalStatus::Finalized(finalized_status) = self.status.clone() {
-            if let ProposalDecisionStatus::Approved(_) = finalized_status.proposal_status {
-                return now >= finalized_status.finalized_at + self.parameters.grace_period;
-            }
+        if let ProposalStatus::PendingExecution(finalized_at) = self.status.clone() {
+            return now >= finalized_at + self.parameters.grace_period;
         }
 
         false
     }
 
+    /// Returns whether the proposal is ready for execution by now.
+    /// It compares grace period and exact execution block with the current block.
+    pub fn is_ready_for_execution(&self, now: BlockNumber) -> bool {
+        self.is_grace_period_expired(now) && self.is_execution_block_reached_or_not_set(now)
+    }
+
+    /// Returns whether exact execution block reached by now.
+    /// If not set returns True.
+    /// Returns False otherwise.
+    pub fn is_execution_block_reached_or_not_set(&self, now: BlockNumber) -> bool {
+        self.exact_execution_block
+            .map(|block_number| block_number <= now)
+            .unwrap_or(true)
+    }
+
     /// Determines the finalized proposal status using voting results tally for current proposal.
     /// Calculates votes, takes in account voting period expiration.
     /// If voting process is in progress, then decision status is None.
     /// Parameters: current time, total voters number involved (council size).
     /// Returns the proposal finalized status if any.
-    pub fn define_proposal_decision_status(
+    pub fn define_proposal_decision(
         &self,
         total_voters_count: u32,
         now: BlockNumber,
-    ) -> Option<ProposalDecisionStatus> {
+    ) -> Option<ProposalDecision> {
         let proposal_status_resolution = ProposalStatusResolution {
             proposal: self,
             approvals: self.voting_results.approvals,
@@ -198,17 +208,24 @@ where
         if proposal_status_resolution.is_approval_quorum_reached()
             && proposal_status_resolution.is_approval_threshold_reached()
         {
-            Some(ProposalDecisionStatus::Approved(
-                ApprovedProposalStatus::PendingExecution,
-            ))
+            let approved_status =
+                if proposal_status_resolution.is_constitutionality_reached_on_approval() {
+                    ApprovedProposalDecision::PendingExecution
+                } else {
+                    ApprovedProposalDecision::PendingConstitutionality
+                };
+
+            Some(ProposalDecision::Approved(approved_status))
         } else if proposal_status_resolution.is_slashing_quorum_reached()
             && proposal_status_resolution.is_slashing_threshold_reached()
         {
-            Some(ProposalDecisionStatus::Slashed)
+            Some(ProposalDecision::Slashed)
+        } else if proposal_status_resolution.is_rejection_imminent() {
+            Some(ProposalDecision::Rejected)
         } else if proposal_status_resolution.is_expired() {
-            Some(ProposalDecisionStatus::Expired)
+            Some(ProposalDecision::Expired)
         } else if proposal_status_resolution.is_voting_completed() {
-            Some(ProposalDecisionStatus::Rejected)
+            Some(ProposalDecision::Rejected)
         } else {
             None
         }
@@ -216,8 +233,8 @@ where
 
     /// Reset the proposal in Active status. Proposal with other status won't be changed.
     /// Reset proposal operation clears voting results.
-    pub fn reset_proposal(&mut self) {
-        if let ProposalStatus::Active(_) = self.status.clone() {
+    pub fn reset_proposal_votes(&mut self) {
+        if self.status == ProposalStatus::Active {
             self.voting_results = VotingResults::default();
         }
     }
@@ -230,20 +247,25 @@ pub trait VotersParameters {
 }
 
 // Calculates quorum, votes threshold, expiration status
-struct ProposalStatusResolution<'a, BlockNumber, ProposerId, Balance, StakeId, AccountId> {
-    proposal: &'a Proposal<BlockNumber, ProposerId, Balance, StakeId, AccountId>,
-    now: BlockNumber,
-    votes_count: u32,
-    total_voters_count: u32,
-    approvals: u32,
-    slashes: u32,
+pub(crate) struct ProposalStatusResolution<'a, BlockNumber, ProposerId, Balance, AccountId> {
+    /// Proposal data
+    pub proposal: &'a Proposal<BlockNumber, ProposerId, Balance, AccountId>,
+    /// Current block
+    pub now: BlockNumber,
+    /// Total votes number so far
+    pub votes_count: u32,
+    /// Council size
+    pub total_voters_count: u32,
+    /// Approval votes number
+    pub approvals: u32,
+    /// Slash votes number
+    pub slashes: u32,
 }
 
-impl<'a, BlockNumber, ProposerId, Balance, StakeId, AccountId>
-    ProposalStatusResolution<'a, BlockNumber, ProposerId, Balance, StakeId, AccountId>
+impl<'a, BlockNumber, ProposerId, Balance, AccountId>
+    ProposalStatusResolution<'a, BlockNumber, ProposerId, Balance, AccountId>
 where
     BlockNumber: Add<Output = BlockNumber> + PartialOrd + Copy,
-    StakeId: Clone,
     AccountId: Clone,
 {
     // Proposal has been expired and quorum not reached.
@@ -252,8 +274,8 @@ where
     }
 
     // Approval quorum reached for the proposal. Compares predefined parameter with actual
-    // votes sum divided by total possible votes count.
-    pub fn is_approval_quorum_reached(&self) -> bool {
+    // votes sum divided by total possible votes number.
+    pub(crate) fn is_approval_quorum_reached(&self) -> bool {
         let actual_votes_fraction =
             Perbill::from_rational_approximation(self.votes_count, self.total_voters_count);
         let approval_quorum_fraction =
@@ -262,8 +284,43 @@ where
         actual_votes_fraction.deconstruct() >= approval_quorum_fraction.deconstruct()
     }
 
+    // Verifies that approval threshold is still achievable for the proposal.
+    // Compares actual approval votes sum with remaining possible votes number.
+    pub(crate) fn is_approval_threshold_achievable(&self) -> bool {
+        let remaining_votes_count = self.total_voters_count - self.votes_count;
+        let possible_approval_votes_fraction = Perbill::from_rational_approximation(
+            self.approvals + remaining_votes_count,
+            self.votes_count + remaining_votes_count,
+        );
+
+        let required_threshold_fraction =
+            Perbill::from_percent(self.proposal.parameters.approval_threshold_percentage);
+
+        possible_approval_votes_fraction.deconstruct() >= required_threshold_fraction.deconstruct()
+    }
+
+    // Verifies that both approval and slashing thresholds cannot be achieved.
+    pub fn is_rejection_imminent(&self) -> bool {
+        !self.is_approval_threshold_achievable() && !self.is_slashing_threshold_achievable()
+    }
+
+    // Verifies that slashing threshold is still achievable for the proposal.
+    // Compares actual slashing votes sum with remaining possible votes number.
+    pub(crate) fn is_slashing_threshold_achievable(&self) -> bool {
+        let remaining_votes_count = self.total_voters_count - self.votes_count;
+        let possible_slashing_votes_fraction = Perbill::from_rational_approximation(
+            self.slashes + remaining_votes_count,
+            self.votes_count + remaining_votes_count,
+        );
+
+        let required_threshold_fraction =
+            Perbill::from_percent(self.proposal.parameters.slashing_threshold_percentage);
+
+        possible_slashing_votes_fraction.deconstruct() >= required_threshold_fraction.deconstruct()
+    }
+
     // Slashing quorum reached for the proposal. Compares predefined parameter with actual
-    // votes sum divided by total possible votes count.
+    // votes sum divided by total possible votes number.
     pub fn is_slashing_quorum_reached(&self) -> bool {
         let actual_votes_fraction =
             Perbill::from_rational_approximation(self.votes_count, self.total_voters_count);
@@ -274,7 +331,7 @@ where
     }
 
     // Approval threshold reached for the proposal. Compares predefined parameter with 'approve'
-    // votes sum divided by actual votes count.
+    // votes sum divided by actual votes number.
     pub fn is_approval_threshold_reached(&self) -> bool {
         let approval_votes_fraction =
             Perbill::from_rational_approximation(self.approvals, self.votes_count);
@@ -299,6 +356,12 @@ where
     pub fn is_voting_completed(&self) -> bool {
         self.votes_count == self.total_voters_count
     }
+
+    // Council approved the proposal enough times.
+    pub fn is_constitutionality_reached_on_approval(&self) -> bool {
+        self.proposal.current_constitutionality_level + 1
+            >= self.proposal.parameters.constitutionality
+    }
 }
 
 /// Proposal executable code wrapper
@@ -316,479 +379,44 @@ pub trait ProposalCodeDecoder<T: frame_system::Trait> {
     ) -> Result<Box<dyn ProposalExecutable>, &'static str>;
 }
 
-/// Balance alias
-pub type BalanceOf<T> =
-    <<T as stake::Trait>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::Balance;
-
-/// Balance alias for staking
-pub type NegativeImbalance<T> = <<T as stake::Trait>::Currency as Currency<
-    <T as frame_system::Trait>::AccountId,
->>::NegativeImbalance;
-
-/// Balance type of runtime
-pub type CurrencyOf<T> = <T as stake::Trait>::Currency;
-
-/// Data container for the finalized proposal results
-pub(crate) struct FinalizedProposalData<
-    ProposalId,
-    BlockNumber,
-    ProposerId,
-    Balance,
-    StakeId,
-    AccountId,
-> {
-    /// Proposal id
-    pub proposal_id: ProposalId,
-
-    /// Proposal to be finalized
-    pub proposal: Proposal<BlockNumber, ProposerId, Balance, StakeId, AccountId>,
-
-    /// Proposal finalization status
-    pub status: ProposalDecisionStatus,
-
-    /// Proposal finalization block number
-    pub finalized_at: BlockNumber,
-}
-
-/// Data container for the approved proposal results
-pub(crate) struct ApprovedProposalData<
-    ProposalId,
-    BlockNumber,
-    ProposerId,
-    Balance,
-    StakeId,
-    AccountId,
-> {
-    /// Proposal id
-    pub proposal_id: ProposalId,
-
-    /// Proposal to be finalized
-    pub proposal: Proposal<BlockNumber, ProposerId, Balance, StakeId, AccountId>,
-
-    /// Proposal finalisation status data
-    pub finalisation_status_data: FinalizationData<BlockNumber, StakeId, AccountId>,
-}
-
-#[cfg(test)]
-mod tests {
-    use crate::types::ProposalStatusResolution;
-    use crate::*;
-
-    // Alias introduced for simplicity of changing Proposal exact types.
-    type ProposalObject = Proposal<u64, u64, u64, u64, u64>;
-
-    #[test]
-    fn proposal_voting_period_expired() {
-        let mut proposal = ProposalObject::default();
-
-        proposal.created_at = 1;
-        proposal.parameters.voting_period = 3;
-
-        assert!(proposal.is_voting_period_expired(4));
-    }
-
-    #[test]
-    fn proposal_voting_period_not_expired() {
-        let mut proposal = ProposalObject::default();
-
-        proposal.created_at = 1;
-        proposal.parameters.voting_period = 3;
-
-        assert!(!proposal.is_voting_period_expired(3));
-    }
-
-    #[test]
-    fn proposal_grace_period_expired() {
-        let mut proposal = ProposalObject::default();
-
-        proposal.parameters.grace_period = 3;
-        proposal.status = ProposalStatus::finalized_successfully(
-            ProposalDecisionStatus::Approved(ApprovedProposalStatus::PendingExecution),
-            0,
-        );
-
-        assert!(proposal.is_grace_period_expired(4));
-    }
-
-    #[test]
-    fn proposal_grace_period_auto_expired() {
-        let mut proposal = ProposalObject::default();
-
-        proposal.parameters.grace_period = 0;
-        proposal.status = ProposalStatus::finalized_successfully(
-            ProposalDecisionStatus::Approved(ApprovedProposalStatus::PendingExecution),
-            0,
-        );
-
-        assert!(proposal.is_grace_period_expired(1));
-    }
-
-    #[test]
-    fn proposal_grace_period_not_expired() {
-        let mut proposal = ProposalObject::default();
-
-        proposal.parameters.grace_period = 3;
+/// Containter-type for a proposal creation method.
+pub struct ProposalCreationParameters<BlockNumber, Balance, MemberId, AccountId> {
+    /// Account id of the proposer.
+    pub account_id: AccountId,
 
-        assert!(!proposal.is_grace_period_expired(3));
-    }
-
-    #[test]
-    fn proposal_grace_period_not_expired_because_of_not_approved_proposal() {
-        let mut proposal = ProposalObject::default();
-
-        proposal.parameters.grace_period = 3;
-
-        assert!(!proposal.is_grace_period_expired(3));
-    }
-
-    #[test]
-    fn define_proposal_decision_status_returns_expired() {
-        let mut proposal = ProposalObject::default();
-        let now = 5;
-        proposal.created_at = 1;
-        proposal.parameters.voting_period = 3;
-        proposal.parameters.approval_quorum_percentage = 80;
-        proposal.parameters.approval_threshold_percentage = 40;
-        proposal.parameters.slashing_quorum_percentage = 50;
-        proposal.parameters.slashing_threshold_percentage = 50;
-
-        proposal.voting_results.add_vote(VoteKind::Reject);
-        proposal.voting_results.add_vote(VoteKind::Approve);
-        proposal.voting_results.add_vote(VoteKind::Approve);
-
-        assert_eq!(
-            proposal.voting_results,
-            VotingResults {
-                abstentions: 0,
-                approvals: 2,
-                rejections: 1,
-                slashes: 0,
-            }
-        );
-
-        let expected_proposal_status = proposal.define_proposal_decision_status(5, now);
-        assert_eq!(
-            expected_proposal_status,
-            Some(ProposalDecisionStatus::Expired)
-        );
-    }
-
-    #[test]
-    fn define_proposal_decision_status_returns_approved() {
-        let now = 2;
-        let mut proposal = ProposalObject::default();
-        proposal.created_at = 1;
-        proposal.parameters.voting_period = 3;
-        proposal.parameters.approval_quorum_percentage = 60;
-        proposal.parameters.slashing_quorum_percentage = 50;
-        proposal.parameters.slashing_threshold_percentage = 50;
-
-        proposal.voting_results.add_vote(VoteKind::Reject);
-        proposal.voting_results.add_vote(VoteKind::Approve);
-        proposal.voting_results.add_vote(VoteKind::Approve);
-        proposal.voting_results.add_vote(VoteKind::Approve);
-
-        assert_eq!(
-            proposal.voting_results,
-            VotingResults {
-                abstentions: 0,
-                approvals: 3,
-                rejections: 1,
-                slashes: 0,
-            }
-        );
+    /// Proposer member id.
+    pub proposer_id: MemberId,
 
-        let expected_proposal_status = proposal.define_proposal_decision_status(5, now);
-        assert_eq!(
-            expected_proposal_status,
-            Some(ProposalDecisionStatus::Approved(
-                ApprovedProposalStatus::PendingExecution
-            ))
-        );
-    }
+    /// Risk management proposal parameters.
+    pub proposal_parameters: ProposalParameters<BlockNumber, Balance>,
 
-    #[test]
-    fn define_proposal_decision_status_returns_rejected() {
-        let mut proposal = ProposalObject::default();
-        let now = 2;
-
-        proposal.created_at = 1;
-        proposal.parameters.voting_period = 3;
-        proposal.parameters.approval_quorum_percentage = 50;
-        proposal.parameters.approval_threshold_percentage = 51;
-        proposal.parameters.slashing_quorum_percentage = 50;
-        proposal.parameters.slashing_threshold_percentage = 50;
-
-        proposal.voting_results.add_vote(VoteKind::Reject);
-        proposal.voting_results.add_vote(VoteKind::Reject);
-        proposal.voting_results.add_vote(VoteKind::Abstain);
-        proposal.voting_results.add_vote(VoteKind::Approve);
-
-        assert_eq!(
-            proposal.voting_results,
-            VotingResults {
-                abstentions: 1,
-                approvals: 1,
-                rejections: 2,
-                slashes: 0,
-            }
-        );
-
-        let expected_proposal_status = proposal.define_proposal_decision_status(4, now);
-        assert_eq!(
-            expected_proposal_status,
-            Some(ProposalDecisionStatus::Rejected)
-        );
-    }
-
-    #[test]
-    fn define_proposal_decision_status_returns_slashed() {
-        let mut proposal = ProposalObject::default();
-        let now = 2;
-
-        proposal.created_at = 1;
-        proposal.parameters.voting_period = 3;
-        proposal.parameters.approval_quorum_percentage = 50;
-        proposal.parameters.approval_threshold_percentage = 50;
-        proposal.parameters.slashing_quorum_percentage = 50;
-        proposal.parameters.slashing_threshold_percentage = 50;
-
-        proposal.voting_results.add_vote(VoteKind::Slash);
-        proposal.voting_results.add_vote(VoteKind::Reject);
-        proposal.voting_results.add_vote(VoteKind::Abstain);
-        proposal.voting_results.add_vote(VoteKind::Slash);
-
-        assert_eq!(
-            proposal.voting_results,
-            VotingResults {
-                abstentions: 1,
-                approvals: 0,
-                rejections: 1,
-                slashes: 2,
-            }
-        );
-
-        let expected_proposal_status = proposal.define_proposal_decision_status(4, now);
-        assert_eq!(
-            expected_proposal_status,
-            Some(ProposalDecisionStatus::Slashed)
-        );
-    }
-
-    #[test]
-    fn define_proposal_decision_status_returns_none() {
-        let mut proposal = ProposalObject::default();
-        let now = 2;
-
-        proposal.created_at = 1;
-        proposal.parameters.voting_period = 3;
-        proposal.parameters.approval_quorum_percentage = 60;
-        proposal.parameters.slashing_quorum_percentage = 50;
-
-        proposal.voting_results.add_vote(VoteKind::Abstain);
-        assert_eq!(
-            proposal.voting_results,
-            VotingResults {
-                abstentions: 1,
-                approvals: 0,
-                rejections: 0,
-                slashes: 0,
-            }
-        );
-
-        let expected_proposal_status = proposal.define_proposal_decision_status(5, now);
-        assert_eq!(expected_proposal_status, None);
-    }
-
-    #[test]
-    fn define_proposal_decision_status_returns_approved_before_slashing_before_rejection() {
-        let mut proposal = ProposalObject::default();
-        let now = 2;
-
-        proposal.created_at = 1;
-        proposal.parameters.voting_period = 3;
-        proposal.parameters.approval_quorum_percentage = 50;
-        proposal.parameters.approval_threshold_percentage = 30;
-        proposal.parameters.slashing_quorum_percentage = 50;
-        proposal.parameters.slashing_threshold_percentage = 30;
-
-        proposal.voting_results.add_vote(VoteKind::Approve);
-        proposal.voting_results.add_vote(VoteKind::Approve);
-        proposal.voting_results.add_vote(VoteKind::Reject);
-        proposal.voting_results.add_vote(VoteKind::Reject);
-        proposal.voting_results.add_vote(VoteKind::Slash);
-        proposal.voting_results.add_vote(VoteKind::Slash);
-
-        assert_eq!(
-            proposal.voting_results,
-            VotingResults {
-                abstentions: 0,
-                approvals: 2,
-                rejections: 2,
-                slashes: 2,
-            }
-        );
-
-        let expected_proposal_status = proposal.define_proposal_decision_status(6, now);
-
-        assert_eq!(
-            expected_proposal_status,
-            Some(ProposalDecisionStatus::Approved(
-                ApprovedProposalStatus::PendingExecution
-            ))
-        );
-    }
-
-    #[test]
-    fn define_proposal_decision_status_returns_slashed_before_rejection() {
-        let mut proposal = ProposalObject::default();
-        let now = 2;
-
-        proposal.created_at = 1;
-        proposal.parameters.voting_period = 3;
-        proposal.parameters.approval_quorum_percentage = 50;
-        proposal.parameters.approval_threshold_percentage = 30;
-        proposal.parameters.slashing_quorum_percentage = 50;
-        proposal.parameters.slashing_threshold_percentage = 30;
-
-        proposal.voting_results.add_vote(VoteKind::Abstain);
-        proposal.voting_results.add_vote(VoteKind::Approve);
-        proposal.voting_results.add_vote(VoteKind::Reject);
-        proposal.voting_results.add_vote(VoteKind::Reject);
-        proposal.voting_results.add_vote(VoteKind::Slash);
-        proposal.voting_results.add_vote(VoteKind::Slash);
-
-        assert_eq!(
-            proposal.voting_results,
-            VotingResults {
-                abstentions: 1,
-                approvals: 1,
-                rejections: 2,
-                slashes: 2,
-            }
-        );
-
-        let expected_proposal_status = proposal.define_proposal_decision_status(6, now);
-
-        assert_eq!(
-            expected_proposal_status,
-            Some(ProposalDecisionStatus::Slashed)
-        );
-    }
-
-    #[test]
-    fn proposal_status_resolution_approval_quorum_works_correctly() {
-        let no_approval_quorum_proposal: Proposal<u64, u64, u64, u64, u64> = Proposal {
-            parameters: ProposalParameters {
-                approval_quorum_percentage: 63,
-                slashing_threshold_percentage: 63,
-                ..ProposalParameters::default()
-            },
-            ..Proposal::default()
-        };
-        let no_approval_proposal_status_resolution = ProposalStatusResolution {
-            proposal: &no_approval_quorum_proposal,
-            now: 20,
-            votes_count: 314,
-            total_voters_count: 500,
-            approvals: 3,
-            slashes: 3,
-        };
-
-        assert!(!no_approval_proposal_status_resolution.is_approval_quorum_reached());
-
-        let approval_quorum_proposal_status_resolution = ProposalStatusResolution {
-            votes_count: 315,
-            ..no_approval_proposal_status_resolution
-        };
-
-        assert!(approval_quorum_proposal_status_resolution.is_approval_quorum_reached());
-    }
-
-    #[test]
-    fn proposal_status_resolution_slashing_quorum_works_correctly() {
-        let no_slashing_quorum_proposal: Proposal<u64, u64, u64, u64, u64> = Proposal {
-            parameters: ProposalParameters {
-                approval_quorum_percentage: 63,
-                slashing_quorum_percentage: 63,
-                ..ProposalParameters::default()
-            },
-            ..Proposal::default()
-        };
-        let no_slashing_proposal_status_resolution = ProposalStatusResolution {
-            proposal: &no_slashing_quorum_proposal,
-            now: 20,
-            votes_count: 314,
-            total_voters_count: 500,
-            approvals: 3,
-            slashes: 3,
-        };
-
-        assert!(!no_slashing_proposal_status_resolution.is_slashing_quorum_reached());
-
-        let slashing_quorum_proposal_status_resolution = ProposalStatusResolution {
-            votes_count: 315,
-            ..no_slashing_proposal_status_resolution
-        };
-
-        assert!(slashing_quorum_proposal_status_resolution.is_slashing_quorum_reached());
-    }
+    /// Proposal title.
+    pub title: Vec<u8>,
 
-    #[test]
-    fn proposal_status_resolution_approval_threshold_works_correctly() {
-        let no_approval_threshold_proposal: Proposal<u64, u64, u64, u64, u64> = Proposal {
-            parameters: ProposalParameters {
-                slashing_threshold_percentage: 63,
-                approval_threshold_percentage: 63,
-                ..ProposalParameters::default()
-            },
-            ..Proposal::default()
-        };
-        let no_approval_proposal_status_resolution = ProposalStatusResolution {
-            proposal: &no_approval_threshold_proposal,
-            now: 20,
-            votes_count: 500,
-            total_voters_count: 600,
-            approvals: 314,
-            slashes: 3,
-        };
+    /// Proposal description.
+    pub description: Vec<u8>,
 
-        assert!(!no_approval_proposal_status_resolution.is_approval_threshold_reached());
+    /// Staking account for the proposal.
+    pub staking_account_id: Option<AccountId>,
 
-        let approval_threshold_proposal_status_resolution = ProposalStatusResolution {
-            approvals: 315,
-            ..no_approval_proposal_status_resolution
-        };
+    /// Encoded executable proposal code.
+    pub encoded_dispatchable_call_code: Vec<u8>,
 
-        assert!(approval_threshold_proposal_status_resolution.is_approval_threshold_reached());
-    }
-
-    #[test]
-    fn proposal_status_resolution_slashing_threshold_works_correctly() {
-        let no_slashing_threshold_proposal: Proposal<u64, u64, u64, u64, u64> = Proposal {
-            parameters: ProposalParameters {
-                slashing_threshold_percentage: 63,
-                approval_threshold_percentage: 63,
-                ..ProposalParameters::default()
-            },
-            ..Proposal::default()
-        };
-        let no_slashing_proposal_status_resolution = ProposalStatusResolution {
-            proposal: &no_slashing_threshold_proposal,
-            now: 20,
-            votes_count: 500,
-            total_voters_count: 600,
-            approvals: 3,
-            slashes: 314,
-        };
+    /// Exact block for the proposal execution.
+    /// Should be greater than starting block + grace_period if set.
+    pub exact_execution_block: Option<BlockNumber>,
+}
 
-        assert!(!no_slashing_proposal_status_resolution.is_slashing_threshold_reached());
+// Type alias for member id.
+pub(crate) type MemberId<T> = <T as membership::Trait>::MemberId;
 
-        let slashing_threshold_proposal_status_resolution = ProposalStatusResolution {
-            slashes: 315,
-            ..no_slashing_proposal_status_resolution
-        };
+/// Balance alias for `balances` module.
+pub type BalanceOf<T> = <T as balances::Trait>::Balance;
 
-        assert!(slashing_threshold_proposal_status_resolution.is_slashing_threshold_reached());
-    }
-}
+// Simplification of the 'Proposal' type
+pub(crate) type ProposalOf<T> = Proposal<
+    <T as frame_system::Trait>::BlockNumber,
+    MemberId<T>,
+    BalanceOf<T>,
+    <T as frame_system::Trait>::AccountId,
+>;

+ 71 - 149
runtime-modules/proposals/engine/src/types/proposal_statuses.rs

@@ -5,193 +5,115 @@ use codec::{Decode, Encode};
 use serde::{Deserialize, Serialize};
 use sp_std::vec::Vec;
 
-use crate::ActiveStake;
-
-/// Current status of the proposal
+/// Current status of the proposal.
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
-pub enum ProposalStatus<BlockNumber, StakeId, AccountId> {
-    /// A new proposal status that is available for voting (with optional stake data).
-    Active(Option<ActiveStake<StakeId, AccountId>>),
+pub enum ProposalStatus<BlockNumber> {
+    /// A new proposal status that is available for voting.
+    Active,
+
+    /// A proposal was approved and grace period is in effect.
+    /// Parameter contains approval block number.
+    PendingExecution(BlockNumber),
 
-    /// The proposal decision was made.
-    Finalized(FinalizationData<BlockNumber, StakeId, AccountId>),
+    /// The proposal needs more than one council approval.
+    PendingConstitutionality,
 }
 
-impl<BlockNumber, StakeId, AccountId> Default for ProposalStatus<BlockNumber, StakeId, AccountId> {
+impl<BlockNumber> Default for ProposalStatus<BlockNumber> {
     fn default() -> Self {
-        ProposalStatus::Active(None)
+        ProposalStatus::Active
     }
 }
 
-impl<BlockNumber, StakeId, AccountId> ProposalStatus<BlockNumber, StakeId, AccountId> {
-    /// Creates finalized proposal status with provided ProposalDecisionStatus
-    pub fn finalized_successfully(
-        decision_status: ProposalDecisionStatus,
+impl<BlockNumber: Clone> ProposalStatus<BlockNumber> {
+    /// Creates proposal status using ApprovedProposalDecision.
+    pub fn approved(
+        approved_status: ApprovedProposalDecision,
         now: BlockNumber,
-    ) -> ProposalStatus<BlockNumber, StakeId, AccountId> {
-        Self::finalized(decision_status, None, None, now)
+    ) -> ProposalStatus<BlockNumber> {
+        match approved_status {
+            ApprovedProposalDecision::PendingExecution => ProposalStatus::PendingExecution(now),
+            ApprovedProposalDecision::PendingConstitutionality => {
+                ProposalStatus::PendingConstitutionality
+            }
+        }
     }
 
-    /// Creates finalized proposal status with provided ProposalDecisionStatus and error
-    pub fn finalized(
-        decision_status: ProposalDecisionStatus,
-        encoded_unstaking_error_due_to_broken_runtime: Option<&str>,
-        active_stake: Option<ActiveStake<StakeId, AccountId>>,
-        now: BlockNumber,
-    ) -> ProposalStatus<BlockNumber, StakeId, AccountId> {
-        // drop the stake information if there were no errors on unstaking
-        let actual_stake = if encoded_unstaking_error_due_to_broken_runtime.is_some() {
-            active_stake
-        } else {
-            None
-        };
-        ProposalStatus::Finalized(FinalizationData {
-            proposal_status: decision_status,
-            encoded_unstaking_error_due_to_broken_runtime:
-                encoded_unstaking_error_due_to_broken_runtime.map(|err| err.as_bytes().to_vec()),
-            finalized_at: now,
-            stake_data_after_unstaking_error: actual_stake,
-        })
+    /// Determines whether a proposal in active or pending execution statuses.
+    pub fn is_active_or_pending_execution(&self) -> bool {
+        self.is_active_proposal() || self.is_pending_execution_proposal()
     }
 
-    /// Creates finalized and approved proposal status with provided ApprovedProposalStatus
-    pub fn approved(
-        approved_status: ApprovedProposalStatus,
-        now: BlockNumber,
-    ) -> ProposalStatus<BlockNumber, StakeId, AccountId> {
-        ProposalStatus::Finalized(FinalizationData {
-            proposal_status: ProposalDecisionStatus::Approved(approved_status),
-            encoded_unstaking_error_due_to_broken_runtime: None,
-            finalized_at: now,
-            stake_data_after_unstaking_error: None,
-        })
+    /// Detemines whether a proposal in active status.
+    pub fn is_active_proposal(&self) -> bool {
+        matches!(self.clone(), ProposalStatus::Active)
     }
-}
-
-/// Final proposal status and potential error.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
-pub struct FinalizationData<BlockNumber, StakeId, AccountId> {
-    /// Final proposal status
-    pub proposal_status: ProposalDecisionStatus,
-
-    /// Proposal finalization block number
-    pub finalized_at: BlockNumber,
 
-    /// Error occured during the proposal finalization - unstaking failed in the stake module
-    pub encoded_unstaking_error_due_to_broken_runtime: Option<Vec<u8>>,
-
-    /// Stake data for the proposal, filled if the unstaking wasn't successful
-    pub stake_data_after_unstaking_error: Option<ActiveStake<StakeId, AccountId>>,
-}
-
-impl<BlockNumber, StakeId, AccountId> FinalizationData<BlockNumber, StakeId, AccountId> {
-    /// FinalizationData helper, creates ApprovedProposalStatus
-    pub fn create_approved_proposal_status(
-        self,
-        approved_status: ApprovedProposalStatus,
-    ) -> ProposalStatus<BlockNumber, StakeId, AccountId> {
-        ProposalStatus::Finalized(FinalizationData {
-            proposal_status: ProposalDecisionStatus::Approved(approved_status),
-            ..self
-        })
+    /// Determines whether a proposal in pending execution status.
+    pub fn is_pending_execution_proposal(&self) -> bool {
+        matches!(self.clone(), ProposalStatus::PendingExecution{..})
     }
-}
-
-/// Status of the approved proposal. Defines execution stages.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
-pub enum ApprovedProposalStatus {
-    /// A proposal was approved and grace period is in effect
-    PendingExecution,
-
-    /// Proposal was successfully executed
-    Executed,
-
-    /// Proposal was executed and failed with an error
-    ExecutionFailed {
-        /// Error message
-        error: Vec<u8>,
-    },
-}
 
-impl ApprovedProposalStatus {
-    /// ApprovedProposalStatus helper, creates ExecutionFailed approved proposal status
-    pub fn failed_execution(err: &str) -> ApprovedProposalStatus {
-        ApprovedProposalStatus::ExecutionFailed {
-            error: err.as_bytes().to_vec(),
-        }
+    /// Determines whether a proposal in pending contitutionality status.
+    pub fn is_pending_constitutionality_proposal(&self) -> bool {
+        matches!(self.clone(), ProposalStatus::PendingConstitutionality)
     }
 }
 
-/// Status for the proposal with finalized decision
+/// Decision for the finalized proposal.
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
-pub enum ProposalDecisionStatus {
+pub enum ProposalDecision {
     /// Proposal was withdrawn by its proposer.
     Canceled,
 
     /// Proposal was vetoed by root.
     Vetoed,
 
-    /// A proposal was rejected
+    /// A proposal was rejected.
     Rejected,
 
-    /// A proposal was rejected ans its stake should be slashed
+    /// A proposal was rejected ans its stake should be slashed.
     Slashed,
 
     /// Not enough votes and voting period expired.
     Expired,
 
-    /// To clear the quorum requirement, the percentage of council members with revealed votes
-    /// must be no less than the quorum value for the given proposal type.
-    Approved(ApprovedProposalStatus),
+    /// A proposal was approved.
+    Approved(ApprovedProposalDecision),
 }
 
-#[cfg(test)]
-mod tests {
-    use crate::{
-        ActiveStake, ApprovedProposalStatus, FinalizationData, ProposalDecisionStatus,
-        ProposalStatus,
-    };
-
-    #[test]
-    fn approved_proposal_status_helper_succeeds() {
-        let msg = "error";
-
-        assert_eq!(
-            ApprovedProposalStatus::failed_execution(&msg),
-            ApprovedProposalStatus::ExecutionFailed {
-                error: msg.as_bytes().to_vec()
-            }
-        );
-    }
+/// Approved proposal decision.
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
+#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
+pub enum ApprovedProposalDecision {
+    /// A proposal should be executed and grace period is in effect.
+    PendingExecution,
+
+    /// The proposal needs more than one council approval.
+    PendingConstitutionality,
+}
 
-    #[test]
-    fn finalized_proposal_status_helper_succeeds() {
-        let msg = "error";
-        let block_number = 20;
-        let stake = ActiveStake {
-            stake_id: 50,
-            source_account_id: 2,
-        };
-
-        let proposal_status = ProposalStatus::finalized(
-            ProposalDecisionStatus::Slashed,
-            Some(msg),
-            Some(stake),
-            block_number,
-        );
-
-        assert_eq!(
-            ProposalStatus::Finalized(FinalizationData {
-                proposal_status: ProposalDecisionStatus::Slashed,
-                finalized_at: block_number,
-                encoded_unstaking_error_due_to_broken_runtime: Some(msg.as_bytes().to_vec()),
-                stake_data_after_unstaking_error: Some(stake)
-            }),
-            proposal_status
-        );
+/// Defines execution outcome.
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
+#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
+pub enum ExecutionStatus {
+    /// Proposal was successfully executed.
+    Executed,
+
+    /// Proposal was executed and failed with an error.
+    ExecutionFailed {
+        /// Error message
+        error: Vec<u8>,
+    },
+}
+
+impl ExecutionStatus {
+    /// ExecutionStatus helper, creates ExecutionFailed proposal execution status
+    pub fn failed_execution(err: &str) -> ExecutionStatus {
+        ExecutionStatus::ExecutionFailed {
+            error: err.as_bytes().to_vec(),
+        }
     }
 }

+ 0 - 248
runtime-modules/proposals/engine/src/types/stakes.rs

@@ -1,248 +0,0 @@
-#![warn(missing_docs)]
-
-use super::{BalanceOf, CurrencyOf, NegativeImbalance};
-use crate::Trait;
-use frame_support::traits::{Currency, ExistenceRequirement, WithdrawReasons};
-use sp_std::convert::From;
-use sp_std::marker::PhantomData;
-use sp_std::rc::Rc;
-
-// Mocking dependencies for testing
-#[cfg(test)]
-use mockall::predicate::*;
-#[cfg(test)]
-use mockall::*;
-
-/// Returns registered stake handler. This is scaffolds for the mocking of the stake module.
-pub trait StakeHandlerProvider<T: Trait> {
-    /// Returns stake logic handler
-    fn stakes() -> Rc<dyn StakeHandler<T>>;
-}
-
-/// Default implementation of the stake module logic provider. Returns actual implementation
-/// dependent on the stake module.
-pub struct DefaultStakeHandlerProvider;
-impl<T: Trait> StakeHandlerProvider<T> for DefaultStakeHandlerProvider {
-    /// Returns stake logic handler
-    fn stakes() -> Rc<dyn StakeHandler<T>> {
-        Rc::new(DefaultStakeHandler {
-            marker: PhantomData::<T>::default(),
-        })
-    }
-}
-
-/// Stake logic handler.
-#[cfg_attr(test, automock)] // attributes creates mocks in testing environment
-pub trait StakeHandler<T: Trait> {
-    /// Creates a stake. Returns created stake id or an error.
-    fn create_stake(&self) -> Result<T::StakeId, &'static str>;
-
-    /// Stake the imbalance
-    fn stake(
-        &self,
-        stake_id: &T::StakeId,
-        stake_imbalance: NegativeImbalance<T>,
-    ) -> Result<(), &'static str>;
-
-    /// Removes stake
-    fn remove_stake(&self, stake_id: T::StakeId) -> Result<(), &'static str>;
-
-    /// Execute unstaking
-    fn unstake(&self, stake_id: T::StakeId) -> Result<(), &'static str>;
-
-    /// Slash balance from the existing stake
-    fn slash(&self, stake_id: T::StakeId, slash_balance: BalanceOf<T>) -> Result<(), &'static str>;
-
-    /// Withdraw some balance from the source account and create stake imbalance
-    fn make_stake_imbalance(
-        &self,
-        balance: BalanceOf<T>,
-        source_account_id: &T::AccountId,
-    ) -> Result<NegativeImbalance<T>, &'static str>;
-}
-
-/// Default implementation of the stake logic. Uses actual stake module.
-/// 'marker' responsible for the 'Trait' binding.
-pub(crate) struct DefaultStakeHandler<T> {
-    pub marker: PhantomData<T>,
-}
-
-impl<T: Trait> StakeHandler<T> for DefaultStakeHandler<T> {
-    /// Creates a stake. Returns created stake id or an error.
-    fn create_stake(&self) -> Result<<T as stake::Trait>::StakeId, &'static str> {
-        Ok(stake::Module::<T>::create_stake())
-    }
-
-    /// Stake the imbalance
-    fn stake(
-        &self,
-        stake_id: &<T as stake::Trait>::StakeId,
-        stake_imbalance: NegativeImbalance<T>,
-    ) -> Result<(), &'static str> {
-        stake::Module::<T>::stake(&stake_id, stake_imbalance).map_err(WrappedError)?;
-
-        Ok(())
-    }
-
-    /// Removes stake
-    fn remove_stake(&self, stake_id: <T as stake::Trait>::StakeId) -> Result<(), &'static str> {
-        stake::Module::<T>::remove_stake(&stake_id).map_err(WrappedError)?;
-
-        Ok(())
-    }
-
-    /// Execute unstaking
-    fn unstake(&self, stake_id: <T as stake::Trait>::StakeId) -> Result<(), &'static str> {
-        stake::Module::<T>::initiate_unstaking(&stake_id, None).map_err(WrappedError)?;
-
-        Ok(())
-    }
-
-    /// Slash balance from the existing stake
-    fn slash(
-        &self,
-        stake_id: <T as stake::Trait>::StakeId,
-        slash_balance: BalanceOf<T>,
-    ) -> Result<(), &'static str> {
-        let _ignored_successful_result =
-            stake::Module::<T>::slash_immediate(&stake_id, slash_balance, false)
-                .map_err(WrappedError)?;
-
-        Ok(())
-    }
-
-    /// Withdraw some balance from the source account and create stake imbalance
-    fn make_stake_imbalance(
-        &self,
-        balance: BalanceOf<T>,
-        source_account_id: &T::AccountId,
-    ) -> Result<NegativeImbalance<T>, &'static str> {
-        CurrencyOf::<T>::withdraw(
-            source_account_id,
-            balance,
-            WithdrawReasons::all(),
-            ExistenceRequirement::AllowDeath,
-        )
-        .map_err(<&str>::from)
-    }
-}
-
-/// Proposal implementation of the stake logic.
-/// 'marker' responsible for the 'Trait' binding.
-pub(crate) struct ProposalStakeManager<T> {
-    pub marker: PhantomData<T>,
-}
-
-impl<T: Trait> ProposalStakeManager<T> {
-    /// Creates a stake using stake balance and source account.
-    /// Returns created stake id or an error.
-    pub fn create_stake(
-        stake_balance: BalanceOf<T>,
-        source_account_id: T::AccountId,
-    ) -> Result<T::StakeId, &'static str> {
-        let stake_id = T::StakeHandlerProvider::stakes().create_stake()?;
-
-        let stake_imbalance = T::StakeHandlerProvider::stakes()
-            .make_stake_imbalance(stake_balance, &source_account_id)?;
-
-        T::StakeHandlerProvider::stakes().stake(&stake_id, stake_imbalance)?;
-
-        Ok(stake_id)
-    }
-
-    /// Execute unstaking and removes the stake
-    pub fn remove_stake(stake_id: T::StakeId) -> Result<(), &'static str> {
-        T::StakeHandlerProvider::stakes().unstake(stake_id)?;
-
-        T::StakeHandlerProvider::stakes().remove_stake(stake_id)?;
-
-        Ok(())
-    }
-
-    /// Slash balance from the existing stake
-    pub fn slash(stake_id: T::StakeId, slash_balance: BalanceOf<T>) -> Result<(), &'static str> {
-        T::StakeHandlerProvider::stakes().slash(stake_id, slash_balance)
-    }
-}
-
-// 'New type' pattern for the error
-// https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#using-the-newtype-pattern-to-implement-external-traits-on-external-types
-struct WrappedError<E>(E);
-
-// error conversion for the Wrapped StakeActionError with the inner InitiateUnstakingError
-impl From<WrappedError<stake::StakeActionError<stake::InitiateUnstakingError>>> for &str {
-    fn from(wrapper: WrappedError<stake::StakeActionError<stake::InitiateUnstakingError>>) -> Self {
-        {
-            match wrapper.0 {
-                stake::StakeActionError::StakeNotFound => "StakeNotFound",
-                stake::StakeActionError::Error(err) => match err {
-                    stake::InitiateUnstakingError::UnstakingPeriodShouldBeGreaterThanZero => {
-                        "UnstakingPeriodShouldBeGreaterThanZero"
-                    }
-                    stake::InitiateUnstakingError::UnstakingError(e) => match e {
-                        stake::UnstakingError::NotStaked => "NotStaked",
-                        stake::UnstakingError::AlreadyUnstaking => "AlreadyUnstaking",
-                        stake::UnstakingError::CannotUnstakeWhileSlashesOngoing => {
-                            "CannotUnstakeWhileSlashesOngoing"
-                        }
-                    },
-                },
-            }
-        }
-    }
-}
-
-// error conversion for the Wrapped StakeActionError with the inner StakingError
-impl From<WrappedError<stake::StakeActionError<stake::StakingError>>> for &str {
-    fn from(wrapper: WrappedError<stake::StakeActionError<stake::StakingError>>) -> Self {
-        {
-            match wrapper.0 {
-                stake::StakeActionError::StakeNotFound => "StakeNotFound",
-                stake::StakeActionError::Error(err) => match err {
-                    stake::StakingError::CannotStakeZero => "CannotStakeZero",
-                    stake::StakingError::CannotStakeLessThanMinimumBalance => {
-                        "CannotStakeLessThanMinimumBalance"
-                    }
-                    stake::StakingError::AlreadyStaked => "AlreadyStaked",
-                },
-            }
-        }
-    }
-}
-
-// error conversion for the Wrapped StakeActionError with the inner InitiateSlashingError
-impl From<WrappedError<stake::StakeActionError<stake::InitiateSlashingError>>> for &str {
-    fn from(wrapper: WrappedError<stake::StakeActionError<stake::InitiateSlashingError>>) -> Self {
-        {
-            match wrapper.0 {
-                stake::StakeActionError::StakeNotFound => "StakeNotFound",
-                stake::StakeActionError::Error(err) => match err {
-                    stake::InitiateSlashingError::NotStaked => "NotStaked",
-                    stake::InitiateSlashingError::SlashPeriodShouldBeGreaterThanZero => {
-                        "SlashPeriodShouldBeGreaterThanZero"
-                    }
-                    stake::InitiateSlashingError::SlashAmountShouldBeGreaterThanZero => {
-                        "SlashAmountShouldBeGreaterThanZero"
-                    }
-                },
-            }
-        }
-    }
-}
-
-// error conversion for the Wrapped StakeActionError with the inner ImmediateSlashingError
-impl From<WrappedError<stake::StakeActionError<stake::ImmediateSlashingError>>> for &str {
-    fn from(wrapper: WrappedError<stake::StakeActionError<stake::ImmediateSlashingError>>) -> Self {
-        {
-            match wrapper.0 {
-                stake::StakeActionError::StakeNotFound => "StakeNotFound",
-                stake::StakeActionError::Error(err) => match err {
-                    stake::ImmediateSlashingError::NotStaked => "NotStaked",
-                    stake::ImmediateSlashingError::SlashAmountShouldBeGreaterThanZero => {
-                        "SlashAmountShouldBeGreaterThanZero"
-                    }
-                },
-            }
-        }
-    }
-}

+ 2 - 4
runtime-modules/working-group/src/lib.rs

@@ -486,10 +486,8 @@ decl_module! {
             rationale_text: Vec<u8>,
             slash_stake: bool,
         ) {
-            let (cloned_origin1, cloned_origin2) = common::origin::double_origin::<T>(origin);
-
             // Ensure lead is set or it is the council terminating the leader.
-            let exit_origin = Self::ensure_origin_for_leader(cloned_origin1, worker_id)?;
+            let exit_origin = Self::ensure_origin_for_leader(origin.clone(), worker_id)?;
 
             // Ensuring worker actually exists.
             let worker = Self::ensure_worker_exists(&worker_id)?;
@@ -502,7 +500,7 @@ decl_module! {
             //
 
             if slash_stake {
-                Self::slash_stake(cloned_origin2, worker_id, BalanceOf::<T>::max_value())?;
+                Self::slash_stake(origin, worker_id, BalanceOf::<T>::max_value())?;
             }
 
             Self::deactivate_worker(

+ 7 - 0
runtime/Cargo.toml

@@ -9,6 +9,9 @@ version = '7.8.0'
 [dependencies]
 # Third-party dependencies
 serde = { version = "1.0.101", optional = true, features = ["derive"] }
+lazy_static = {version = "1.4.0", features = ["spin_no_std"] }
+lite-json = { version = '0.1.3', default-features = false}
+hex-literal = { optional = true, version = '0.3.1' }
 codec = { package = 'parity-scale-codec', version = '1.3.4', default-features = false, features = ['derive'] }
 
 # Substrate primitives
@@ -78,6 +81,7 @@ proposals-engine = { package = 'pallet-proposals-engine', default-features = fal
 proposals-discussion = { package = 'pallet-proposals-discussion', default-features = false, path = '../runtime-modules/proposals/discussion'}
 proposals-codex = { package = 'pallet-proposals-codex', default-features = false, path = '../runtime-modules/proposals/codex'}
 content-directory = { package = 'pallet-content-directory', default-features = false, path = '../runtime-modules/content-directory' }
+constitution = { package = 'pallet-constitution', default-features = false, path = '../runtime-modules/constitution' }
 
 [dev-dependencies]
 sp-io = { package = 'sp-io', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
@@ -155,6 +159,7 @@ std = [
     'proposals-discussion/std',
     'proposals-codex/std',
     'content-directory/std',
+    'constitution/std',
 ]
 runtime-benchmarks = [
     "frame-system/runtime-benchmarks",
@@ -169,6 +174,8 @@ runtime-benchmarks = [
     "pallet-offences-benchmarking",
 	"pallet-session-benchmarking",
     "pallet-utility/runtime-benchmarks",
+    "proposals-discussion/runtime-benchmarks",
+    "hex-literal",
 ]
 
 

+ 1 - 0
runtime/src/integration/mod.rs

@@ -1,6 +1,7 @@
 pub mod content_directory;
 pub mod content_working_group;
 pub mod proposals;
+pub mod staking_handler;
 pub mod storage;
 pub mod transactions;
 pub mod versioned_store_permissions;

+ 2 - 1
runtime/src/integration/proposals/council_elected_handler.rs

@@ -9,6 +9,7 @@ pub struct CouncilElectedHandler;
 
 impl<Elected, Term> CouncilElected<Elected, Term> for CouncilElectedHandler {
     fn council_elected(_new_council: Elected, _term: Term) {
-        <proposals_engine::Module<Runtime>>::reset_active_proposals();
+        <proposals_engine::Module<Runtime>>::reject_active_proposals();
+        <proposals_engine::Module<Runtime>>::reactivate_pending_constitutionality_proposals();
     }
 }

+ 0 - 2
runtime/src/integration/proposals/mod.rs

@@ -4,10 +4,8 @@ mod council_elected_handler;
 mod council_origin_validator;
 mod membership_origin_validator;
 mod proposal_encoder;
-mod staking_events_handler;
 
 pub use council_elected_handler::CouncilElectedHandler;
 pub use council_origin_validator::CouncilManager;
 pub use membership_origin_validator::{MemberId, MembershipOriginValidator};
 pub use proposal_encoder::ExtrinsicProposalEncoder;
-pub use staking_events_handler::StakingEventsHandler;

+ 3 - 0
runtime/src/integration/proposals/proposal_encoder.rs

@@ -127,6 +127,9 @@ impl ProposalEncoder<Runtime> for ExtrinsicProposalEncoder {
                     Wg::terminate_role_call(terminate_role_params)
                 )
             }
+            ProposalDetails::AmendConstitution(constitution_text) => {
+                Call::Constitution(constitution::Call::amend_constitution(constitution_text))
+            }
         };
 
         call.encode()

+ 0 - 50
runtime/src/integration/proposals/staking_events_handler.rs

@@ -1,50 +0,0 @@
-#![warn(missing_docs)]
-
-use frame_support::traits::{Currency, Imbalance};
-use frame_support::StorageMap;
-use sp_std::marker::PhantomData;
-
-// Balance alias
-type BalanceOf<T> =
-    <<T as stake::Trait>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::Balance;
-
-// Balance alias for staking
-type NegativeImbalance<T> = <<T as stake::Trait>::Currency as Currency<
-    <T as frame_system::Trait>::AccountId,
->>::NegativeImbalance;
-
-/// Proposal implementation of the staking event handler from the stake module.
-/// 'marker' responsible for the 'Trait' binding.
-pub struct StakingEventsHandler<T> {
-    pub marker: PhantomData<T>,
-}
-
-impl<T: stake::Trait + proposals_engine::Trait> stake::StakingEventsHandler<T>
-    for StakingEventsHandler<T>
-{
-    /// Unstake remaining sum back to the source_account_id
-    fn unstaked(
-        id: &<T as stake::Trait>::StakeId,
-        _unstaked_amount: BalanceOf<T>,
-        remaining_imbalance: NegativeImbalance<T>,
-    ) -> NegativeImbalance<T> {
-        if <proposals_engine::StakesProposals<T>>::contains_key(id) {
-            <proposals_engine::Module<T>>::refund_proposal_stake(*id, remaining_imbalance);
-
-            return <NegativeImbalance<T>>::zero(); // imbalance was consumed
-        }
-
-        remaining_imbalance
-    }
-
-    /// Empty handler for slashing
-    fn slashed(
-        _: &<T as stake::Trait>::StakeId,
-        _: Option<<T as stake::Trait>::SlashId>,
-        _: BalanceOf<T>,
-        _: BalanceOf<T>,
-        remaining_imbalance: NegativeImbalance<T>,
-    ) -> NegativeImbalance<T> {
-        remaining_imbalance
-    }
-}

+ 105 - 0
runtime/src/integration/staking_handler.rs

@@ -0,0 +1,105 @@
+use frame_support::dispatch::{DispatchError, DispatchResult};
+use frame_support::traits::{Currency, Get, LockIdentifier, LockableCurrency, WithdrawReasons};
+use membership::staking_handler::{BalanceOf, MemberId, StakingHandler};
+use sp_arithmetic::traits::Zero;
+use sp_std::marker::PhantomData;
+
+/// Implementation of the StakingHandler.
+pub struct StakingManager<
+    T: frame_system::Trait + membership::Trait + pallet_balances::Trait,
+    LockId: Get<LockIdentifier>,
+> {
+    trait_marker: PhantomData<T>,
+    lock_id_marker: PhantomData<LockId>,
+}
+
+impl<
+        T: frame_system::Trait + membership::Trait + pallet_balances::Trait,
+        LockId: Get<LockIdentifier>,
+    > StakingHandler<T> for StakingManager<T, LockId>
+{
+    fn lock(account_id: &T::AccountId, amount: BalanceOf<T>) {
+        <pallet_balances::Module<T>>::set_lock(
+            LockId::get(),
+            &account_id,
+            amount,
+            WithdrawReasons::all(),
+        )
+    }
+
+    fn unlock(account_id: &T::AccountId) {
+        T::Currency::remove_lock(LockId::get(), &account_id);
+    }
+
+    fn slash(account_id: &T::AccountId, amount: Option<BalanceOf<T>>) -> BalanceOf<T> {
+        let locks = <pallet_balances::Module<T>>::locks(&account_id);
+
+        let existing_lock = locks.iter().find(|lock| lock.id == LockId::get());
+
+        let mut actually_slashed_balance = Default::default();
+        if let Some(existing_lock) = existing_lock {
+            Self::unlock(&account_id);
+
+            let mut slashable_amount = existing_lock.amount;
+            if let Some(amount) = amount {
+                if existing_lock.amount > amount {
+                    let new_amount = existing_lock.amount - amount;
+                    Self::lock(&account_id, new_amount);
+
+                    slashable_amount = amount;
+                }
+            }
+
+            let _ = <pallet_balances::Module<T>>::slash(&account_id, slashable_amount);
+
+            actually_slashed_balance = slashable_amount
+        }
+
+        actually_slashed_balance
+    }
+
+    fn set_stake(account_id: &T::AccountId, new_stake: BalanceOf<T>) -> DispatchResult {
+        let current_stake = Self::current_stake(account_id);
+
+        //Unlock previous stake if its not zero.
+        if current_stake > Zero::zero() {
+            Self::unlock(account_id);
+        }
+
+        if !Self::is_enough_balance_for_stake(account_id, new_stake) {
+            //Restore previous stake if its not zero.
+            if current_stake > Zero::zero() {
+                Self::lock(account_id, current_stake);
+            }
+            return Err(DispatchError::Other("Not enough balance for a new stake."));
+        }
+
+        Self::lock(account_id, new_stake);
+
+        Ok(())
+    }
+
+    fn is_member_staking_account(_member_id: &MemberId<T>, _account_id: &T::AccountId) -> bool {
+        true
+    }
+
+    fn is_account_free_of_conflicting_stakes(account_id: &T::AccountId) -> bool {
+        let locks = <pallet_balances::Module<T>>::locks(&account_id);
+
+        let existing_lock = locks.iter().find(|lock| lock.id == LockId::get());
+
+        existing_lock.is_none()
+    }
+
+    fn is_enough_balance_for_stake(account_id: &T::AccountId, amount: BalanceOf<T>) -> bool {
+        <pallet_balances::Module<T>>::usable_balance(account_id) >= amount
+    }
+
+    fn current_stake(account_id: &T::AccountId) -> BalanceOf<T> {
+        let locks = <pallet_balances::Module<T>>::locks(&account_id);
+
+        let existing_lock = locks.iter().find(|lock| lock.id == LockId::get());
+
+        existing_lock.map_or(Zero::zero(), |lock| lock.amount)
+    }
+}

+ 47 - 24
runtime/src/lib.rs

@@ -16,13 +16,17 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
 mod constants;
 mod integration;
 pub mod primitives;
+mod proposals_configuration;
 mod runtime_api;
 #[cfg(test)]
 mod tests;
 /// Weights for pallets used in the runtime.
 mod weights; // Runtime integration tests
 
-use frame_support::traits::KeyOwnerProofSystem;
+#[macro_use]
+extern crate lazy_static; // for proposals_configuration module
+
+use frame_support::traits::{KeyOwnerProofSystem, LockIdentifier};
 use frame_support::weights::{
     constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight},
     Weight,
@@ -45,6 +49,7 @@ use sp_version::RuntimeVersion;
 
 pub use constants::*;
 pub use primitives::*;
+pub use proposals_configuration::*;
 pub use runtime_api::*;
 
 use integration::proposals::{CouncilManager, ExtrinsicProposalEncoder, MembershipOriginValidator};
@@ -54,6 +59,10 @@ use storage::data_object_storage_registry;
 
 // Node dependencies
 pub use common;
+pub use content_directory;
+pub use content_directory::{
+    HashedTextMaxLength, InputValidationLengthConstraint, MaxNumber, TextMaxLength, VecMaxLength,
+};
 pub use content_working_group as content_wg;
 pub use forum;
 pub use governance::election_params::ElectionParameters;
@@ -61,17 +70,12 @@ pub use membership;
 #[cfg(any(feature = "std", test))]
 pub use pallet_balances::Call as BalancesCall;
 pub use pallet_staking::StakerStatus;
-pub use proposals_codex::ProposalsConfigParameters;
+pub use proposals_engine::ProposalParameters;
 pub use storage::{data_directory, data_object_type_registry};
 pub use versioned_store;
 pub use versioned_store_permissions;
 pub use working_group;
 
-pub use content_directory;
-pub use content_directory::{
-    HashedTextMaxLength, InputValidationLengthConstraint, MaxNumber, TextMaxLength, VecMaxLength,
-};
-
 #[cfg(feature = "std")]
 /// Wasm binary unwrapped. If built with `BUILD_DUMMY_WASM_BINARY`, the function panics.
 pub fn wasm_binary_unwrap() -> &'static [u8] {
@@ -487,11 +491,8 @@ impl stake::Trait for Runtime {
     type Currency = <Self as common::currency::GovernanceCurrency>::Currency;
     type StakePoolId = StakePoolId;
     type StakingEventsHandler = (
-        crate::integration::proposals::StakingEventsHandler<Self>,
-        (
-            crate::integration::working_group::ContentDirectoryWGStakingEventsHandler<Self>,
-            crate::integration::working_group::StorageWgStakingEventsHandler<Self>,
-        ),
+        crate::integration::working_group::ContentDirectoryWGStakingEventsHandler<Self>,
+        crate::integration::working_group::StorageWgStakingEventsHandler<Self>,
     );
     type StakeId = u64;
     type SlashId = u64;
@@ -662,6 +663,7 @@ parameter_types! {
     pub const ProposalTitleMaxLength: u32 = 40;
     pub const ProposalDescriptionMaxLength: u32 = 3000;
     pub const ProposalMaxActiveProposalLimit: u32 = 5;
+    pub const ProposalsLockId: LockIdentifier = [5; 8];
 }
 
 impl proposals_engine::Trait for Runtime {
@@ -670,14 +672,16 @@ impl proposals_engine::Trait for Runtime {
     type VoterOriginValidator = CouncilManager<Self>;
     type TotalVotersCounter = CouncilManager<Self>;
     type ProposalId = u32;
-    type StakeHandlerProvider = proposals_engine::DefaultStakeHandlerProvider;
+    type StakingHandler = integration::staking_handler::StakingManager<Self, ProposalsLockId>;
     type CancellationFee = ProposalCancellationFee;
     type RejectionFee = ProposalRejectionFee;
     type TitleMaxLength = ProposalTitleMaxLength;
     type DescriptionMaxLength = ProposalDescriptionMaxLength;
     type MaxActiveProposalLimit = ProposalMaxActiveProposalLimit;
     type DispatchableCallCode = Call;
+    type ProposalObserver = ProposalsCodex;
 }
+
 impl Default for Call {
     fn default() -> Self {
         panic!("shouldn't call default for Call");
@@ -685,21 +689,16 @@ impl Default for Call {
 }
 
 parameter_types! {
-    pub const ProposalMaxPostEditionNumber: u32 = 0; // post update is disabled
-    pub const ProposalMaxThreadInARowNumber: u32 = 100_000; // will not be used
-    pub const ProposalThreadTitleLengthLimit: u32 = 40;
-    pub const ProposalPostLengthLimit: u32 = 1000;
+    pub const MaxWhiteListSize: u32 = 20;
 }
 
 impl proposals_discussion::Trait for Runtime {
     type Event = Event;
-    type PostAuthorOriginValidator = MembershipOriginValidator<Self>;
+    type AuthorOriginValidator = MembershipOriginValidator<Self>;
+    type CouncilOriginValidator = CouncilManager<Self>;
     type ThreadId = ThreadId;
     type PostId = PostId;
-    type MaxPostEditionNumber = ProposalMaxPostEditionNumber;
-    type ThreadTitleLengthLimit = ProposalThreadTitleLengthLimit;
-    type PostLengthLimit = ProposalPostLengthLimit;
-    type MaxThreadInARowNumber = ProposalMaxThreadInARowNumber;
+    type MaxWhiteListSize = MaxWhiteListSize;
 }
 
 parameter_types! {
@@ -708,10 +707,33 @@ parameter_types! {
 }
 
 impl proposals_codex::Trait for Runtime {
-    type MembershipOriginValidator = MembershipOriginValidator<Self>;
     type TextProposalMaxLength = TextProposalMaxLength;
     type RuntimeUpgradeWasmProposalMaxLength = RuntimeUpgradeWasmProposalMaxLength;
+    type MembershipOriginValidator = MembershipOriginValidator<Self>;
     type ProposalEncoder = ExtrinsicProposalEncoder;
+    type SetValidatorCountProposalParameters = SetValidatorCountProposalParameters;
+    type RuntimeUpgradeProposalParameters = RuntimeUpgradeProposalParameters;
+    type TextProposalParameters = TextProposalParameters;
+    type SpendingProposalParameters = SpendingProposalParameters;
+    type AddWorkingGroupOpeningProposalParameters = AddWorkingGroupOpeningProposalParameters;
+    type BeginReviewWorkingGroupApplicationsProposalParameters =
+        BeginReviewWorkingGroupApplicationsProposalParameters;
+    type FillWorkingGroupOpeningProposalParameters = FillWorkingGroupOpeningProposalParameters;
+    type SetWorkingGroupMintCapacityProposalParameters =
+        SetWorkingGroupMintCapacityProposalParameters;
+    type DecreaseWorkingGroupLeaderStakeProposalParameters =
+        DecreaseWorkingGroupLeaderStakeProposalParameters;
+    type SlashWorkingGroupLeaderStakeProposalParameters =
+        SlashWorkingGroupLeaderStakeProposalParameters;
+    type SetWorkingGroupLeaderRewardProposalParameters =
+        SetWorkingGroupLeaderRewardProposalParameters;
+    type TerminateWorkingGroupLeaderRoleProposalParameters =
+        TerminateWorkingGroupLeaderRoleProposalParameters;
+    type AmendConstitutionProposalParameters = AmendConstitutionProposalParameters;
+}
+
+impl constitution::Trait for Runtime {
+    type Event = Event;
 }
 
 parameter_types! {
@@ -781,6 +803,7 @@ construct_runtime!(
         Hiring: hiring::{Module, Call, Storage},
         ContentWorkingGroup: content_wg::{Module, Call, Storage, Event<T>, Config<T>},
         ContentDirectory: content_directory::{Module, Call, Storage, Event<T>, Config<T>},
+        Constitution: constitution::{Module, Call, Storage, Event},
         // --- Storage
         DataObjectTypeRegistry: data_object_type_registry::{Module, Call, Storage, Event<T>, Config<T>},
         DataDirectory: data_directory::{Module, Call, Storage, Event<T>, Config<T>},
@@ -789,7 +812,7 @@ construct_runtime!(
         // --- Proposals
         ProposalsEngine: proposals_engine::{Module, Call, Storage, Event<T>},
         ProposalsDiscussion: proposals_discussion::{Module, Call, Storage, Event<T>},
-        ProposalsCodex: proposals_codex::{Module, Call, Storage, Config<T>},
+        ProposalsCodex: proposals_codex::{Module, Call, Storage},
         // --- Working groups
         ForumWorkingGroup: working_group::<Instance1>::{Module, Call, Storage, Config<T>, Event<T>},
         StorageWorkingGroup: working_group::<Instance2>::{Module, Call, Storage, Config<T>, Event<T>},

+ 189 - 0
runtime/src/proposals_configuration/defaults.rs

@@ -0,0 +1,189 @@
+//! This module contains default parameters for the runtime codex proposals.
+
+use crate::{Balance, BlockNumber, ProposalParameters};
+
+// Proposal parameters for the 'Set validator count' proposal
+pub(crate) fn set_validator_count_proposal() -> ProposalParameters<BlockNumber, Balance> {
+    ProposalParameters {
+        voting_period: 43200,
+        grace_period: 0,
+        approval_quorum_percentage: 66,
+        approval_threshold_percentage: 80,
+        slashing_quorum_percentage: 60,
+        slashing_threshold_percentage: 80,
+        required_stake: Some(100_000),
+        constitutionality: 1,
+    }
+}
+
+// Proposal parameters for the upgrade runtime proposal
+pub(crate) fn runtime_upgrade_proposal() -> ProposalParameters<BlockNumber, Balance> {
+    ProposalParameters {
+        voting_period: 72000,
+        grace_period: 72000,
+        approval_quorum_percentage: 80,
+        approval_threshold_percentage: 100,
+        slashing_quorum_percentage: 60,
+        slashing_threshold_percentage: 80,
+        required_stake: Some(1_000_000),
+        constitutionality: 1,
+    }
+}
+
+// Proposal parameters for the text proposal
+pub(crate) fn text_proposal() -> ProposalParameters<BlockNumber, Balance> {
+    ProposalParameters {
+        voting_period: 72000,
+        grace_period: 0,
+        approval_quorum_percentage: 60,
+        approval_threshold_percentage: 80,
+        slashing_quorum_percentage: 60,
+        slashing_threshold_percentage: 80,
+        required_stake: Some(25000),
+        constitutionality: 1,
+    }
+}
+
+// Proposal parameters for the 'Spending' proposal
+pub(crate) fn spending_proposal() -> ProposalParameters<BlockNumber, Balance> {
+    ProposalParameters {
+        voting_period: 72000,
+        grace_period: 14400,
+        approval_quorum_percentage: 60,
+        approval_threshold_percentage: 80,
+        slashing_quorum_percentage: 60,
+        slashing_threshold_percentage: 80,
+        required_stake: Some(25000),
+        constitutionality: 1,
+    }
+}
+// Proposal parameters for the 'Add working group opening' proposal
+pub(crate) fn add_working_group_opening_proposal() -> ProposalParameters<BlockNumber, Balance> {
+    ProposalParameters {
+        voting_period: 72000,
+        grace_period: 0,
+        approval_quorum_percentage: 60,
+        approval_threshold_percentage: 80,
+        slashing_quorum_percentage: 60,
+        slashing_threshold_percentage: 80,
+        required_stake: Some(100_000),
+        constitutionality: 1,
+    }
+}
+
+// Proposal parameters for the 'Begin review working group applications' proposal
+pub(crate) fn begin_review_working_group_applications_proposal(
+) -> ProposalParameters<BlockNumber, Balance> {
+    ProposalParameters {
+        voting_period: 43200,
+        grace_period: 14400,
+        approval_quorum_percentage: 60,
+        approval_threshold_percentage: 75,
+        slashing_quorum_percentage: 60,
+        slashing_threshold_percentage: 80,
+        required_stake: Some(25000),
+        constitutionality: 1,
+    }
+}
+
+// Proposal parameters for the 'Fill working group opening' proposal
+pub(crate) fn fill_working_group_opening_proposal() -> ProposalParameters<BlockNumber, Balance> {
+    ProposalParameters {
+        voting_period: 43200,
+        grace_period: 0,
+        approval_quorum_percentage: 60,
+        approval_threshold_percentage: 75,
+        slashing_quorum_percentage: 60,
+        slashing_threshold_percentage: 80,
+        required_stake: Some(50000),
+        constitutionality: 1,
+    }
+}
+
+// Proposal parameters for the 'Set working group mint capacity' proposal
+pub(crate) fn set_working_group_mint_capacity_proposal() -> ProposalParameters<BlockNumber, Balance>
+{
+    ProposalParameters {
+        voting_period: 43200,
+        grace_period: 0,
+        approval_quorum_percentage: 60,
+        approval_threshold_percentage: 75,
+        slashing_quorum_percentage: 60,
+        slashing_threshold_percentage: 80,
+        required_stake: Some(50000),
+        constitutionality: 1,
+    }
+}
+
+// Proposal parameters for the 'Decrease working group leader stake' proposal
+pub(crate) fn decrease_working_group_leader_stake_proposal(
+) -> ProposalParameters<BlockNumber, Balance> {
+    ProposalParameters {
+        voting_period: 43200,
+        grace_period: 0,
+        approval_quorum_percentage: 60,
+        approval_threshold_percentage: 75,
+        slashing_quorum_percentage: 60,
+        slashing_threshold_percentage: 80,
+        required_stake: Some(50000),
+        constitutionality: 1,
+    }
+}
+
+// Proposal parameters for the 'Slash working group leader stake' proposal
+pub fn slash_working_group_leader_stake_proposal() -> ProposalParameters<BlockNumber, Balance> {
+    ProposalParameters {
+        voting_period: 43200,
+        grace_period: 0,
+        approval_quorum_percentage: 60,
+        approval_threshold_percentage: 75,
+        slashing_quorum_percentage: 60,
+        slashing_threshold_percentage: 80,
+        required_stake: Some(50000),
+        constitutionality: 1,
+    }
+}
+
+// Proposal parameters for the 'Set working group leader reward' proposal
+pub(crate) fn set_working_group_leader_reward_proposal() -> ProposalParameters<BlockNumber, Balance>
+{
+    ProposalParameters {
+        voting_period: 43200,
+        grace_period: 0,
+        approval_quorum_percentage: 60,
+        approval_threshold_percentage: 75,
+        slashing_quorum_percentage: 60,
+        slashing_threshold_percentage: 80,
+        required_stake: Some(50000),
+        constitutionality: 1,
+    }
+}
+
+// Proposal parameters for the 'Terminate working group leader role' proposal
+pub(crate) fn terminate_working_group_leader_role_proposal(
+) -> ProposalParameters<BlockNumber, Balance> {
+    ProposalParameters {
+        voting_period: 72200,
+        grace_period: 0,
+        approval_quorum_percentage: 66,
+        approval_threshold_percentage: 80,
+        slashing_quorum_percentage: 60,
+        slashing_threshold_percentage: 80,
+        required_stake: Some(100_000),
+        constitutionality: 1,
+    }
+}
+
+// Proposal parameters for the 'Amend constitution' proposal
+pub(crate) fn amend_constitution_proposal() -> ProposalParameters<BlockNumber, Balance> {
+    ProposalParameters {
+        voting_period: 72200,
+        grace_period: 72200,
+        approval_quorum_percentage: 80,
+        approval_threshold_percentage: 100,
+        slashing_quorum_percentage: 60,
+        slashing_threshold_percentage: 80,
+        required_stake: Some(1_000_000),
+        constitutionality: 1,
+    }
+}

+ 269 - 0
runtime/src/proposals_configuration/mod.rs

@@ -0,0 +1,269 @@
+//! This module defines a set of the parameters for each proposal in the runtime like
+//! _SetValidatorCountProposalParameters_. It is separated because we need to be able to configure
+//! these parameters during the compilation time. Main consumer of the conditional compilation planned
+//! to be the integration tests.
+//!
+//! The whole parameter set is initialized only once by deserializing JSON from the environment variable
+//! "ALL_PROPOSALS_PARAMETERS_JSON". If it doesn't exists or contains invalid or empty JSON then
+//! the default parameters are returned. If some proposal section of the JSON file contains only
+//! partial object definition - default values are returned as missing fields.
+//!
+
+use crate::{Balance, BlockNumber, ProposalParameters};
+use frame_support::dispatch::Vec;
+use frame_support::parameter_types;
+use frame_support::sp_runtime::SaturatedConversion;
+use lite_json::{JsonObject, JsonValue};
+
+mod defaults;
+#[cfg(test)]
+mod tests;
+
+/////////// Proposal parameters definition
+
+parameter_types! {
+    pub SetValidatorCountProposalParameters: ProposalParameters<BlockNumber, Balance> = ALL_PROPOSALS_PARAMETERS.set_validator_count_proposal;
+    pub RuntimeUpgradeProposalParameters: ProposalParameters<BlockNumber, Balance> = ALL_PROPOSALS_PARAMETERS.runtime_upgrade_proposal;
+    pub TextProposalParameters: ProposalParameters<BlockNumber, Balance> = ALL_PROPOSALS_PARAMETERS.text_proposal;
+    pub SpendingProposalParameters: ProposalParameters<BlockNumber, Balance> = ALL_PROPOSALS_PARAMETERS.spending_proposal;
+    pub AddWorkingGroupOpeningProposalParameters: ProposalParameters<BlockNumber, Balance> = ALL_PROPOSALS_PARAMETERS.add_working_group_opening_proposal;
+    pub BeginReviewWorkingGroupApplicationsProposalParameters: ProposalParameters<BlockNumber, Balance> = ALL_PROPOSALS_PARAMETERS.begin_review_working_group_applications_proposal;
+    pub FillWorkingGroupOpeningProposalParameters: ProposalParameters<BlockNumber, Balance> = ALL_PROPOSALS_PARAMETERS.fill_working_group_opening_proposal;
+    pub SetWorkingGroupMintCapacityProposalParameters: ProposalParameters<BlockNumber, Balance> = ALL_PROPOSALS_PARAMETERS.set_working_group_mint_capacity_proposal;
+    pub DecreaseWorkingGroupLeaderStakeProposalParameters: ProposalParameters<BlockNumber, Balance> = ALL_PROPOSALS_PARAMETERS.decrease_working_group_leader_stake_proposal;
+    pub SlashWorkingGroupLeaderStakeProposalParameters: ProposalParameters<BlockNumber, Balance> = ALL_PROPOSALS_PARAMETERS.slash_working_group_leader_stake_proposal;
+    pub SetWorkingGroupLeaderRewardProposalParameters: ProposalParameters<BlockNumber, Balance> = ALL_PROPOSALS_PARAMETERS.set_working_group_leader_reward_proposal;
+    pub TerminateWorkingGroupLeaderRoleProposalParameters: ProposalParameters<BlockNumber, Balance> = ALL_PROPOSALS_PARAMETERS.terminate_working_group_leader_role_proposal;
+    pub AmendConstitutionProposalParameters: ProposalParameters<BlockNumber, Balance> = ALL_PROPOSALS_PARAMETERS.amend_constitution_proposal;
+}
+
+///////////
+
+struct AllProposalsParameters {
+    pub set_validator_count_proposal: ProposalParameters<BlockNumber, Balance>,
+    pub runtime_upgrade_proposal: ProposalParameters<BlockNumber, Balance>,
+    pub text_proposal: ProposalParameters<BlockNumber, Balance>,
+    pub spending_proposal: ProposalParameters<BlockNumber, Balance>,
+    pub add_working_group_opening_proposal: ProposalParameters<BlockNumber, Balance>,
+    pub begin_review_working_group_applications_proposal: ProposalParameters<BlockNumber, Balance>,
+    pub fill_working_group_opening_proposal: ProposalParameters<BlockNumber, Balance>,
+    pub set_working_group_mint_capacity_proposal: ProposalParameters<BlockNumber, Balance>,
+    pub decrease_working_group_leader_stake_proposal: ProposalParameters<BlockNumber, Balance>,
+    pub slash_working_group_leader_stake_proposal: ProposalParameters<BlockNumber, Balance>,
+    pub set_working_group_leader_reward_proposal: ProposalParameters<BlockNumber, Balance>,
+    pub terminate_working_group_leader_role_proposal: ProposalParameters<BlockNumber, Balance>,
+    pub amend_constitution_proposal: ProposalParameters<BlockNumber, Balance>,
+}
+
+// to initialize parameters only once.
+lazy_static! {
+    static ref ALL_PROPOSALS_PARAMETERS: AllProposalsParameters =
+        get_all_proposals_parameters_objects();
+}
+
+// We need to fail fast.
+#[allow(clippy::match_wild_err_arm)]
+// Composes AllProposalsParameters object from the JSON string.
+// It gets the JSON string from the environment variable and tries to parse it.
+// On error and any missing values it gets default values.
+fn get_all_proposals_parameters_objects() -> AllProposalsParameters {
+    let json_str: Option<&'static str> = option_env!("ALL_PROPOSALS_PARAMETERS_JSON");
+
+    json_str
+        .map(lite_json::parse_json)
+        .map(|res| match res {
+            Ok(json) => Some(json),
+            Err(_) => {
+                panic!("Invalid JSON with proposals parameters provided.");
+            }
+        })
+        .flatten()
+        .map(convert_json_object_to_proposal_parameters)
+        .unwrap_or_else(default_parameters)
+}
+
+// Helper macro for initializing single ProposalParameters object for a specified field of the
+// AllProposalsParameters object. It helps to reduce duplication of the field names for
+// AllProposalsParameters field, JSON object field name and default value function.
+// Consider this as duplication example:
+//         parameters.set_validator_count_proposal = create_proposal_parameters_object(
+//             json_object,
+//             "set_validator_count_proposal",
+//             defaults::set_validator_count_proposal(),
+//         );
+macro_rules! init_proposal_parameter_object {
+    ($parameters_object:ident, $jsonObj:expr, $name:ident) => {
+        $parameters_object.$name =
+            create_proposal_parameters_object($jsonObj, stringify!($name), defaults::$name());
+    };
+}
+
+// Tries to extract all proposal parameters from the parsed JSON object.
+fn convert_json_object_to_proposal_parameters(
+    json: lite_json::JsonValue,
+) -> AllProposalsParameters {
+    let mut params = default_parameters();
+
+    if let lite_json::JsonValue::Object(jo) = json {
+        init_proposal_parameter_object!(params, jo.clone(), set_validator_count_proposal);
+        init_proposal_parameter_object!(params, jo.clone(), runtime_upgrade_proposal);
+        init_proposal_parameter_object!(params, jo.clone(), text_proposal);
+        init_proposal_parameter_object!(params, jo.clone(), spending_proposal);
+        init_proposal_parameter_object!(params, jo.clone(), add_working_group_opening_proposal);
+        init_proposal_parameter_object!(
+            params,
+            jo.clone(),
+            begin_review_working_group_applications_proposal
+        );
+        init_proposal_parameter_object!(params, jo.clone(), fill_working_group_opening_proposal);
+        init_proposal_parameter_object!(
+            params,
+            jo.clone(),
+            set_working_group_mint_capacity_proposal
+        );
+        init_proposal_parameter_object!(
+            params,
+            jo.clone(),
+            decrease_working_group_leader_stake_proposal
+        );
+        init_proposal_parameter_object!(
+            params,
+            jo.clone(),
+            slash_working_group_leader_stake_proposal
+        );
+        init_proposal_parameter_object!(
+            params,
+            jo.clone(),
+            set_working_group_leader_reward_proposal
+        );
+        init_proposal_parameter_object!(
+            params,
+            jo.clone(),
+            terminate_working_group_leader_role_proposal
+        );
+        init_proposal_parameter_object!(params, jo, amend_constitution_proposal);
+    }
+
+    params
+}
+
+// Tries to create specific ProposalParameters object from the parsed JSON object.
+// Returns default parameters on missing values.
+fn create_proposal_parameters_object(
+    json_object: JsonObject,
+    proposal_name: &'static str,
+    defaults: ProposalParameters<BlockNumber, Balance>,
+) -> ProposalParameters<BlockNumber, Balance> {
+    json_object
+        .iter()
+        .find(|(name_vec, _)| name_vec.eq(&proposal_name.chars().collect::<Vec<_>>()))
+        .map(|(_, params)| extract_proposal_parameters(params, defaults))
+        .unwrap_or(defaults)
+}
+
+// Helper macro for initializing single field of the ProposalParameters object.
+// It helps to reduce duplication of the field names for ProposalParameters
+// field name, JSON object field name and default value field name.
+// Consider this as duplication example:
+//     ProposalParameters::<BlockNumber, Balance> {
+//         voting_period: extract_numeric_parameter(
+//             json_object,
+//             "voting_period",
+//             defaults.voting_period.saturated_into(),
+//         )
+//         .saturated_into(),
+//      ....
+//      }
+macro_rules! init_proposal_parameter_field {
+    ($parameters_object:ident, $jsonObj:expr, $default_object:ident, $name:ident) => {
+        $parameters_object.$name = extract_numeric_parameter(
+            $jsonObj,
+            stringify!($name),
+            $default_object.$name.saturated_into(),
+        )
+        .saturated_into();
+    };
+}
+
+// Helper macro similar to init_proposal_parameter_field but for optional parameters.
+// Zero value is wrapped as None.
+macro_rules! init_proposal_parameter_optional_field {
+    ($parameters_object:ident, $jsonObj:expr, $default_object:ident, $name:ident) => {
+        let param_value = extract_numeric_parameter(
+            $jsonObj,
+            stringify!($name),
+            $default_object.$name.unwrap_or_default().saturated_into(),
+        )
+        .saturated_into();
+        let opt_value = if param_value == 0 {
+            None
+        } else {
+            Some(param_value)
+        };
+
+        $parameters_object.$name = opt_value;
+    };
+}
+
+// Extracts proposal parameters from the parsed JSON object.
+fn extract_proposal_parameters(
+    json_object: &JsonValue,
+    defaults: ProposalParameters<BlockNumber, Balance>,
+) -> ProposalParameters<BlockNumber, Balance> {
+    let mut params = ProposalParameters::default();
+
+    init_proposal_parameter_field!(params, json_object, defaults, voting_period);
+    init_proposal_parameter_field!(params, json_object, defaults, grace_period);
+    init_proposal_parameter_field!(params, json_object, defaults, approval_quorum_percentage);
+    init_proposal_parameter_field!(params, json_object, defaults, approval_threshold_percentage);
+    init_proposal_parameter_field!(params, json_object, defaults, slashing_quorum_percentage);
+    init_proposal_parameter_field!(params, json_object, defaults, slashing_threshold_percentage);
+    init_proposal_parameter_optional_field!(params, json_object, defaults, required_stake);
+    init_proposal_parameter_field!(params, json_object, defaults, constitutionality);
+
+    params
+}
+
+// Extracts a specific numeric parameter from the parsed JSON object.
+fn extract_numeric_parameter(
+    json_object: &JsonValue,
+    parameter_name: &'static str,
+    default: u128,
+) -> u128 {
+    match json_object {
+        JsonValue::Object(json_object) => json_object
+            .iter()
+            .find(|(name_vec, _)| name_vec.eq(&parameter_name.chars().collect::<Vec<_>>()))
+            .map(|(_, value)| match value {
+                JsonValue::Number(number) => number.integer.saturated_into(),
+                _ => panic!("Incorrect JSON: not a number."),
+            })
+            .unwrap_or(default),
+        _ => default,
+    }
+}
+
+// Returns all default proposal parameters.
+fn default_parameters() -> AllProposalsParameters {
+    AllProposalsParameters {
+        set_validator_count_proposal: defaults::set_validator_count_proposal(),
+        runtime_upgrade_proposal: defaults::runtime_upgrade_proposal(),
+        text_proposal: defaults::text_proposal(),
+        spending_proposal: defaults::spending_proposal(),
+        add_working_group_opening_proposal: defaults::add_working_group_opening_proposal(),
+        begin_review_working_group_applications_proposal:
+            defaults::begin_review_working_group_applications_proposal(),
+        fill_working_group_opening_proposal: defaults::fill_working_group_opening_proposal(),
+        set_working_group_mint_capacity_proposal:
+            defaults::set_working_group_mint_capacity_proposal(),
+        decrease_working_group_leader_stake_proposal:
+            defaults::decrease_working_group_leader_stake_proposal(),
+        slash_working_group_leader_stake_proposal:
+            defaults::slash_working_group_leader_stake_proposal(),
+        set_working_group_leader_reward_proposal:
+            defaults::set_working_group_leader_reward_proposal(),
+        terminate_working_group_leader_role_proposal:
+            defaults::terminate_working_group_leader_role_proposal(),
+        amend_constitution_proposal: defaults::amend_constitution_proposal(),
+    }
+}

+ 25 - 0
runtime/src/proposals_configuration/sample_proposal_parameters.json

@@ -0,0 +1,25 @@
+{
+  "_comment": "This is a sample 'Proposal parameters' JSON file to enable conditional runtime compilation.",
+  "set_validator_count_proposal": {
+    "voting_period": 1,
+    "grace_period": 2,
+    "approval_quorum_percentage": 3,
+    "approval_threshold_percentage": 4,
+    "slashing_quorum_percentage": 5,
+    "slashing_threshold_percentage": 6,
+    "required_stake": 7,
+    "constitutionality": 8
+  },
+  "runtime_upgrade_proposal" : {},
+  "text_proposal": {},
+  "spending_proposal": {},
+  "add_working_group_opening_proposal": {},
+  "begin_review_working_group_applications_proposal": {},
+  "fill_working_group_opening_proposal": {},
+  "set_working_group_mint_capacity_proposal": {},
+  "decrease_working_group_leader_stake_proposal": {},
+  "slash_working_group_leader_stake_proposal": {},
+  "set_working_group_leader_reward_proposal": {},
+  "terminate_working_group_leader_role_proposal": {},
+  "amend_constitution_proposal": {}
+}

+ 20 - 0
runtime/src/proposals_configuration/tests.rs

@@ -0,0 +1,20 @@
+use crate::ProposalParameters;
+
+// Enable during the conditional compilation tests.
+#[ignore]
+#[test]
+fn proposal_parameters_are_initialized() {
+    let actual_params = super::SetValidatorCountProposalParameters::get();
+    let expected_params = ProposalParameters {
+        voting_period: 1,
+        grace_period: 2,
+        approval_quorum_percentage: 3,
+        approval_threshold_percentage: 4,
+        slashing_quorum_percentage: 5,
+        slashing_threshold_percentage: 6,
+        required_stake: Some(7),
+        constitutionality: 8,
+    };
+
+    assert_eq!(expected_params, actual_params);
+}

+ 48 - 0
runtime/src/runtime_api.rs

@@ -254,4 +254,52 @@ impl_runtime_apis! {
             SessionKeys::decode_into_raw_public_keys(&encoded)
         }
     }
+
+     #[cfg(feature = "runtime-benchmarks")]
+    impl frame_benchmarking::Benchmark<Block> for Runtime {
+        fn dispatch_benchmark(
+            pallet: Vec<u8>,
+            benchmark: Vec<u8>,
+            lowest_range_values: Vec<u32>,
+            highest_range_values: Vec<u32>,
+            steps: Vec<u32>,
+            repeat: u32,
+        ) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, sp_runtime::RuntimeString> {
+            /*
+             * TODO: remember to benchhmark every pallet
+             */
+            use sp_std::vec;
+            use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark};
+            use frame_system_benchmarking::Module as SystemBench;
+            impl frame_system_benchmarking::Trait for Runtime {}
+
+            use crate::ProposalsDiscussion;
+
+            let whitelist: Vec<Vec<u8>> = vec![
+                // Block Number
+                hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec(),
+                // Total Issuance
+                hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec(),
+                // Execution Phase
+                hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec(),
+                // Event Count
+                hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec(),
+                // System Events
+                hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec(),
+                // Caller 0 Account
+                hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da946c154ffd9992e395af90b5b13cc6f295c77033fce8a9045824a6690bbf99c6db269502f0a8d1d2a008542d5690a0749").to_vec(),
+                // Treasury Account
+                hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da95ecffd7b6c0f78751baa9d281e0bfa3a6d6f646c70792f74727372790000000000000000000000000000000000000000").to_vec(),
+            ];
+
+            let mut batches = Vec::<BenchmarkBatch>::new();
+            let params = (&pallet, &benchmark, &lowest_range_values, &highest_range_values, &steps, repeat, &whitelist);
+
+            add_benchmark!(params, batches, b"system", SystemBench::<Runtime>);
+            add_benchmark!(params, batches, b"proposals-discussion", ProposalsDiscussion);
+
+            if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
+            Ok(batches)
+        }
+    }
 }

+ 116 - 93
runtime/src/tests/proposals_integration/mod.rs

@@ -9,9 +9,8 @@ use codec::Encode;
 use governance::election_params::ElectionParameters;
 use membership;
 use proposals_engine::{
-    ActiveStake, ApprovedProposalStatus, BalanceOf, FinalizationData, Proposal,
-    ProposalDecisionStatus, ProposalParameters, ProposalStatus, VoteKind, VotersParameters,
-    VotingResults,
+    ApprovedProposalDecision, BalanceOf, Proposal, ProposalCreationParameters, ProposalParameters,
+    ProposalStatus, VoteKind, VotersParameters, VotingResults,
 };
 
 use frame_support::dispatch::{DispatchError, DispatchResult};
@@ -136,6 +135,7 @@ impl VoteGenerator {
             self.current_voter_id,
             self.proposal_id,
             vote_kind,
+            Vec::new(),
         )
     }
 }
@@ -148,7 +148,8 @@ struct DummyProposalFixture {
     proposal_code: Vec<u8>,
     title: Vec<u8>,
     description: Vec<u8>,
-    stake_balance: Option<BalanceOf<Runtime>>,
+    staking_account_id: Option<AccountId32>,
+    exact_execution_block: Option<u32>,
 }
 
 impl Default for DummyProposalFixture {
@@ -167,13 +168,15 @@ impl Default for DummyProposalFixture {
                 slashing_threshold_percentage: 60,
                 grace_period: 0,
                 required_stake: None,
+                constitutionality: 1,
             },
             account_id: <Runtime as frame_system::Trait>::AccountId::default(),
             proposer_id: 0,
             proposal_code: dummy_proposal.encode(),
             title,
             description,
-            stake_balance: None,
+            staking_account_id: None,
+            exact_execution_block: None,
         }
     }
 }
@@ -183,6 +186,16 @@ impl DummyProposalFixture {
         DummyProposalFixture { parameters, ..self }
     }
 
+    fn with_constitutionality(&self, constitutionality: u32) -> Self {
+        DummyProposalFixture {
+            parameters: ProposalParameters {
+                constitutionality,
+                ..self.parameters
+            },
+            ..self.clone()
+        }
+    }
+
     fn with_account_id(self, account_id: AccountId32) -> Self {
         DummyProposalFixture { account_id, ..self }
     }
@@ -197,9 +210,9 @@ impl DummyProposalFixture {
         }
     }
 
-    fn with_stake(self, stake_balance: BalanceOf<Runtime>) -> Self {
+    fn with_stake(self, account_id: AccountId32) -> Self {
         DummyProposalFixture {
-            stake_balance: Some(stake_balance),
+            staking_account_id: Some(account_id),
             ..self
         }
     }
@@ -212,15 +225,17 @@ impl DummyProposalFixture {
     }
 
     fn create_proposal_and_assert(self, result: Result<u32, DispatchError>) -> Option<u32> {
-        let proposal_id_result = ProposalsEngine::create_proposal(
-            self.account_id,
-            self.proposer_id,
-            self.parameters,
-            self.title,
-            self.description,
-            self.stake_balance,
-            self.proposal_code,
-        );
+        let proposal_id_result = ProposalsEngine::create_proposal(ProposalCreationParameters {
+            account_id: self.account_id,
+            proposer_id: self.proposer_id,
+            proposal_parameters: self.parameters,
+            title: self.title,
+            description: self.description,
+            staking_account_id: self.staking_account_id,
+            encoded_dispatchable_call_code: self.proposal_code,
+            exact_execution_block: self.exact_execution_block,
+        });
+
         assert_eq!(proposal_id_result, result);
 
         proposal_id_result.ok()
@@ -281,11 +296,12 @@ fn proposal_cancellation_with_slashes_with_balance_checks_succeeds() {
             slashing_threshold_percentage: 60,
             grace_period: 5,
             required_stake: Some(stake_amount),
+            constitutionality: 1,
         };
         let dummy_proposal = DummyProposalFixture::default()
             .with_parameters(parameters)
             .with_account_id(account_id.clone())
-            .with_stake(stake_amount)
+            .with_stake(account_id.clone())
             .with_proposer(member_id);
 
         let account_balance = 500000;
@@ -293,29 +309,27 @@ fn proposal_cancellation_with_slashes_with_balance_checks_succeeds() {
             <Runtime as stake::Trait>::Currency::deposit_creating(&account_id, account_balance);
 
         assert_eq!(
-            <Runtime as stake::Trait>::Currency::total_balance(&account_id),
+            <Runtime as stake::Trait>::Currency::usable_balance(&account_id),
             account_balance
         );
 
         let proposal_id = dummy_proposal.create_proposal_and_assert(Ok(1)).unwrap();
         assert_eq!(
-            <Runtime as stake::Trait>::Currency::total_balance(&account_id),
+            <Runtime as stake::Trait>::Currency::usable_balance(&account_id),
             account_balance - stake_amount
         );
 
-        let mut proposal = ProposalsEngine::proposals(proposal_id);
+        let proposal = ProposalsEngine::proposals(proposal_id);
 
-        let mut expected_proposal = Proposal {
+        let expected_proposal = Proposal {
             parameters,
             proposer_id: member_id,
-            created_at: 0,
-            status: ProposalStatus::Active(Some(ActiveStake {
-                stake_id: 0,
-                source_account_id: account_id.clone(),
-            })),
-            title: b"title".to_vec(),
-            description: b"description".to_vec(),
+            activated_at: 0,
+            status: ProposalStatus::Active,
             voting_results: VotingResults::default(),
+            exact_execution_block: None,
+            current_constitutionality_level: 0,
+            staking_account_id: Some(account_id.clone()),
         };
 
         assert_eq!(proposal, expected_proposal);
@@ -325,20 +339,9 @@ fn proposal_cancellation_with_slashes_with_balance_checks_succeeds() {
 
         cancel_proposal_fixture.cancel_and_assert(Ok(()));
 
-        proposal = ProposalsEngine::proposals(proposal_id);
-
-        expected_proposal.status = ProposalStatus::Finalized(FinalizationData {
-            proposal_status: ProposalDecisionStatus::Canceled,
-            finalized_at: 0,
-            encoded_unstaking_error_due_to_broken_runtime: None,
-            stake_data_after_unstaking_error: None,
-        });
-
-        assert_eq!(proposal, expected_proposal);
-
         let cancellation_fee = ProposalCancellationFee::get() as u128;
         assert_eq!(
-            <Runtime as stake::Trait>::Currency::total_balance(&account_id),
+            <Runtime as stake::Trait>::Currency::usable_balance(&account_id),
             account_balance - cancellation_fee
         );
     });
@@ -359,8 +362,6 @@ fn proposal_reset_succeeds() {
         vote_generator.vote_and_assert_ok(VoteKind::Abstain);
         vote_generator.vote_and_assert_ok(VoteKind::Slash);
 
-        assert!(<proposals_engine::ActiveProposalIds<Runtime>>::contains_key(proposal_id));
-
         // check
         let proposal = ProposalsEngine::proposals(proposal_id);
         assert_eq!(
@@ -507,7 +508,7 @@ where
             setup_members(15);
             setup_council();
 
-            increase_total_balance_issuance_using_account_id(account_id.clone().into(), 500000);
+            increase_total_balance_issuance_using_account_id(account_id.clone().into(), 1_500_000);
         }
 
         assert_eq!((self.successful_call)(), Ok(()));
@@ -520,27 +521,6 @@ where
         vote_generator.vote_and_assert_ok(VoteKind::Approve);
 
         run_to_block(self.run_to_block);
-
-        let proposal = ProposalsEngine::proposals(self.proposal_id);
-
-        assert_eq!(
-            proposal,
-            Proposal {
-                status: ProposalStatus::approved(
-                    ApprovedProposalStatus::Executed,
-                    self.run_to_block - 2
-                ),
-                title: b"title".to_vec(),
-                description: b"body".to_vec(),
-                voting_results: VotingResults {
-                    abstentions: 0,
-                    approvals: 5,
-                    rejections: 0,
-                    slashes: 0,
-                },
-                ..proposal
-            }
-        );
     }
 }
 
@@ -556,8 +536,9 @@ fn text_proposal_execution_succeeds() {
                 member_id as u64,
                 b"title".to_vec(),
                 b"body".to_vec(),
-                Some(<BalanceOf<Runtime>>::from(25000u32)),
+                Some(account_id.into()),
                 b"text".to_vec(),
+                None,
             )
         })
         .with_member_id(member_id as u64);
@@ -583,9 +564,10 @@ fn spending_proposal_execution_succeeds() {
                 member_id as u64,
                 b"title".to_vec(),
                 b"body".to_vec(),
-                Some(<BalanceOf<Runtime>>::from(25_000_u32)),
+                Some(account_id.into()),
                 new_balance,
                 target_account_id.clone().into(),
+                None,
             )
         })
         .with_member_id(member_id as u64);
@@ -595,65 +577,106 @@ fn spending_proposal_execution_succeeds() {
 
         codex_extrinsic_test_fixture.call_extrinsic_and_assert();
 
+        run_to_block(14410);
+
         assert_eq!(Balances::free_balance(converted_account_id), new_balance);
     });
 }
 
 #[test]
-fn set_election_parameters_proposal_execution_succeeds() {
+fn set_validator_count_proposal_execution_succeeds() {
     initial_test_ext().execute_with(|| {
         let member_id = 1;
         let account_id: [u8; 32] = [member_id; 32];
 
-        let election_parameters = ElectionParameters {
-            announcing_period: 14400,
-            voting_period: 14400,
-            revealing_period: 14400,
-            council_size: 4,
-            candidacy_limit: 25,
-            new_term_duration: 14400,
-            min_council_stake: 1,
-            min_voting_stake: 1,
-        };
-        assert_eq!(Election::announcing_period(), 0);
+        let new_validator_count = 8;
+        assert_eq!(<pallet_staking::ValidatorCount>::get(), 0);
 
         let codex_extrinsic_test_fixture = CodexProposalTestFixture::default_for_call(|| {
-            ProposalCodex::create_set_election_parameters_proposal(
+            ProposalCodex::create_set_validator_count_proposal(
                 RawOrigin::Signed(account_id.clone().into()).into(),
                 member_id as u64,
                 b"title".to_vec(),
                 b"body".to_vec(),
-                Some(<BalanceOf<Runtime>>::from(200_000_u32)),
-                election_parameters,
+                Some(account_id.into()),
+                new_validator_count,
+                None,
             )
         });
         codex_extrinsic_test_fixture.call_extrinsic_and_assert();
 
-        assert_eq!(Election::announcing_period(), 14400);
+        run_to_block(14410);
+
+        assert_eq!(<pallet_staking::ValidatorCount>::get(), new_validator_count);
     });
 }
 
 #[test]
-fn set_validator_count_proposal_execution_succeeds() {
+fn amend_constitution_proposal_execution_succeeds() {
     initial_test_ext().execute_with(|| {
-        let member_id = 1;
+        let member_id = 10;
         let account_id: [u8; 32] = [member_id; 32];
 
-        let new_validator_count = 8;
-        assert_eq!(<pallet_staking::ValidatorCount>::get(), 0);
-
         let codex_extrinsic_test_fixture = CodexProposalTestFixture::default_for_call(|| {
-            ProposalCodex::create_set_validator_count_proposal(
-                RawOrigin::Signed(account_id.clone().into()).into(),
+            ProposalCodex::create_amend_constitution_proposal(
+                RawOrigin::Signed(account_id.into()).into(),
                 member_id as u64,
                 b"title".to_vec(),
                 b"body".to_vec(),
-                Some(<BalanceOf<Runtime>>::from(100_000_u32)),
-                new_validator_count,
+                Some(account_id.into()),
+                b"Constitution text".to_vec(),
+                None,
             )
-        });
+        })
+        .with_member_id(member_id as u64);
+
         codex_extrinsic_test_fixture.call_extrinsic_and_assert();
+    });
+}
 
-        assert_eq!(<pallet_staking::ValidatorCount>::get(), new_validator_count);
+#[test]
+fn proposal_reactivation_succeeds() {
+    initial_test_ext().execute_with(|| {
+        let starting_block = 0;
+        setup_members(5);
+        setup_council();
+        // create proposal
+        let dummy_proposal = DummyProposalFixture::default()
+            .with_voting_period(100)
+            .with_constitutionality(2);
+        let proposal_id = dummy_proposal.create_proposal_and_assert(Ok(1)).unwrap();
+
+        // create some votes
+        let mut vote_generator = VoteGenerator::new(proposal_id);
+        vote_generator.vote_and_assert_ok(VoteKind::Approve);
+        vote_generator.vote_and_assert_ok(VoteKind::Approve);
+        vote_generator.vote_and_assert_ok(VoteKind::Approve);
+        vote_generator.vote_and_assert_ok(VoteKind::Approve);
+
+        run_to_block(2);
+
+        // check
+        let proposal = ProposalsEngine::proposals(proposal_id);
+        assert_eq!(
+            proposal.status,
+            ProposalStatus::approved(
+                ApprovedProposalDecision::PendingConstitutionality,
+                starting_block
+            )
+        );
+
+        // Ensure council was elected
+        assert_eq!(CouncilManager::<Runtime>::total_voters_count(), 6);
+
+        elect_single_councilor();
+
+        run_to_block(10);
+
+        let updated_proposal = ProposalsEngine::proposals(proposal_id);
+
+        assert_eq!(updated_proposal.status, ProposalStatus::Active);
+
+        // Check council CouncilElected hook. It should set current council. And we elected single councilor.
+        assert_eq!(CouncilManager::<Runtime>::total_voters_count(), 1);
     });
 }

+ 24 - 9
runtime/src/tests/proposals_integration/working_group_proposals.rs

@@ -68,7 +68,7 @@ fn add_opening(
             member_id as u64,
             b"title".to_vec(),
             b"body".to_vec(),
-            Some(<BalanceOf<Runtime>>::from(100_000_u32)),
+            Some(account_id.into()),
             AddOpeningParameters {
                 activate_at: activate_at.clone(),
                 commitment: opening_policy_commitment
@@ -77,6 +77,7 @@ fn add_opening(
                 human_readable_text: Vec::new(),
                 working_group,
             },
+            None,
         )
     })
     .with_expected_proposal_id(expected_proposal_id)
@@ -103,9 +104,10 @@ fn begin_review_applications(
             member_id,
             b"title".to_vec(),
             b"body".to_vec(),
-            Some(<BalanceOf<Runtime>>::from(25_000_u32)),
+            Some(account_id.into()),
             opening_id,
             working_group,
+            None,
         )
     })
     .disable_setup_enviroment()
@@ -133,13 +135,14 @@ fn fill_opening(
             member_id,
             b"title".to_vec(),
             b"body".to_vec(),
-            Some(<BalanceOf<Runtime>>::from(50_000_u32)),
+            Some(account_id.into()),
             proposals_codex::FillOpeningParameters {
                 opening_id,
                 successful_application_id,
                 reward_policy: reward_policy.clone(),
                 working_group,
             },
+            None,
         )
     })
     .disable_setup_enviroment()
@@ -174,10 +177,11 @@ fn decrease_stake(
             member_id,
             b"title".to_vec(),
             b"body".to_vec(),
-            Some(<BalanceOf<Runtime>>::from(50_000_u32)),
+            Some(account_id.into()),
             leader_worker_id,
             stake_amount,
             working_group,
+            None,
         )
     })
     .disable_setup_enviroment()
@@ -204,10 +208,11 @@ fn slash_stake(
             member_id,
             b"title".to_vec(),
             b"body".to_vec(),
-            Some(<BalanceOf<Runtime>>::from(50_000_u32)),
+            Some(account_id.into()),
             leader_worker_id,
             stake_amount,
             working_group,
+            None,
         )
     })
     .disable_setup_enviroment()
@@ -234,10 +239,11 @@ fn set_reward(
             member_id as u64,
             b"title".to_vec(),
             b"body".to_vec(),
-            Some(<BalanceOf<Runtime>>::from(50_000_u32)),
+            Some(account_id.into()),
             leader_worker_id,
             reward_amount,
             working_group,
+            None,
         )
     })
     .disable_setup_enviroment()
@@ -276,9 +282,10 @@ fn set_mint_capacity<
             member_id,
             b"title".to_vec(),
             b"body".to_vec(),
-            Some(<BalanceOf<Runtime>>::from(50_000_u32)),
+            Some(account_id.into()),
             mint_capacity,
             working_group,
+            None,
         )
     })
     .with_setup_enviroment(setup_environment)
@@ -305,13 +312,14 @@ fn terminate_role(
             member_id,
             b"title".to_vec(),
             b"body".to_vec(),
-            Some(<BalanceOf<Runtime>>::from(100_000_u32)),
+            Some(account_id.into()),
             proposals_codex::TerminateRoleParameters {
                 worker_id: leader_worker_id,
                 rationale: Vec::new(),
                 slash,
                 working_group,
             },
+            None,
         )
     })
     .disable_setup_enviroment()
@@ -453,6 +461,8 @@ fn run_create_begin_review_working_group_leader_applications_proposal_execution_
         );
 
         begin_review_applications(member_id, account_id, opening_id, 2, working_group);
+        let grace_period = 14400;
+        run_to_block(grace_period + 10);
 
         let hiring_opening = Hiring::opening_by_id(hiring_opening_id);
         assert_eq!(
@@ -460,7 +470,7 @@ fn run_create_begin_review_working_group_leader_applications_proposal_execution_
             hiring::OpeningStage::Active {
                 stage: hiring::ActiveOpeningStage::ReviewPeriod {
                     started_accepting_applicants_at_block: 0,
-                    started_review_period_at_block: 2,
+                    started_review_period_at_block: grace_period + 2,
                 },
                 applications_added: BTreeSet::new(),
                 active_application_count: 0,
@@ -539,6 +549,9 @@ fn create_fill_working_group_leader_opening_proposal_execution_succeeds() {
             let lead = WorkingGroupInstance::<T, I>::current_lead();
             assert!(lead.is_none());
 
+            let grace_period_for_begin_application_proposal = 14400;
+            run_to_block(grace_period_for_begin_application_proposal + 20);
+
             fill_opening(
                 member_id,
                 account_id,
@@ -549,6 +562,8 @@ fn create_fill_working_group_leader_opening_proposal_execution_succeeds() {
                 working_group,
             );
 
+            run_to_block(grace_period_for_begin_application_proposal + 30);
+
             let lead = WorkingGroupInstance::<T, I>::current_lead();
             assert!(lead.is_some());
         });

+ 0 - 8
rust-builder.Dockerfile

@@ -1,8 +0,0 @@
-FROM liuchong/rustup:1.46.0 AS builder
-LABEL description="Rust and WASM build environment for joystream and substrate"
-
-WORKDIR /setup
-COPY setup.sh /setup
-ENV TERM=xterm
-
-RUN ./setup.sh

+ 7 - 8
scripts/runtime-code-shasum.sh

@@ -7,17 +7,16 @@ export WORKSPACE_ROOT=`cargo metadata --offline --no-deps --format-version 1 | j
 
 cd ${WORKSPACE_ROOT}
 
-# srot/owner/group/mtime arguments only work with gnu version of tar.
-# So if you run this on Mac the default version of tar is `bsdtar`
-# and you will not get an idempotent result.
-# Install gnu-tar with brew
-#   brew install gnu-tar
-#   export PATH="/usr/local/opt/gnu-tar/libexec/gnubin:$PATH"
-tar -c --sort=name --owner=root:0 --group=root:0 --mtime='UTC 2020-01-01' \
+TAR=tar
+if [[ "$OSTYPE" == "darwin"* ]]; then
+	TAR=gtar
+fi
+
+# sort/owner/group/mtime arguments only work with gnu version of tar!
+${TAR} -c --sort=name --owner=root:0 --group=root:0 --mtime='UTC 2020-01-01' \
     Cargo.lock \
     Cargo.toml \
     runtime \
     runtime-modules \
     utils/chain-spec-builder \
     joystream-node.Dockerfile | shasum | cut -d " " -f 1
-

+ 18 - 13
setup.sh

@@ -2,11 +2,8 @@
 
 set -e
 
-# If OS is supported will install:
-#  - build tools and any other dependencies required for rust and substrate
-#  - rustup - rust insaller
-#  - rust compiler and toolchains
-#  - skips installing substrate and subkey
+# If OS is supported will install build tools for rust and substrate.
+# Skips installing substrate itself and subkey
 curl https://getsubstrate.io -sSf | bash -s -- --fast
 
 source ~/.cargo/env
@@ -19,13 +16,21 @@ rustup component add rustfmt clippy
 rustup install nightly-2020-10-06 --force
 rustup target add wasm32-unknown-unknown --toolchain nightly-2020-10-06
 
-# Ensure the stable toolchain is still the default
-rustup default stable
+# Sticking with older version of compiler to ensure working build
+rustup install 1.47.0
+rustup default 1.47.0
 
-# TODO: Install additional tools...
+if [[ "$OSTYPE" == "linux-gnu" ]]; then
+    apt-get install -y coreutils clang jq curl gcc xz-utils sudo pkg-config unzip clang libc6-dev-i386
+    apt-get install -y docker.io docker-compose
+elif [[ "$OSTYPE" == "darwin"* ]]; then
+    brew install b2sum gnu-tar jq curl
+    echo "It is recommended to setup Docker desktop from: https://www.docker.com/products/docker-desktop"
+fi
 
-# - b2sum
-# - nodejs
-# - npm
-# - yarn
-# .... ?
+# Volta nodejs, npm, yarn tools manager
+curl https://get.volta.sh | bash
+
+volta install node@12
+volta install yarn
+volta install npx

+ 39 - 0
start.sh

@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+set -e
+
+# Run a complete joystream development network on your machine using docker.
+# Make sure to run build.sh prior to running this script.
+
+# Clean start!
+docker-compose down -v
+
+function down()
+{
+    # Stop containers and clear volumes
+    docker-compose down -v
+}
+
+trap down EXIT
+
+# Run a local development chain
+docker-compose up -d joystream-node
+
+## Storage Infrastructure
+# Configure a dev storage node and start storage node
+DEBUG=joystream:storage-cli:dev yarn storage-cli dev-init
+docker-compose up -d colossus
+# Initialise the content directory with standard classes, schemas and initial entities
+yarn workspace cd-schemas initialize:dev
+
+## Query Node Infrastructure
+# Initialize a new database for the query node infrastructure
+docker-compose up -d db
+yarn workspace query-node-root db:migrate
+# Startup all query-node infrastructure services
+docker-compose up -d graphql-server
+docker-compose up -d processor
+
+echo "press Ctrl+C to shutdown"
+
+# Start a dev instance of pioneer and wait for exit
+docker-compose up pioneer

+ 1 - 0
storage-node/README.md

@@ -35,6 +35,7 @@ _Building_
 
 ```bash
 $ yarn install
+$ yarn build
 ```
 
 The command will install dependencies, and make a `colossus` executable available:

+ 0 - 29
storage-node/docker-compose.yaml

@@ -1,29 +0,0 @@
-version: '3'
-services:
-  ipfs:
-    image: ipfs/go-ipfs:latest
-    ports:
-      - '127.0.0.1:5001:5001'
-      - '127.0.0.1:8080:8080'
-    volumes:
-      - ipfs-data:/data/ipfs
-    entrypoint: ''
-    command: |
-      /bin/sh -c "
-        set -e
-        /usr/local/bin/start_ipfs config profile apply lowpower
-        /usr/local/bin/start_ipfs config --json Gateway.PublicGateways '{\"localhost\": null }'
-        /sbin/tini -- /usr/local/bin/start_ipfs daemon --migrate=true
-      "
-  chain:
-    image: joystream/node:latest
-    ports:
-      - '127.0.0.1:9944:9944'
-    volumes:
-      - chain-data:/data
-    command: --dev --ws-external --base-path /data
-volumes:
-  ipfs-data:
-    driver: local
-  chain-data:
-    driver: local

+ 3 - 0
storage-node/package.json

@@ -48,5 +48,8 @@
     "prettier": "^2.0.5",
     "typescript": "^3.9.6",
     "wsrun": "^3.6.5"
+  },
+  "volta": {
+    "extends": "../package.json"
   }
 }

+ 3 - 0
storage-node/packages/cli/package.json

@@ -26,6 +26,9 @@
   "engines": {
     "node": ">=12.18.0"
   },
+  "volta": {
+    "extends": "../package.json"
+  },
   "scripts": {
     "test": "mocha 'dist/test/**/*.js'",
     "lint": "eslint --ext .js,.ts . && tsc --noEmit --pretty",

+ 3 - 0
storage-node/packages/colossus/package.json

@@ -31,6 +31,9 @@
   "engines": {
     "node": ">=12.18.0"
   },
+  "volta": {
+    "extends": "../package.json"
+  },
   "scripts": {
     "test": "mocha 'test/**/*.js'",
     "lint": "eslint 'paths/**/*.js' 'lib/**/*.js'",

+ 3 - 0
storage-node/packages/helios/package.json

@@ -14,5 +14,8 @@
     "@types/bn.js": "^4.11.5",
     "axios": "^0.19.0",
     "bn.js": "^4.11.8"
+  },
+  "volta": {
+    "extends": "../package.json"
   }
 }

+ 0 - 38
storage-node/start-dev.sh

@@ -1,38 +0,0 @@
-#!/usr/bin/env bash
-set -e
-
-# Avoid pulling joystream/node from docker hub. It is most likely
-# not the version that we want to work with. Either you should
-# build it locally or pull it down manually.
-if ! docker inspect joystream/node:latest > /dev/null 2>&1;
-then
-  echo "Didn't find local joystream/node:latest docker image."
-  exit 1
-fi
-
-SCRIPT_PATH="$(dirname "${BASH_SOURCE[0]}")"
-cd $SCRIPT_PATH
-
-# stop prior run and clear volumes
-# docker-compose down -v
-
-# Run a development joystream-node chain and ipfs daemon in the background
-docker-compose up -d
-
-function down()
-{
-    # Stop containers and clear volumes
-    docker-compose down -v
-}
-
-trap down EXIT
-
-# configure the dev chain
-DEBUG=joystream:storage-cli:dev yarn storage-cli dev-init
-
-# Run the tests
-# Tests sometimes fail, so skip for now
-# yarn workspace storage-node test
-
-# Start Colossus storage-node
-DEBUG=joystream:* yarn colossus --dev

+ 0 - 5
storage-node/stop-dev.sh

@@ -1,5 +0,0 @@
-#!/usr/bin/env bash
-set -e
-
-# stop prior run and clear volumes
-docker-compose down -v

+ 1 - 1
tests/network-tests/.env

@@ -1,7 +1,7 @@
 # Address of the Joystream node.
 NODE_URL = ws://127.0.0.1:9944
 # Address of the Joystream query node.
-QUERY_NODE_URL = http://127.0.0.1:8080/graphql
+QUERY_NODE_URL = http://127.0.0.1:8081/graphql
 # Account which is expected to provide sufficient funds to test accounts.
 TREASURY_ACCOUNT_URI = //Alice
 # Sudo Account

+ 3 - 0
tests/network-tests/package.json

@@ -32,5 +32,8 @@
     "prettier": "2.0.2",
     "ts-node": "^8.8.1",
     "typescript": "^3.8.3"
+  },
+  "volta": {
+    "extends": "../../package.json"
   }
 }

+ 5 - 1
types/package.json

@@ -59,5 +59,9 @@
   "bugs": {
     "url": "https://github.com/Joystream/joystream/issues"
   },
-  "homepage": "https://github.com/Joystream/joystream"
+  "homepage": "https://github.com/Joystream/joystream",
+  "volta": {
+    "node": "12.18.2",
+    "yarn": "1.22.4"
+  }
 }

+ 3 - 0
utils/api-scripts/package.json

@@ -22,5 +22,8 @@
     "@polkadot/ts": "^0.1.56",
     "typescript": "^3.9.7",
     "ts-node": "^8.6.2"
+  },
+  "volta": {
+    "extends": "../../package.json"
   }
 }

+ 1 - 1
utils/api-scripts/src/dev-set-runtime-code.ts

@@ -32,7 +32,7 @@ async function main() {
   const provider = new WsProvider('ws://127.0.0.1:9944')
 
   let api: ApiPromise
-  let retry = 3
+  let retry = 6
   while (true) {
     try {
       api = await ApiPromise.create({ provider, types })

+ 2 - 9
utils/chain-spec-builder/src/main.rs

@@ -25,7 +25,7 @@ use structopt::StructOpt;
 
 use joystream_node::chain_spec::{
     self, chain_spec_properties, content_config, forum_config, initial_balances, initial_members,
-    proposals_config, AccountId,
+    AccountId,
 };
 
 use sc_chain_spec::ChainType;
@@ -216,7 +216,7 @@ impl ChainSpecBuilder {
 // as more args will likely be needed
 #[allow(clippy::too_many_arguments)]
 fn genesis_constructor(
-    deployment: &ChainDeployment,
+    _deployment: &ChainDeployment,
     authority_seeds: &[String],
     endowed_accounts: &[AccountId],
     sudo_account: &AccountId,
@@ -269,17 +269,10 @@ fn genesis_constructor(
         .map(|path| initial_balances::from_json(path.as_path()))
         .unwrap_or_else(Vec::new);
 
-    let proposals_cfg = match deployment {
-        ChainDeployment::live => proposals_config::production(),
-        ChainDeployment::staging => proposals_config::staging(),
-        _ => proposals_config::development(),
-    };
-
     chain_spec::testnet_genesis(
         authorities,
         sudo_account.clone(),
         endowed_accounts.to_vec(),
-        proposals_cfg,
         members,
         forum_cfg,
         versioned_store_cfg,

+ 42 - 34
yarn.lock

@@ -1388,10 +1388,10 @@
     ajv "^6.12.0"
     ajv-keywords "^3.4.1"
 
-"@dzlzv/hydra-cli@^0.0.17":
-  version "0.0.17"
-  resolved "https://registry.yarnpkg.com/@dzlzv/hydra-cli/-/hydra-cli-0.0.17.tgz#56ccae132f76e738724cdc5f0abcd47ff25df530"
-  integrity sha512-ixrjGn6a7UG7ecHYKWTHpcxbdi6X32NbtyCuewm4YGFdb+v0/Eg5zWhFbg1PbMUW9GllC4MiIjDF7Bh1fh9t7Q==
+"@dzlzv/hydra-cli@^0.0.20":
+  version "0.0.20"
+  resolved "https://registry.yarnpkg.com/@dzlzv/hydra-cli/-/hydra-cli-0.0.20.tgz#8837ab287966ba30130cecfa77f27a2d6aad7061"
+  integrity sha512-pFDL2ZkbUyvSGgklmFNAxA2Y/afCJSxvKQHspjuxwhscsjTq0ay05mEtARbvDhLI1yN7jWedfyzQNUtQPCYHuA==
   dependencies:
     "@oclif/command" "^1.5.20"
     "@oclif/config" "^1"
@@ -1415,7 +1415,7 @@
     typeorm-model-generator "^0.4.2"
     warthog "https://github.com/metmirr/warthog/releases/download/v2.20.0/warthog-v2.20.0.tgz"
 
-"@dzlzv/hydra-indexer-lib@^0.0.19-legacy.1.26.1":
+"@dzlzv/hydra-indexer-lib@0.0.19-legacy.1.26.1", "@dzlzv/hydra-indexer-lib@^0.0.19-legacy.1.26.1":
   version "0.0.19-legacy.1.26.1"
   resolved "https://registry.yarnpkg.com/@dzlzv/hydra-indexer-lib/-/hydra-indexer-lib-0.0.19-legacy.1.26.1.tgz#346b564845b2014f7a4d9b3976c03e30da8dd309"
   integrity sha512-4pwaSDRIo/1MqxjfSotjv91fkIj/bfZcZx5nqjB9gRT85X28b3WqkqTFrzlGsGGbvUFWAx4WIeQKnY1yrpX89Q==
@@ -3400,7 +3400,7 @@
     is-ipfs "^0.6.0"
     recursive-fs "^1.1.2"
 
-"@polkadot/api-contract@^1.26.1":
+"@polkadot/api-contract@1.26.1", "@polkadot/api-contract@^1.26.1":
   version "1.26.1"
   resolved "https://registry.yarnpkg.com/@polkadot/api-contract/-/api-contract-1.26.1.tgz#a8b52ef469ab8bbddb83191f8d451e31ffd76142"
   integrity sha512-zLGA/MHUJf12vanUEUBBRqpHVAONHWztoHS0JTIWUUS2+3GEXk6hGw+7PPtBDfDsLj0LgU/Qna1bLalC/zyl5w==
@@ -4938,7 +4938,7 @@
   resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.159.tgz#61089719dc6fdd9c5cb46efc827f2571d1517065"
   integrity sha512-gF7A72f7WQN33DpqOWw9geApQPh4M3PxluMtaHxWHXEGSN12/WbcEk/eNSqWNQcQhF66VSZ06vCF94CrHwXJDg==
 
-"@types/lodash@^4.14.148", "@types/lodash@^4.14.161":
+"@types/lodash@^4.14.148":
   version "4.14.164"
   resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.164.tgz#52348bcf909ac7b4c1bcbeda5c23135176e5dfa0"
   integrity sha512-fXCEmONnrtbYUc5014avwBeMdhHHO8YJCkOBflUL9EoJBSKZ1dei+VO74fA7JkTHZ1GvZack2TyIw5U+1lT8jg==
@@ -4948,6 +4948,11 @@
   resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.157.tgz#fdac1c52448861dfde1a2e1515dbc46e54926dc8"
   integrity sha512-Ft5BNFmv2pHDgxV5JDsndOWTRJ+56zte0ZpYLowp03tW+K+t8u8YMOzAnpuqPgzX6WO1XpDIUm7u04M8vdDiVQ==
 
+"@types/lodash@^4.14.161":
+  version "4.14.165"
+  resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.165.tgz#74d55d947452e2de0742bad65270433b63a8c30f"
+  integrity sha512-tjSSOTHhI5mCHTy/OOXYIhi2Wt1qcbHmuXD1Ha7q70CgI/I71afO4XtLb/cVexki1oVYchpul/TOuu3Arcdxrg==
+
 "@types/long@^4.0.0":
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9"
@@ -7879,21 +7884,11 @@ bluebird@^3.1.1, bluebird@^3.3.5, bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.
   resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
   integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
 
-bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.11.8, bn.js@^4.4.0:
-  version "4.11.9"
-  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828"
-  integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==
-
-bn.js@^5.1.1, bn.js@^5.1.2:
+bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.11.8, bn.js@^4.4.0, bn.js@^5.1.1, bn.js@^5.1.2, bn.js@^5.1.3:
   version "5.1.2"
   resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.2.tgz#c9686902d3c9a27729f43ab10f9d79c2004da7b0"
   integrity sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==
 
-bn.js@^5.1.3:
-  version "5.1.3"
-  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b"
-  integrity sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==
-
 body-parser@1.19.0, body-parser@^1.18.3, body-parser@^1.19.0:
   version "1.19.0"
   resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
@@ -11341,7 +11336,7 @@ dotenv@^6.2.0:
   resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.2.0.tgz#941c0410535d942c8becf28d3f357dbd9d476064"
   integrity sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==
 
-dotenvi@^0.9.0:
+dotenvi@^0.9.0, dotenvi@^0.9.1:
   version "0.9.1"
   resolved "https://registry.yarnpkg.com/dotenvi/-/dotenvi-0.9.1.tgz#e280012ee9d201a0c57cb1f6e43559603b6f0fb4"
   integrity sha512-gM9HKu6P8BS+jBQRcJRdWKkbIA35Ztszr2FEqp1oKYLMfdTWDumLNi9xlIeEAFc2C4DeOwsYcNi+mMl5OWGtcw==
@@ -16146,10 +16141,10 @@ is-color-stop@^1.0.0:
     rgb-regex "^1.0.1"
     rgba-regex "^1.0.0"
 
-is-core-module@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.0.0.tgz#58531b70aed1db7c0e8d4eb1a0a2d1ddd64bd12d"
-  integrity sha512-jq1AH6C8MuteOoBPwkxHafmByhL9j5q4OaPGdbuD+ZtQJVzH+i6E3BJDQcBA09k57i2Hh2yQbEG8yObZ0jdlWw==
+is-core-module@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.1.0.tgz#a4cc031d9b1aca63eecbd18a650e13cb4eeab946"
+  integrity sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==
   dependencies:
     has "^1.0.3"
 
@@ -22401,6 +22396,11 @@ pg-protocol@^1.3.0:
   resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.3.0.tgz#3c8fb7ca34dbbfcc42776ce34ac5f537d6e34770"
   integrity sha512-64/bYByMrhWULUaCd+6/72c9PMWhiVFs3EVxl9Ct6a3v/U8+rKgqP2w+kKg/BIGgMJyB+Bk/eNivT32Al+Jghw==
 
+pg-protocol@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.4.0.tgz#43a71a92f6fe3ac559952555aa3335c8cb4908be"
+  integrity sha512-El+aXWcwG/8wuFICMQjM5ZSAm6OWiJicFdNYo+VY3QP+8vI4SvLIWVe51PppTzMhikUJR+PsyIFKqfdXPz/yxA==
+
 pg-types@1.*:
   version "1.13.0"
   resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-1.13.0.tgz#75f490b8a8abf75f1386ef5ec4455ecf6b345c63"
@@ -22451,7 +22451,20 @@ pg@^7.12.1:
     pgpass "1.x"
     semver "4.3.2"
 
-pg@^8.0.3, pg@^8.3.3:
+pg@^8.0.3:
+  version "8.5.0"
+  resolved "https://registry.yarnpkg.com/pg/-/pg-8.5.0.tgz#c29332763ffd51ce52b07dc20dc2337f4d213d08"
+  integrity sha512-h+KHEwce67pAQilZhMCpCx1RC7rR1US7mdjwvKzHRaRxKQxbbFtv5UlwjzqILQ1dwhK+RVGqOVcahE/2KOcaeA==
+  dependencies:
+    buffer-writer "2.0.0"
+    packet-reader "1.0.0"
+    pg-connection-string "^2.4.0"
+    pg-pool "^3.2.2"
+    pg-protocol "^1.4.0"
+    pg-types "^2.1.0"
+    pgpass "1.x"
+
+pg@^8.3.3:
   version "8.4.2"
   resolved "https://registry.yarnpkg.com/pg/-/pg-8.4.2.tgz#2aa58166a23391e91d56a7ea57c6d99931c0642a"
   integrity sha512-E9FlUrrc7w3+sbRmL1CSw99vifACzB2TjhMM9J5w9D1LIg+6un0jKkpHS1EQf2CWhKhec2bhrBLVMmUBDbjPRQ==
@@ -25101,11 +25114,11 @@ resolve@1.1.7:
   integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=
 
 resolve@1.x, resolve@^1.0.0:
-  version "1.18.1"
-  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.18.1.tgz#018fcb2c5b207d2a6424aee361c5a266da8f4130"
-  integrity sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==
+  version "1.19.0"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c"
+  integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==
   dependencies:
-    is-core-module "^2.0.0"
+    is-core-module "^2.1.0"
     path-parse "^1.0.6"
 
 resolve@^1.1.6, resolve@^1.1.7, resolve@^1.11.0, resolve@^1.11.1, resolve@^1.17.0, resolve@^1.2.0:
@@ -28163,12 +28176,7 @@ typescript-formatter@^7.2.2:
     commandpost "^1.0.0"
     editorconfig "^0.15.0"
 
-typescript@3.5.2:
-  version "3.5.2"
-  resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.2.tgz#a09e1dc69bc9551cadf17dba10ee42cf55e5d56c"
-  integrity sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA==
-
-typescript@^3.0.3, typescript@^3.7.2, typescript@^3.7.5, typescript@^3.8.3, typescript@^3.9.5, typescript@^3.9.6, typescript@^3.9.7:
+typescript@3.5.2, typescript@^3.0.3, typescript@^3.7.2, typescript@^3.7.5, typescript@^3.8.3, typescript@^3.9.5, typescript@^3.9.6, typescript@^3.9.7:
   version "3.9.7"
   resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
   integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==

Неке датотеке нису приказане због велике количине промена