diff --git a/polkadot/Cargo.lock b/polkadot/Cargo.lock index 00cc1044b6..eca3d455bb 100644 --- a/polkadot/Cargo.lock +++ b/polkadot/Cargo.lock @@ -3851,6 +3851,28 @@ dependencies = [ "wasm-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "polkadot-network-test" +version = "0.8.0" +dependencies = [ + "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "polkadot-test-runtime-client 2.0.0", + "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "sc-block-builder 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sc-client 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sc-client-api 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sc-network 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sc-network-test 0.8.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-blockchain 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-consensus 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-core 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-runtime 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", +] + [[package]] name = "polkadot-parachain" version = "0.7.22" @@ -4079,6 +4101,78 @@ dependencies = [ "sp-core 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", ] +[[package]] +name = "polkadot-test-runtime" +version = "0.7.21" +dependencies = [ + "bitvec 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", + "frame-executive 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "frame-support 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "frame-system 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "frame-system-rpc-runtime-api 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libsecp256k1 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "pallet-authorship 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "pallet-babe 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "pallet-balances 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "pallet-finality-tracker 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "pallet-grandpa 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "pallet-indices 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "pallet-nicks 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "pallet-randomness-collective-flip 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "pallet-session 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "pallet-staking 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "pallet-staking-reward-curve 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "pallet-timestamp 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "pallet-transaction-payment 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "pallet-transaction-payment-rpc-runtime-api 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "pallet-vesting 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "parity-scale-codec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "polkadot-parachain 0.7.22", + "polkadot-primitives 0.7.22", + "polkadot-runtime-common 0.7.22", + "rustc-hex 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-api 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-block-builder 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-consensus-babe 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-core 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-inherents 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-io 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-keyring 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-runtime 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-session 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-staking 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-std 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-transaction-pool 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-trie 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-version 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "substrate-wasm-builder-runner 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-db 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "polkadot-test-runtime-client" +version = "2.0.0" +dependencies = [ + "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "polkadot-test-runtime 0.7.21", + "sc-block-builder 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sc-client 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sc-client-api 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-api 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-blockchain 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-core 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-runtime 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "substrate-test-client 2.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "substrate-test-runtime 2.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-master)", +] + [[package]] name = "polkadot-validation" version = "0.7.22" @@ -5229,6 +5323,32 @@ dependencies = [ "wasm-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "sc-network-test" +version = "0.8.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-master#8c672e107789ed10973d937ba8cac245404377e2" +dependencies = [ + "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-timer 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "sc-block-builder 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sc-client 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sc-client-api 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sc-network 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-blockchain 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-consensus 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-consensus-babe 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-core 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-runtime 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "substrate-test-runtime 2.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "substrate-test-runtime-client 2.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "sc-offchain" version = "2.0.0-alpha.3" @@ -5940,6 +6060,20 @@ dependencies = [ "sp-version 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", ] +[[package]] +name = "sp-consensus-aura" +version = "0.8.0-alpha.3" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-master#8c672e107789ed10973d937ba8cac245404377e2" +dependencies = [ + "parity-scale-codec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-api 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-application-crypto 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-inherents 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-runtime 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-std 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-timestamp 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", +] + [[package]] name = "sp-consensus-babe" version = "0.8.0-alpha.3" @@ -6451,6 +6585,88 @@ dependencies = [ "tokio 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "substrate-test-client" +version = "2.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-master#8c672e107789ed10973d937ba8cac245404377e2" +dependencies = [ + "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sc-client 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sc-client-api 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sc-client-db 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sc-executor 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-blockchain 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-consensus 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-core 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-keyring 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-runtime 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-state-machine 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", +] + +[[package]] +name = "substrate-test-runtime" +version = "2.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-master#8c672e107789ed10973d937ba8cac245404377e2" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "frame-executive 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "frame-support 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "frame-system 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "frame-system-rpc-runtime-api 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "memory-db 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pallet-babe 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "pallet-timestamp 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "parity-scale-codec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-util-mem 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sc-client 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-api 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-application-crypto 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-block-builder 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-consensus-aura 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-consensus-babe 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-core 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-inherents 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-io 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-keyring 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-offchain 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-runtime 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-runtime-interface 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-session 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-std 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-transaction-pool 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-trie 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-version 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "substrate-wasm-builder-runner 1.0.5 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "trie-db 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "substrate-test-runtime-client" +version = "2.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-master#8c672e107789ed10973d937ba8cac245404377e2" +dependencies = [ + "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sc-block-builder 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sc-client 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sc-client-api 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-api 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-blockchain 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-core 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "sp-runtime 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "substrate-test-client 2.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "substrate-test-runtime 2.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-master)", +] + +[[package]] +name = "substrate-wasm-builder-runner" +version = "1.0.5" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-master#8c672e107789ed10973d937ba8cac245404377e2" + [[package]] name = "substrate-wasm-builder-runner" version = "1.0.5" @@ -8027,6 +8243,7 @@ dependencies = [ "checksum sc-keystore 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" "checksum sc-network 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" "checksum sc-network-gossip 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" +"checksum sc-network-test 0.8.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" "checksum sc-offchain 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" "checksum sc-peerset 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" "checksum sc-rpc 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" @@ -8084,6 +8301,7 @@ dependencies = [ "checksum sp-block-builder 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" "checksum sp-blockchain 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" "checksum sp-consensus 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" +"checksum sp-consensus-aura 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" "checksum sp-consensus-babe 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" "checksum sp-core 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" "checksum sp-debug-derive 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" @@ -8126,6 +8344,10 @@ dependencies = [ "checksum substrate-browser-utils 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" "checksum substrate-frame-rpc-system 2.0.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" "checksum substrate-prometheus-endpoint 0.8.0-alpha.3 (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" +"checksum substrate-test-client 2.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" +"checksum substrate-test-runtime 2.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" +"checksum substrate-test-runtime-client 2.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" +"checksum substrate-wasm-builder-runner 1.0.5 (git+https://github.com/paritytech/substrate?branch=polkadot-master)" = "" "checksum substrate-wasm-builder-runner 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e30c70de7e7d5fd404fe26db1e7a4d6b553e2760b1ac490f249c04a960c483b8" "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" "checksum subtle 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c65d530b10ccaeac294f349038a597e435b18fb456aadd0840a623f83b9e941" diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index f221b6fdb6..f8b0ac2cb8 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -29,10 +29,13 @@ members = [ "collator", "erasure-coding", "network", + "network/test", "primitives", "runtime/common", "runtime/polkadot", "runtime/kusama", + "runtime/test-runtime", + "runtime/test-runtime/client", "service", "statement-table", "service", diff --git a/polkadot/network/test/Cargo.toml b/polkadot/network/test/Cargo.toml new file mode 100644 index 0000000000..9e5e779eb7 --- /dev/null +++ b/polkadot/network/test/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "polkadot-network-test" +version = "0.8.0" +license = "GPL-3.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +log = "0.4.8" +parking_lot = "0.10.0" +futures = "0.3.1" +rand = "0.7.2" +libp2p = { version = "0.16.2", default-features = false, features = ["libp2p-websocket"] } +sc-network = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +sc-network-test = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +sc-client = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +sc-block-builder = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +env_logger = "0.7.0" +polkadot-test-runtime-client = { path = "../../runtime/test-runtime/client" } diff --git a/polkadot/network/test/src/block_import.rs b/polkadot/network/test/src/block_import.rs new file mode 100644 index 0000000000..7bc8b655f0 --- /dev/null +++ b/polkadot/network/test/src/block_import.rs @@ -0,0 +1,89 @@ +// Copyright 2020 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Testing block import logic. + +use sp_consensus::ImportedAux; +use sp_consensus::import_queue::{ + import_single_block, BasicQueue, BlockImportError, BlockImportResult, IncomingBlock, +}; +use polkadot_test_runtime_client::{self, prelude::*}; +use polkadot_test_runtime_client::runtime::{Block, Hash}; +use sp_runtime::generic::BlockId; +use super::*; + +fn prepare_good_block() -> (TestClient, Hash, u64, PeerId, IncomingBlock) { + let mut client = polkadot_test_runtime_client::new(); + let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + client.import(BlockOrigin::File, block).unwrap(); + + let (hash, number) = (client.block_hash(1).unwrap().unwrap(), 1); + let header = client.header(&BlockId::Number(1)).unwrap(); + let justification = client.justification(&BlockId::Number(1)).unwrap(); + let peer_id = PeerId::random(); + (client, hash, number, peer_id.clone(), IncomingBlock { + hash, + header, + body: Some(Vec::new()), + justification, + origin: Some(peer_id.clone()), + allow_missing_state: false, + import_existing: false, + }) +} + +#[test] +fn import_single_good_block_works() { + let (_, _hash, number, peer_id, block) = prepare_good_block(); + + let mut expected_aux = ImportedAux::default(); + expected_aux.is_new_best = true; + + match import_single_block(&mut polkadot_test_runtime_client::new(), BlockOrigin::File, block, &mut PassThroughVerifier(true)) { + Ok(BlockImportResult::ImportedUnknown(ref num, ref aux, ref org)) + if *num == number as u32 && *aux == expected_aux && *org == Some(peer_id) => {} + r @ _ => panic!("{:?}", r) + } +} + +#[test] +fn import_single_good_known_block_is_ignored() { + let (mut client, _hash, number, _, block) = prepare_good_block(); + match import_single_block(&mut client, BlockOrigin::File, block, &mut PassThroughVerifier(true)) { + Ok(BlockImportResult::ImportedKnown(ref n)) if *n == number as u32 => {} + _ => panic!() + } +} + +#[test] +fn import_single_good_block_without_header_fails() { + let (_, _, _, peer_id, mut block) = prepare_good_block(); + block.header = None; + match import_single_block(&mut polkadot_test_runtime_client::new(), BlockOrigin::File, block, &mut PassThroughVerifier(true)) { + Err(BlockImportError::IncompleteHeader(ref org)) if *org == Some(peer_id) => {} + _ => panic!() + } +} + +#[test] +fn async_import_queue_drops() { + // Perform this test multiple times since it exhibits non-deterministic behavior. + for _ in 0..100 { + let verifier = PassThroughVerifier(true); + let queue = BasicQueue::new(verifier, Box::new(polkadot_test_runtime_client::new()), None, None); + drop(queue); + } +} diff --git a/polkadot/network/test/src/lib.rs b/polkadot/network/test/src/lib.rs new file mode 100644 index 0000000000..cf557c5483 --- /dev/null +++ b/polkadot/network/test/src/lib.rs @@ -0,0 +1,875 @@ +// Copyright 2020 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +#![allow(missing_docs)] + +#[cfg(test)] +mod block_import; + +use std::{collections::HashMap, pin::Pin, sync::Arc, marker::PhantomData, task::{Poll, Context as FutureContext}}; + +use libp2p::build_multiaddr; +use log::trace; +use sc_network::config::FinalityProofProvider; +use sp_blockchain::{ + Result as ClientResult, well_known_cache_keys::{self, Id as CacheKeyId}, Info as BlockchainInfo, +}; +use sc_client_api::{ + BlockchainEvents, BlockImportNotification, + FinalityNotifications, ImportNotifications, + FinalityNotification, + backend::{TransactionFor, AuxStore, Backend, Finalizer}, +}; +use sc_block_builder::{BlockBuilder, BlockBuilderProvider}; +use sc_client::LongestChain; +use sc_network::config::Roles; +use sp_consensus::block_validation::DefaultBlockAnnounceValidator; +use sp_consensus::import_queue::{ + BasicQueue, BoxJustificationImport, Verifier, BoxFinalityProofImport, +}; +use sp_consensus::block_import::{BlockImport, ImportResult}; +use sp_consensus::Error as ConsensusError; +use sp_consensus::{BlockOrigin, BlockImportParams, BlockCheckParams, JustificationImport}; +use futures::prelude::*; +use sc_network::{NetworkWorker, NetworkStateInfo, NetworkService, ReportHandle, config::ProtocolId}; +use sc_network::config::{NetworkConfiguration, TransportConfig, BoxFinalityProofRequestBuilder}; +use libp2p::PeerId; +use parking_lot::Mutex; +use sp_core::H256; +use sc_network::config::{ProtocolConfig, TransactionPool}; +use sp_runtime::generic::BlockId; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; +use sp_runtime::Justification; +pub use sc_network_test::PassThroughVerifier; + +pub use polkadot_test_runtime_client::runtime::{Block, Extrinsic, Hash}; +pub use polkadot_test_runtime_client::{TestClient, TestClientBuilder, TestClientBuilderExt}; + +pub type PeersFullClient = + sc_client::Client; +pub type PeersLightClient = + sc_client::Client; + +#[derive(Clone)] +pub enum PeersClient { + Full(Arc, Arc), + Light(Arc, Arc), +} + +impl PeersClient { + pub fn as_full(&self) -> Option> { + match *self { + PeersClient::Full(ref client, ref _backend) => Some(client.clone()), + _ => None, + } + } + + pub fn as_block_import(&self) -> BlockImportAdapter { + match *self { + PeersClient::Full(ref client, ref _backend) => + BlockImportAdapter::new_full(client.clone()), + PeersClient::Light(ref client, ref _backend) => + BlockImportAdapter::Light(Arc::new(Mutex::new(client.clone())), PhantomData), + } + } + + pub fn get_aux(&self, key: &[u8]) -> ClientResult>> { + match *self { + PeersClient::Full(ref client, ref _backend) => client.get_aux(key), + PeersClient::Light(ref client, ref _backend) => client.get_aux(key), + } + } + + pub fn info(&self) -> BlockchainInfo { + match *self { + PeersClient::Full(ref client, ref _backend) => client.chain_info(), + PeersClient::Light(ref client, ref _backend) => client.chain_info(), + } + } + + pub fn header(&self, block: &BlockId) -> ClientResult::Header>> { + match *self { + PeersClient::Full(ref client, ref _backend) => client.header(block), + PeersClient::Light(ref client, ref _backend) => client.header(block), + } + } + + pub fn justification(&self, block: &BlockId) -> ClientResult> { + match *self { + PeersClient::Full(ref client, ref _backend) => client.justification(block), + PeersClient::Light(ref client, ref _backend) => client.justification(block), + } + } + + pub fn finality_notification_stream(&self) -> FinalityNotifications { + match *self { + PeersClient::Full(ref client, ref _backend) => client.finality_notification_stream(), + PeersClient::Light(ref client, ref _backend) => client.finality_notification_stream(), + } + } + + pub fn import_notification_stream(&self) -> ImportNotifications{ + match *self { + PeersClient::Full(ref client, ref _backend) => client.import_notification_stream(), + PeersClient::Light(ref client, ref _backend) => client.import_notification_stream(), + } + } + + pub fn finalize_block( + &self, + id: BlockId, + justification: Option, + notify: bool + ) -> ClientResult<()> { + match *self { + PeersClient::Full(ref client, ref _backend) => client.finalize_block(id, justification, notify), + PeersClient::Light(ref client, ref _backend) => client.finalize_block(id, justification, notify), + } + } +} + +pub struct Peer { + pub data: D, + client: PeersClient, + /// We keep a copy of the verifier so that we can invoke it for locally-generated blocks, + /// instead of going through the import queue. + verifier: VerifierAdapter, + /// We keep a copy of the block_import so that we can invoke it for locally-generated blocks, + /// instead of going through the import queue. + block_import: BlockImportAdapter<()>, + select_chain: Option>, + backend: Option>, + network: NetworkWorker::Hash>, + imported_blocks_stream: Pin> + Send>>, + finality_notification_stream: Pin> + Send>>, +} + +impl Peer { + /// Get this peer ID. + pub fn id(&self) -> PeerId { + self.network.service().local_peer_id() + } + + /// Returns true if we're major syncing. + pub fn is_major_syncing(&self) -> bool { + self.network.service().is_major_syncing() + } + + // Returns a clone of the local SelectChain, only available on full nodes + pub fn select_chain(&self) -> Option> { + self.select_chain.clone() + } + + /// Returns the number of peers we're connected to. + pub fn num_peers(&self) -> usize { + self.network.num_connected_peers() + } + + /// Returns true if we have no peer. + pub fn is_offline(&self) -> bool { + self.num_peers() == 0 + } + + /// Request a justification for the given block. + pub fn request_justification(&self, hash: &::Hash, number: NumberFor) { + self.network.service().request_justification(hash, number); + } + + /// Announces an important block on the network. + pub fn announce_block(&self, hash: ::Hash, data: Vec) { + self.network.service().announce_block(hash, data); + } + + /// Request explicit fork sync. + pub fn set_sync_fork_request(&self, peers: Vec, hash: ::Hash, number: NumberFor) { + self.network.service().set_sync_fork_request(peers, hash, number); + } + + /// Add blocks to the peer -- edit the block before adding + pub fn generate_blocks(&mut self, count: usize, origin: BlockOrigin, edit_block: F) -> H256 + where F: FnMut(BlockBuilder) -> Block + { + let best_hash = self.client.info().best_hash; + self.generate_blocks_at(BlockId::Hash(best_hash), count, origin, edit_block, false) + } + + /// Add blocks to the peer -- edit the block before adding. The chain will + /// start at the given block iD. + fn generate_blocks_at( + &mut self, + at: BlockId, + count: usize, + origin: BlockOrigin, + mut edit_block: F, + headers_only: bool, + ) -> H256 where F: FnMut(BlockBuilder) -> Block { + let full_client = self.client.as_full() + .expect("blocks could only be generated by full clients"); + let mut at = full_client.header(&at).unwrap().unwrap().hash(); + for _ in 0..count { + let builder = full_client.new_block_at( + &BlockId::Hash(at), + Default::default(), + false, + ).unwrap(); + let block = edit_block(builder); + let hash = block.header.hash(); + trace!( + target: "test_network", + "Generating {}, (#{}, parent={})", + hash, + block.header.number, + block.header.parent_hash, + ); + let header = block.header.clone(); + let (import_block, cache) = self.verifier.verify( + origin, + header.clone(), + None, + if headers_only { None } else { Some(block.extrinsics) }, + ).unwrap(); + let cache = if let Some(cache) = cache { + cache.into_iter().collect() + } else { + Default::default() + }; + self.block_import.import_block(import_block, cache).expect("block_import failed"); + self.network.on_block_imported(header, Vec::new(), true); + at = hash; + } + + self.network.service().announce_block(at.clone(), Vec::new()); + at + } + + /// Push blocks to the peer (simplified: with or without a TX) + pub fn push_blocks(&mut self, count: usize, with_tx: bool) -> H256 { + let best_hash = self.client.info().best_hash; + self.push_blocks_at(BlockId::Hash(best_hash), count, with_tx) + } + + /// Push blocks to the peer (simplified: with or without a TX) + pub fn push_headers(&mut self, count: usize) -> H256 { + let best_hash = self.client.info().best_hash; + self.generate_tx_blocks_at(BlockId::Hash(best_hash), count, false, true) + } + + /// Push blocks to the peer (simplified: with or without a TX) starting from + /// given hash. + pub fn push_blocks_at(&mut self, at: BlockId, count: usize, with_tx: bool) -> H256 { + self.generate_tx_blocks_at(at, count, with_tx, false) + } + + /// Push blocks/headers to the peer (simplified: with or without a TX) starting from + /// given hash. + fn generate_tx_blocks_at(&mut self, at: BlockId, count: usize, with_tx: bool, headers_only:bool) -> H256 { + if with_tx { + self.generate_blocks_at( + at, + count, + BlockOrigin::File, + |builder| builder.build().unwrap().block, + headers_only + ) + } else { + self.generate_blocks_at( + at, + count, + BlockOrigin::File, + |builder| builder.build().unwrap().block, + headers_only, + ) + } + } + + /// Get a reference to the client. + pub fn client(&self) -> &PeersClient { + &self.client + } + + /// Get a reference to the network service. + pub fn network_service(&self) -> &Arc::Hash>> { + &self.network.service() + } + + /// Test helper to compare the blockchain state of multiple (networked) + /// clients. + /// Potentially costly, as it creates in-memory copies of both blockchains in order + /// to compare them. If you have easier/softer checks that are sufficient, e.g. + /// by using .info(), you should probably use it instead of this. + pub fn blockchain_canon_equals(&self, other: &Self) -> bool { + if let (Some(mine), Some(others)) = (self.backend.clone(), other.backend.clone()) { + mine.as_in_memory().blockchain() + .canon_equals_to(others.as_in_memory().blockchain()) + } else { + false + } + } + + /// Count the total number of imported blocks. + pub fn blocks_count(&self) -> u64 { + self.backend.as_ref().map( + |backend| backend.blocks_count() + ).unwrap_or(0) + } + + /// Return a collection of block hashes that failed verification + pub fn failed_verifications(&self) -> HashMap<::Hash, String> { + self.verifier.failed_verifications.lock().clone() + } +} + +pub struct EmptyTransactionPool; + +impl TransactionPool for EmptyTransactionPool { + fn transactions(&self) -> Vec<(Hash, Extrinsic)> { + Vec::new() + } + + fn hash_of(&self, _transaction: &Extrinsic) -> Hash { + Hash::default() + } + + fn import( + &self, + _report_handle: ReportHandle, + _who: PeerId, + _rep_change_good: sc_network::ReputationChange, + _rep_change_bad: sc_network::ReputationChange, + _transaction: Extrinsic + ) {} + + fn on_broadcasted(&self, _: HashMap>) {} + + fn transaction(&self, _h: &Hash) -> Option { None } +} + +/// Implements `BlockImport` for any `Transaction`. Internally the transaction is +/// "converted", aka the field is set to `None`. +/// +/// This is required as the `TestNetFactory` trait does not distinguish between +/// full and light nodes. +pub enum BlockImportAdapter { + Full( + Arc, + Error = ConsensusError + > + Send>>, + PhantomData, + ), + Light( + Arc, + Error = ConsensusError + > + Send>>, + PhantomData, + ), +} + +impl BlockImportAdapter { + /// Create a new instance of `Self::Full`. + pub fn new_full( + full: impl BlockImport< + Block, + Transaction = TransactionFor, + Error = ConsensusError + > + + 'static + + Send + ) -> Self { + Self::Full(Arc::new(Mutex::new(full)), PhantomData) + } + + /// Create a new instance of `Self::Light`. + pub fn new_light( + light: impl BlockImport< + Block, + Transaction = TransactionFor, + Error = ConsensusError + > + + 'static + + Send + ) -> Self { + Self::Light(Arc::new(Mutex::new(light)), PhantomData) + } +} + +impl Clone for BlockImportAdapter { + fn clone(&self) -> Self { + match self { + Self::Full(full, _) => Self::Full(full.clone(), PhantomData), + Self::Light(light, _) => Self::Light(light.clone(), PhantomData), + } + } +} + +impl BlockImport for BlockImportAdapter { + type Error = ConsensusError; + type Transaction = Transaction; + + fn check_block( + &mut self, + block: BlockCheckParams, + ) -> Result { + match self { + Self::Full(full, _) => full.lock().check_block(block), + Self::Light(light, _) => light.lock().check_block(block), + } + } + + fn import_block( + &mut self, + block: BlockImportParams, + cache: HashMap>, + ) -> Result { + match self { + Self::Full(full, _) => full.lock().import_block(block.convert_transaction(), cache), + Self::Light(light, _) => light.lock().import_block(block.convert_transaction(), cache), + } + } +} + +/// Implements `Verifier` on an `Arc>`. Used internally. +#[derive(Clone)] +struct VerifierAdapter { + verifier: Arc>>>, + failed_verifications: Arc>>, +} + +impl Verifier for VerifierAdapter { + fn verify( + &mut self, + origin: BlockOrigin, + header: B::Header, + justification: Option, + body: Option> + ) -> Result<(BlockImportParams, Option)>>), String> { + let hash = header.hash(); + self.verifier.lock().verify(origin, header, justification, body).map_err(|e| { + self.failed_verifications.lock().insert(hash, e.clone()); + e + }) + } +} + +impl VerifierAdapter { + fn new(verifier: Arc>>>) -> VerifierAdapter { + VerifierAdapter { + verifier, + failed_verifications: Default::default(), + } + } +} + +pub trait TestNetFactory: Sized { + type Verifier: 'static + Verifier; + type PeerData: Default; + + /// These two need to be implemented! + fn from_config(config: &ProtocolConfig) -> Self; + fn make_verifier( + &self, + client: PeersClient, + config: &ProtocolConfig, + peer_data: &Self::PeerData, + ) -> Self::Verifier; + + /// Get reference to peer. + fn peer(&mut self, i: usize) -> &mut Peer; + fn peers(&self) -> &Vec>; + fn mut_peers>)>( + &mut self, + closure: F, + ); + + /// Get custom block import handle for fresh client, along with peer data. + fn make_block_import(&self, client: PeersClient) + -> ( + BlockImportAdapter, + Option>, + Option>, + Option>, + Self::PeerData, + ) + { + (client.as_block_import(), None, None, None, Default::default()) + } + + /// Get finality proof provider (if supported). + fn make_finality_proof_provider( + &self, + _client: PeersClient, + ) -> Option>> { + None + } + + fn default_config() -> ProtocolConfig { + ProtocolConfig::default() + } + + /// Create new test network with this many peers. + fn new(n: usize) -> Self { + trace!(target: "test_network", "Creating test network"); + let config = Self::default_config(); + let mut net = Self::from_config(&config); + + for i in 0..n { + trace!(target: "test_network", "Adding peer {}", i); + net.add_full_peer(&config); + } + net + } + + fn add_full_peer(&mut self, config: &ProtocolConfig) { + self.add_full_peer_with_states(config, None) + } + + /// Add a full peer. + fn add_full_peer_with_states(&mut self, config: &ProtocolConfig, keep_blocks: Option) { + let test_client_builder = match keep_blocks { + Some(keep_blocks) => TestClientBuilder::with_pruning_window(keep_blocks), + None => TestClientBuilder::with_default_backend(), + }; + let backend = test_client_builder.backend(); + let (c, longest_chain) = test_client_builder.build_with_longest_chain(); + let client = Arc::new(c); + + let ( + block_import, + justification_import, + finality_proof_import, + finality_proof_request_builder, + data, + ) = self.make_block_import(PeersClient::Full(client.clone(), backend.clone())); + + let verifier = self.make_verifier( + PeersClient::Full(client.clone(), backend.clone()), + config, + &data, + ); + let verifier = VerifierAdapter::new(Arc::new(Mutex::new(Box::new(verifier) as Box<_>))); + + let import_queue = Box::new(BasicQueue::new( + verifier.clone(), + Box::new(block_import.clone()), + justification_import, + finality_proof_import, + )); + + let listen_addr = build_multiaddr![Memory(rand::random::())]; + + let network = NetworkWorker::new(sc_network::config::Params { + roles: config.roles, + executor: None, + network_config: NetworkConfiguration { + listen_addresses: vec![listen_addr.clone()], + transport: TransportConfig::MemoryOnly, + ..NetworkConfiguration::default() + }, + chain: client.clone(), + finality_proof_provider: self.make_finality_proof_provider( + PeersClient::Full(client.clone(), backend.clone()), + ), + finality_proof_request_builder, + on_demand: None, + transaction_pool: Arc::new(EmptyTransactionPool), + protocol_id: ProtocolId::from(&b"test-protocol-name"[..]), + import_queue, + block_announce_validator: Box::new(DefaultBlockAnnounceValidator::new(client.clone())), + metrics_registry: None, + }).unwrap(); + + self.mut_peers(|peers| { + for peer in peers.iter_mut() { + peer.network.add_known_address(network.service().local_peer_id(), listen_addr.clone()); + } + + let imported_blocks_stream = Box::pin(client.import_notification_stream().fuse()); + let finality_notification_stream = Box::pin(client.finality_notification_stream().fuse()); + + peers.push(Peer { + data, + client: PeersClient::Full(client, backend.clone()), + select_chain: Some(longest_chain), + backend: Some(backend), + imported_blocks_stream, + finality_notification_stream, + block_import, + verifier, + network, + }); + }); + } + + /// Add a light peer. + fn add_light_peer(&mut self, config: &ProtocolConfig) { + let mut config = config.clone(); + config.roles = Roles::LIGHT; + + let (c, backend) = polkadot_test_runtime_client::new_light(); + let client = Arc::new(c); + let ( + block_import, + justification_import, + finality_proof_import, + finality_proof_request_builder, + data, + ) = self.make_block_import(PeersClient::Light(client.clone(), backend.clone())); + + let verifier = self.make_verifier( + PeersClient::Light(client.clone(), backend.clone()), + &config, + &data, + ); + let verifier = VerifierAdapter::new(Arc::new(Mutex::new(Box::new(verifier) as Box<_>))); + + let import_queue = Box::new(BasicQueue::new( + verifier.clone(), + Box::new(block_import.clone()), + justification_import, + finality_proof_import, + )); + + let listen_addr = build_multiaddr![Memory(rand::random::())]; + + let network = NetworkWorker::new(sc_network::config::Params { + roles: config.roles, + executor: None, + network_config: NetworkConfiguration { + listen_addresses: vec![listen_addr.clone()], + transport: TransportConfig::MemoryOnly, + ..NetworkConfiguration::default() + }, + chain: client.clone(), + finality_proof_provider: self.make_finality_proof_provider( + PeersClient::Light(client.clone(), backend.clone()) + ), + finality_proof_request_builder, + on_demand: None, + transaction_pool: Arc::new(EmptyTransactionPool), + protocol_id: ProtocolId::from(&b"test-protocol-name"[..]), + import_queue, + block_announce_validator: Box::new(DefaultBlockAnnounceValidator::new(client.clone())), + metrics_registry: None, + }).unwrap(); + + self.mut_peers(|peers| { + for peer in peers.iter_mut() { + peer.network.add_known_address(network.service().local_peer_id(), listen_addr.clone()); + } + + let imported_blocks_stream = Box::pin(client.import_notification_stream().fuse()); + let finality_notification_stream = Box::pin(client.finality_notification_stream().fuse()); + + peers.push(Peer { + data, + verifier, + select_chain: None, + backend: None, + block_import, + client: PeersClient::Light(client, backend), + imported_blocks_stream, + finality_notification_stream, + network, + }); + }); + } + + /// Polls the testnet until all nodes are in sync. + /// + /// Must be executed in a task context. + fn poll_until_sync(&mut self, cx: &mut FutureContext) -> Poll<()> { + self.poll(cx); + + // Return `NotReady` if there's a mismatch in the highest block number. + let mut highest = None; + for peer in self.peers().iter() { + if peer.is_major_syncing() || peer.network.num_queued_blocks() != 0 { + return Poll::Pending + } + if peer.network.num_sync_requests() != 0 { + return Poll::Pending + } + match (highest, peer.client.info().best_hash) { + (None, b) => highest = Some(b), + (Some(ref a), ref b) if a == b => {}, + (Some(_), _) => return Poll::Pending + } + } + Poll::Ready(()) + } + + /// Polls the testnet until theres' no activiy of any kind. + /// + /// Must be executed in a task context. + fn poll_until_idle(&mut self, cx: &mut FutureContext) -> Poll<()> { + self.poll(cx); + + for peer in self.peers().iter() { + if peer.is_major_syncing() || peer.network.num_queued_blocks() != 0 { + return Poll::Pending + } + if peer.network.num_sync_requests() != 0 { + return Poll::Pending + } + } + Poll::Ready(()) + } + + /// Blocks the current thread until we are sync'ed. + /// + /// Calls `poll_until_sync` repeatedly. + fn block_until_sync(&mut self) { + futures::executor::block_on(futures::future::poll_fn::<(), _>(|cx| self.poll_until_sync(cx))); + } + + /// Blocks the current thread until there are no pending packets. + /// + /// Calls `poll_until_idle` repeatedly with the runtime passed as parameter. + fn block_until_idle(&mut self) { + futures::executor::block_on(futures::future::poll_fn::<(), _>(|cx| self.poll_until_idle(cx))); + } + + /// Polls the testnet. Processes all the pending actions and returns `NotReady`. + fn poll(&mut self, cx: &mut FutureContext) { + self.mut_peers(|peers| { + for peer in peers { + trace!(target: "sync", "-- Polling {}", peer.id()); + if let Poll::Ready(res) = Pin::new(&mut peer.network).poll(cx) { + res.unwrap(); + } + trace!(target: "sync", "-- Polling complete {}", peer.id()); + + // We poll `imported_blocks_stream`. + while let Poll::Ready(Some(notification)) = peer.imported_blocks_stream.as_mut().poll_next(cx) { + peer.network.on_block_imported( + notification.header, + Vec::new(), + true, + ); + } + + // We poll `finality_notification_stream`, but we only take the last event. + let mut last = None; + while let Poll::Ready(Some(item)) = peer.finality_notification_stream.as_mut().poll_next(cx) { + last = Some(item); + } + if let Some(notification) = last { + peer.network.on_block_finalized(notification.hash, notification.header); + } + } + }); + } +} + +pub struct TestNet { + peers: Vec>, +} + +impl TestNetFactory for TestNet { + type Verifier = PassThroughVerifier; + type PeerData = (); + + /// Create new test network with peers and given config. + fn from_config(_config: &ProtocolConfig) -> Self { + TestNet { + peers: Vec::new(), + } + } + + fn make_verifier(&self, _client: PeersClient, _config: &ProtocolConfig, _peer_data: &()) + -> Self::Verifier + { + PassThroughVerifier(false) + } + + fn peer(&mut self, i: usize) -> &mut Peer<()> { + &mut self.peers[i] + } + + fn peers(&self) -> &Vec> { + &self.peers + } + + fn mut_peers>)>(&mut self, closure: F) { + closure(&mut self.peers); + } +} + +pub struct ForceFinalized(PeersClient); + +impl JustificationImport for ForceFinalized { + type Error = ConsensusError; + + fn import_justification( + &mut self, + hash: H256, + _number: NumberFor, + justification: Justification, + ) -> Result<(), Self::Error> { + self.0.finalize_block(BlockId::Hash(hash), Some(justification), true) + .map_err(|_| ConsensusError::InvalidJustification.into()) + } +} + +pub struct JustificationTestNet(TestNet); + +impl TestNetFactory for JustificationTestNet { + type Verifier = PassThroughVerifier; + type PeerData = (); + + fn from_config(config: &ProtocolConfig) -> Self { + JustificationTestNet(TestNet::from_config(config)) + } + + fn make_verifier(&self, client: PeersClient, config: &ProtocolConfig, peer_data: &()) -> Self::Verifier { + self.0.make_verifier(client, config, peer_data) + } + + fn peer(&mut self, i: usize) -> &mut Peer { + self.0.peer(i) + } + + fn peers(&self) -> &Vec> { + self.0.peers() + } + + fn mut_peers>, + )>(&mut self, closure: F) { + self.0.mut_peers(closure) + } + + fn make_block_import(&self, client: PeersClient) + -> ( + BlockImportAdapter, + Option>, + Option>, + Option>, + Self::PeerData, + ) + { + ( + client.as_block_import(), + Some(Box::new(ForceFinalized(client))), + None, + None, + Default::default(), + ) + } +} diff --git a/polkadot/runtime/kusama/src/lib.rs b/polkadot/runtime/kusama/src/lib.rs index 27b4c9d010..d1ab6c1da9 100644 --- a/polkadot/runtime/kusama/src/lib.rs +++ b/polkadot/runtime/kusama/src/lib.rs @@ -77,7 +77,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_name: create_runtime_str!("parity-kusama"), authoring_version: 2, spec_version: 1050, - impl_version: 0, + impl_version: 1, apis: RUNTIME_API_VERSIONS, }; diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml new file mode 100644 index 0000000000..3431e7c1e6 --- /dev/null +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -0,0 +1,109 @@ +[package] +name = "polkadot-test-runtime" +version = "0.7.21" +authors = ["Parity Technologies "] +edition = "2018" +build = "build.rs" + +[dependencies] +bitvec = { version = "0.15.2", default-features = false, features = ["alloc"] } +codec = { package = "parity-scale-codec", version = "1.1.0", default-features = false, features = ["derive"] } +log = { version = "0.3.9", optional = true } +rustc-hex = { version = "2.0.1", default-features = false } +serde = { version = "1.0.102", default-features = false } +serde_derive = { version = "1.0.102", optional = true } + +babe-primitives = { package = "sp-consensus-babe", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +inherents = { package = "sp-inherents", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +rstd = { package = "sp-std", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +sp-staking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +sp-session = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +version = { package = "sp-version", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +tx-pool-api = { package = "sp-transaction-pool", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +block-builder-api = { package = "sp-block-builder", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } + +authorship = { package = "pallet-authorship", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +babe = { package = "pallet-babe", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +balances = { package = "pallet-balances", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +transaction-payment = { package = "pallet-transaction-payment", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +executive = { package = "frame-executive", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +finality-tracker = { package = "pallet-finality-tracker", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +grandpa = { package = "pallet-grandpa", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false, features = ["migrate-authorities"] } +indices = { package = "pallet-indices", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +nicks = { package = "pallet-nicks", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +randomness-collective-flip = { package = "pallet-randomness-collective-flip", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +session = { package = "pallet-session", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +staking = { package = "pallet-staking", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +pallet-staking-reward-curve = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +system = { package = "frame-system", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +system_rpc_runtime_api = { package = "frame-system-rpc-runtime-api", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +timestamp = { package = "pallet-timestamp", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } +vesting = { package = "pallet-vesting", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false } + +runtime-common = { package = "polkadot-runtime-common", path = "../common", default-features = false } +primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } +polkadot-parachain = { path = "../../parachain", default-features = false } + +[dev-dependencies] +hex-literal = "0.2.1" +libsecp256k1 = "0.3.2" +tiny-keccak = "1.5.0" +keyring = { package = "sp-keyring", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +sp-trie = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +trie-db = "0.20.0" +serde_json = "1.0.41" + +[build-dependencies] +wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.5" } + +[features] +default = ["std"] +no_std = [] +only-staking = [] +std = [ + "bitvec/std", + "primitives/std", + "rustc-hex/std", + "codec/std", + "inherents/std", + "sp-core/std", + "polkadot-parachain/std", + "sp-api/std", + "tx-pool-api/std", + "block-builder-api/std", + "rstd/std", + "sp-io/std", + "frame-support/std", + "authorship/std", + "balances/std", + "transaction-payment/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "executive/std", + "finality-tracker/std", + "grandpa/std", + "indices/std", + "nicks/std", + "sp-runtime/std", + "sp-staking/std", + "session/std", + "staking/std", + "system/std", + "system_rpc_runtime_api/std", + "timestamp/std", + "version/std", + "vesting/std", + "serde_derive", + "serde/std", + "log", + "babe/std", + "babe-primitives/std", + "sp-session/std", + "randomness-collective-flip/std", + "runtime-common/std", +] diff --git a/polkadot/runtime/test-runtime/build.rs b/polkadot/runtime/test-runtime/build.rs new file mode 100644 index 0000000000..4852496f7b --- /dev/null +++ b/polkadot/runtime/test-runtime/build.rs @@ -0,0 +1,26 @@ +// Copyright 2019-2020 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +use wasm_builder_runner::WasmBuilder; + +fn main() { + WasmBuilder::new() + .with_current_project() + .with_wasm_builder_from_crates("1.0.9") + .import_memory() + .export_heap_base() + .build() +} diff --git a/polkadot/runtime/test-runtime/client/Cargo.toml b/polkadot/runtime/test-runtime/client/Cargo.toml new file mode 100644 index 0000000000..a953792616 --- /dev/null +++ b/polkadot/runtime/test-runtime/client/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "polkadot-test-runtime-client" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" +license = "GPL-3.0" + +[dependencies] +sc-block-builder = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +substrate-test-client = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +polkadot-test-runtime = { path = ".." } +substrate-test-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +codec = { package = "parity-scale-codec", version = "1.0.0" } +sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +sc-client = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +futures = "0.3.1" diff --git a/polkadot/runtime/test-runtime/client/src/lib.rs b/polkadot/runtime/test-runtime/client/src/lib.rs new file mode 100644 index 0000000000..e7130f68dd --- /dev/null +++ b/polkadot/runtime/test-runtime/client/src/lib.rs @@ -0,0 +1,323 @@ +// Copyright 2020 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Client testing utilities. + +#![warn(missing_docs)] + +use std::sync::Arc; +use std::collections::BTreeMap; +pub use substrate_test_client::*; +pub use polkadot_test_runtime as runtime; +pub use sc_client::LongestChain; + +use sp_core::{sr25519, ChangesTrieConfiguration, map, twox_128}; +use sp_core::storage::{ChildInfo, Storage, StorageChild}; +use substrate_test_runtime::genesismap::{GenesisConfig}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Hash as HashT, HashFor}; +use sc_client::{ + light::fetcher::{ + RemoteCallRequest, RemoteBodyRequest, + }, +}; + +/// A prelude to import in tests. +pub mod prelude { + // Trait extensions + pub use super::{ClientExt, ClientBlockImportExt}; + // Client structs + pub use super::{ + TestClient, TestClientBuilder, Backend, LightBackend, + Executor, LightExecutor, LocalExecutor, NativeExecutor, WasmExecutionMethod, + }; + // Keyring + pub use super::{AccountKeyring, Sr25519Keyring}; +} + +sc_executor::native_executor_instance! { + pub LocalExecutor, + polkadot_test_runtime::api::dispatch, + polkadot_test_runtime::native_version, +} + +/// Test client database backend. +pub type Backend = substrate_test_client::Backend; + +/// Test client executor. +pub type Executor = sc_client::LocalCallExecutor< + Backend, + NativeExecutor, +>; + +/// Test client light database backend. +pub type LightBackend = substrate_test_client::LightBackend; + +/// Test client light executor. +pub type LightExecutor = sc_client::light::call_executor::GenesisCallExecutor< + LightBackend, + sc_client::LocalCallExecutor< + sc_client::light::backend::Backend< + sc_client_db::light::LightStorage, + HashFor + >, + NativeExecutor + > +>; + +/// Parameters of test-client builder with test-runtime. +#[derive(Default)] +pub struct GenesisParameters { + changes_trie_config: Option, + heap_pages_override: Option, + extra_storage: Storage, +} + +impl GenesisParameters { + fn genesis_config(&self) -> GenesisConfig { + GenesisConfig::new( + self.changes_trie_config.clone(), + vec![ + sr25519::Public::from(Sr25519Keyring::Alice).into(), + sr25519::Public::from(Sr25519Keyring::Bob).into(), + sr25519::Public::from(Sr25519Keyring::Charlie).into(), + ], + vec![ + AccountKeyring::Alice.into(), + AccountKeyring::Bob.into(), + AccountKeyring::Charlie.into(), + ], + 1000, + self.heap_pages_override, + self.extra_storage.clone(), + ) + } +} + +fn additional_storage_with_genesis(genesis_block: &polkadot_test_runtime::Block) -> BTreeMap, Vec> { + map![ + twox_128(&b"latest"[..]).to_vec() => genesis_block.hash().as_fixed_bytes().to_vec() + ] +} + +impl substrate_test_client::GenesisInit for GenesisParameters { + fn genesis_storage(&self) -> Storage { + use codec::Encode; + + let mut storage = self.genesis_config().genesis_map(); + + let child_roots = storage.children.iter().map(|(sk, child_content)| { + let state_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( + child_content.data.clone().into_iter().collect() + ); + (sk.clone(), state_root.encode()) + }); + let state_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( + storage.top.clone().into_iter().chain(child_roots).collect() + ); + let block: runtime::Block = sc_client::genesis::construct_genesis_block(state_root); + storage.top.extend(additional_storage_with_genesis(&block)); + + storage + } +} + +/// A `TestClient` with `test-runtime` builder. +pub type TestClientBuilder = substrate_test_client::TestClientBuilder< + polkadot_test_runtime::Block, + E, + B, + GenesisParameters, +>; + +/// Test client type with `LocalExecutor` and generic Backend. +pub type Client = sc_client::Client< + B, + sc_client::LocalCallExecutor>, + polkadot_test_runtime::Block, + polkadot_test_runtime::RuntimeApi, +>; + +/// A test client with default backend. +pub type TestClient = Client; + +/// A `TestClientBuilder` with default backend and executor. +pub trait DefaultTestClientBuilderExt: Sized { + /// Create new `TestClientBuilder` + fn new() -> Self; +} + +impl DefaultTestClientBuilderExt for TestClientBuilder { + fn new() -> Self { + Self::with_default_backend() + } +} + +/// A `test-runtime` extensions to `TestClientBuilder`. +pub trait TestClientBuilderExt: Sized { + /// Returns a mutable reference to the genesis parameters. + fn genesis_init_mut(&mut self) -> &mut GenesisParameters; + + /// Set changes trie configuration for genesis. + fn changes_trie_config(mut self, config: Option) -> Self { + self.genesis_init_mut().changes_trie_config = config; + self + } + + /// Override the default value for Wasm heap pages. + fn set_heap_pages(mut self, heap_pages: u64) -> Self { + self.genesis_init_mut().heap_pages_override = Some(heap_pages); + self + } + + /// Add an extra value into the genesis storage. + /// + /// # Panics + /// + /// Panics if the key is empty. + fn add_extra_child_storage>, K: Into>, V: Into>>( + mut self, + storage_key: SK, + child_info: ChildInfo, + key: K, + value: V, + ) -> Self { + let storage_key = storage_key.into(); + let key = key.into(); + assert!(!storage_key.is_empty()); + assert!(!key.is_empty()); + self.genesis_init_mut().extra_storage.children + .entry(storage_key) + .or_insert_with(|| StorageChild { + data: Default::default(), + child_info: child_info.to_owned(), + }).data.insert(key, value.into()); + self + } + + /// Add an extra child value into the genesis storage. + /// + /// # Panics + /// + /// Panics if the key is empty. + fn add_extra_storage>, V: Into>>(mut self, key: K, value: V) -> Self { + let key = key.into(); + assert!(!key.is_empty()); + self.genesis_init_mut().extra_storage.top.insert(key, value.into()); + self + } + + /// Build the test client. + fn build(self) -> Client { + self.build_with_longest_chain().0 + } + + /// Build the test client and longest chain selector. + fn build_with_longest_chain(self) -> (Client, sc_client::LongestChain); + + /// Build the test client and the backend. + fn build_with_backend(self) -> (Client, Arc); +} + +impl TestClientBuilderExt for TestClientBuilder< + sc_client::LocalCallExecutor>, + Backend +> { + fn genesis_init_mut(&mut self) -> &mut GenesisParameters { + Self::genesis_init_mut(self) + } + + fn build_with_longest_chain(self) -> (Client, sc_client::LongestChain) { + self.build_with_native_executor(None) + } + + fn build_with_backend(self) -> (Client, Arc) { + let backend = self.backend(); + (self.build_with_native_executor(None).0, backend) + } +} + +/// Type of optional fetch callback. +type MaybeFetcherCallback = Option Result + Send + Sync>>; + +/// Implementation of light client fetcher used in tests. +#[derive(Default)] +pub struct LightFetcher { + call: MaybeFetcherCallback, Vec>, + body: MaybeFetcherCallback, Vec>, +} + +impl LightFetcher { + /// Sets remote call callback. + pub fn with_remote_call( + self, + call: MaybeFetcherCallback, Vec>, + ) -> Self { + LightFetcher { + call, + body: self.body, + } + } + + /// Sets remote body callback. + pub fn with_remote_body( + self, + body: MaybeFetcherCallback, Vec>, + ) -> Self { + LightFetcher { + call: self.call, + body, + } + } +} + +/// Creates new client instance used for tests. +pub fn new() -> Client { + TestClientBuilder::new().build() +} + +/// Creates new light client instance used for tests. +pub fn new_light() -> ( + sc_client::Client, + Arc, +) { + + let storage = sc_client_db::light::LightStorage::new_test(); + let blockchain = Arc::new(sc_client::light::blockchain::Blockchain::new(storage)); + let backend = Arc::new(LightBackend::new(blockchain.clone())); + let executor = new_native_executor(); + let local_call_executor = sc_client::LocalCallExecutor::new(backend.clone(), executor); + let call_executor = LightExecutor::new( + backend.clone(), + local_call_executor, + ); + + ( + TestClientBuilder::with_backend(backend.clone()) + .build_with_executor(call_executor) + .0, + backend, + ) +} + +/// Creates new light client fetcher used for tests. +pub fn new_light_fetcher() -> LightFetcher { + LightFetcher::default() +} + +/// Create a new native executor. +pub fn new_native_executor() -> sc_executor::NativeExecutor { + sc_executor::NativeExecutor::new(sc_executor::WasmExecutionMethod::Interpreted, None) +} diff --git a/polkadot/runtime/test-runtime/src/constants.rs b/polkadot/runtime/test-runtime/src/constants.rs new file mode 100644 index 0000000000..17ebfcc5f3 --- /dev/null +++ b/polkadot/runtime/test-runtime/src/constants.rs @@ -0,0 +1,72 @@ +// Copyright 2019-2020 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +/// Money matters. +pub mod currency { + use primitives::Balance; + + pub const DOTS: Balance = 1_000_000_000_000; + pub const DOLLARS: Balance = DOTS; + pub const CENTS: Balance = DOLLARS / 100; + pub const MILLICENTS: Balance = CENTS / 1_000; +} + +/// Time and blocks. +pub mod time { + use primitives::{Moment, BlockNumber}; + // Testnet + pub const MILLISECS_PER_BLOCK: Moment = 1000; + pub const SLOT_DURATION: Moment = MILLISECS_PER_BLOCK; + // Testnet + pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 10 * MINUTES; + + // These time units are defined in number of blocks. + pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); + pub const HOURS: BlockNumber = MINUTES * 60; + pub const DAYS: BlockNumber = HOURS * 24; + + // 1 in 4 blocks (on average, not counting collisions) will be primary babe blocks. + pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4); +} + +/// Fee-related. +pub mod fee { + pub use sp_runtime::Perbill; + use primitives::Balance; + use frame_support::weights::Weight; + use sp_runtime::traits::Convert; + + /// The block saturation level. Fees will be updates based on this value. + pub const TARGET_BLOCK_FULLNESS: Perbill = Perbill::from_percent(25); + + /// Handles converting a weight scalar to a fee value, based on the scale and granularity of the + /// node's balance type. + /// + /// This should typically create a mapping between the following ranges: + /// - [0, system::MaximumBlockWeight] + /// - [Balance::min, Balance::max] + /// + /// Yet, it can be used for any other sort of change to weight-fee. Some examples being: + /// - Setting it to `0` will essentially disable the weight fee. + /// - Setting it to `1` will cause the literal `#[weight = x]` values to be charged. + pub struct WeightToFee; + impl Convert for WeightToFee { + fn convert(x: Weight) -> Balance { + // in Kusama a weight of 10_000 (smallest non-zero weight) is mapped to 1/10 CENT: + Balance::from(x).saturating_mul(super::currency::CENTS / (10 * 10_000)) + } + } +} diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs new file mode 100644 index 0000000000..a70e186024 --- /dev/null +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -0,0 +1,580 @@ +// Copyright 2017-2020 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! The Polkadot runtime. This can be compiled with `#[no_std]`, ready for Wasm. + +#![cfg_attr(not(feature = "std"), no_std)] +// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. +#![recursion_limit="256"] + +use rstd::prelude::*; +use codec::{Encode, Decode}; +use primitives::{ + AccountId, AccountIndex, Balance, BlockNumber, Hash as HashT, Nonce, Signature, Moment, + parachain::{self, ActiveParas, AbridgedCandidateReceipt}, ValidityError, +}; +use runtime_common::{attestations, claims, parachains, registrar, slots, + impls::{CurrencyToVoteHandler, TargetedFeeAdjustment}, + BlockHashCount, MaximumBlockWeight, AvailableBlockRatio, + MaximumBlockLength, +}; + +use sp_runtime::{ + create_runtime_str, generic, impl_opaque_keys, + ApplyExtrinsicResult, Perbill, RuntimeDebug, + transaction_validity::{TransactionValidity, InvalidTransaction, TransactionValidityError}, + curve::PiecewiseLinear, + traits::{BlakeTwo256, Block as BlockT, StaticLookup, SignedExtension, OpaqueKeys, ConvertInto}, +}; +use version::RuntimeVersion; +use grandpa::{AuthorityId as GrandpaId, fg_primitives}; +#[cfg(any(feature = "std", test))] +use version::NativeVersion; +use sp_core::OpaqueMetadata; +use sp_staking::SessionIndex; +use frame_support::{ + parameter_types, construct_runtime, traits::Randomness, + weights::DispatchInfo, +}; +use pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; + +#[cfg(feature = "std")] +pub use staking::StakerStatus; +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; +pub use timestamp::Call as TimestampCall; +pub use balances::Call as BalancesCall; +pub use attestations::{Call as AttestationsCall, MORE_ATTESTATIONS_IDENTIFIER}; +pub use parachains::Call as ParachainsCall; + +/// Constant values used within the runtime. +pub mod constants; +use constants::{time::*, currency::*, fee::*}; + +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +/// Runtime version (Kusama). +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("polkadot-test-runtime"), + impl_name: create_runtime_str!("parity-polkadot-test-runtime"), + authoring_version: 2, + spec_version: 1048, + impl_version: 0, + apis: RUNTIME_API_VERSIONS, +}; + +/// Native version. +#[cfg(any(feature = "std", test))] +pub fn native_version() -> NativeVersion { + NativeVersion { + runtime_version: VERSION, + can_author_with: Default::default(), + } +} + +/// Avoid processing transactions from slots and parachain registrar. +#[derive(Default, Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug)] +pub struct RestrictFunctionality; +impl SignedExtension for RestrictFunctionality { + const IDENTIFIER: &'static str = "RestrictFunctionality"; + type AccountId = AccountId; + type Call = Call; + type AdditionalSigned = (); + type Pre = (); + type DispatchInfo = DispatchInfo; + + fn additional_signed(&self) -> rstd::result::Result<(), TransactionValidityError> { Ok(()) } + + fn validate(&self, _: &Self::AccountId, call: &Self::Call, _: DispatchInfo, _: usize) + -> TransactionValidity + { + match call { + Call::Slots(_) | Call::Registrar(_) + => Err(InvalidTransaction::Custom(ValidityError::NoPermission.into()).into()), + _ => Ok(Default::default()), + } + } +} + +parameter_types! { + pub const Version: RuntimeVersion = VERSION; +} + +impl system::Trait for Runtime { + type Origin = Origin; + type Call = Call; + type Index = Nonce; + type BlockNumber = BlockNumber; + type Hash = HashT; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = Indices; + type Header = generic::Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; + type AvailableBlockRatio = AvailableBlockRatio; + type Version = Version; + type ModuleToIndex = ModuleToIndex; + type AccountData = balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); +} + +parameter_types! { + pub const EpochDuration: u64 = EPOCH_DURATION_IN_BLOCKS as u64; + pub const ExpectedBlockTime: Moment = MILLISECS_PER_BLOCK; +} + +impl babe::Trait for Runtime { + type EpochDuration = EpochDuration; + type ExpectedBlockTime = ExpectedBlockTime; + + // session module is the trigger + type EpochChangeTrigger = babe::ExternalTrigger; +} + +parameter_types! { + pub const IndexDeposit: Balance = 1 * DOLLARS; +} + +impl indices::Trait for Runtime { + type AccountIndex = AccountIndex; + type Currency = Balances; + type Deposit = IndexDeposit; + type Event = Event; +} + +parameter_types! { + pub const ExistentialDeposit: Balance = 1 * CENTS; +} + +impl balances::Trait for Runtime { + type Balance = Balance; + type DustRemoval = (); + type Event = Event; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; +} + +parameter_types! { + pub const TransactionBaseFee: Balance = 1 * CENTS; + pub const TransactionByteFee: Balance = 10 * MILLICENTS; + // for a sane configuration, this should always be less than `AvailableBlockRatio`. + pub const TargetBlockFullness: Perbill = Perbill::from_percent(25); +} + +impl transaction_payment::Trait for Runtime { + type Currency = Balances; + type OnTransactionPayment = (); + type TransactionBaseFee = TransactionBaseFee; + type TransactionByteFee = TransactionByteFee; + type WeightToFee = WeightToFee; + type FeeMultiplierUpdate = TargetedFeeAdjustment; +} + +parameter_types! { + pub const MinimumPeriod: u64 = SLOT_DURATION / 2; +} +impl timestamp::Trait for Runtime { + type Moment = u64; + type OnTimestampSet = Babe; + type MinimumPeriod = MinimumPeriod; +} + +parameter_types! { + pub const UncleGenerations: u32 = 0; +} + +// TODO: substrate#2986 implement this properly +impl authorship::Trait for Runtime { + type FindAuthor = session::FindAccountFromAuthorIndex; + type UncleGenerations = UncleGenerations; + type FilterUncle = (); + type EventHandler = Staking; +} + +parameter_types! { + pub const Period: BlockNumber = 10 * MINUTES; + pub const Offset: BlockNumber = 0; +} + +impl_opaque_keys! { + pub struct SessionKeys { + pub grandpa: Grandpa, + pub babe: Babe, + pub parachain_validator: Parachains, + } +} + +parameter_types! { + pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(17); +} + +impl session::Trait for Runtime { + type Event = Event; + type ValidatorId = AccountId; + type ValidatorIdOf = staking::StashOf; + type ShouldEndSession = Babe; + type SessionManager = Staking; + type SessionHandler = ::KeyTypeIdProviders; + type Keys = SessionKeys; + type DisabledValidatorsThreshold = DisabledValidatorsThreshold; +} + +impl session::historical::Trait for Runtime { + type FullIdentification = staking::Exposure; + type FullIdentificationOf = staking::ExposureOf; +} + +pallet_staking_reward_curve::build! { + const REWARD_CURVE: PiecewiseLinear<'static> = curve!( + min_inflation: 0_025_000, + max_inflation: 0_100_000, + ideal_stake: 0_500_000, + falloff: 0_050_000, + max_piece_count: 40, + test_precision: 0_005_000, + ); +} + +parameter_types! { + // Six sessions in an era (6 hours). + pub const SessionsPerEra: SessionIndex = 6; + // 28 eras for unbonding (7 days). + pub const BondingDuration: staking::EraIndex = 28; + // 28 eras in which slashes can be cancelled (7 days). + pub const SlashDeferDuration: staking::EraIndex = 28; + pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; + pub const MaxNominatorRewardedPerValidator: u32 = 64; +} + +impl staking::Trait for Runtime { + type Currency = Balances; + type Time = Timestamp; + type CurrencyToVote = CurrencyToVoteHandler; + type RewardRemainder = (); + type Event = Event; + type Slash = (); + type Reward = (); + type SessionsPerEra = SessionsPerEra; + type BondingDuration = BondingDuration; + type SlashDeferDuration = SlashDeferDuration; + // A majority of the council can cancel the slash. + type SlashCancelOrigin = system::EnsureNever<()>; + type SessionInterface = Self; + type RewardCurve = RewardCurve; + type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; +} + +impl grandpa::Trait for Runtime { + type Event = Event; +} + +parameter_types! { + pub const AttestationPeriod: BlockNumber = 50; +} + +impl attestations::Trait for Runtime { + type AttestationPeriod = AttestationPeriod; + type ValidatorIdentities = parachains::ValidatorIdentities; + type RewardAttestation = Staking; +} + +parameter_types! { + pub const MaxCodeSize: u32 = 10 * 1024 * 1024; // 10 MB + pub const MaxHeadDataSize: u32 = 20 * 1024; // 20 KB +} + +impl parachains::Trait for Runtime { + type Origin = Origin; + type Call = Call; + type ParachainCurrency = Balances; + type Randomness = RandomnessCollectiveFlip; + type ActiveParachains = Registrar; + type Registrar = Registrar; + type MaxCodeSize = MaxCodeSize; + type MaxHeadDataSize = MaxHeadDataSize; +} + +parameter_types! { + pub const ParathreadDeposit: Balance = 5 * DOLLARS; + pub const QueueSize: usize = 2; + pub const MaxRetries: u32 = 3; +} + +impl registrar::Trait for Runtime { + type Event = Event; + type Origin = Origin; + type Currency = Balances; + type ParathreadDeposit = ParathreadDeposit; + type SwapAux = Slots; + type QueueSize = QueueSize; + type MaxRetries = MaxRetries; +} + +parameter_types! { + pub const LeasePeriod: BlockNumber = 100_000; + pub const EndingPeriod: BlockNumber = 1000; +} + +impl slots::Trait for Runtime { + type Event = Event; + type Currency = Balances; + type Parachains = Registrar; + type LeasePeriod = LeasePeriod; + type EndingPeriod = EndingPeriod; + type Randomness = RandomnessCollectiveFlip; +} + +parameter_types! { + pub const Prefix: &'static [u8] = b"Pay KSMs to the Kusama account:"; +} + +impl claims::Trait for Runtime { + type Event = Event; + type VestingSchedule = Vesting; + type Prefix = Prefix; +} + +parameter_types! { + pub const MinVestedTransfer: Balance = 100 * DOLLARS; +} + +impl vesting::Trait for Runtime { + type Event = Event; + type Currency = Balances; + type BlockNumberToBalance = ConvertInto; + type MinVestedTransfer = MinVestedTransfer; +} + +construct_runtime! { + pub enum Runtime where + Block = Block, + NodeBlock = primitives::Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + // Basic stuff; balances is uncallable initially. + System: system::{Module, Call, Storage, Config, Event}, + RandomnessCollectiveFlip: randomness_collective_flip::{Module, Storage}, + + // Must be before session. + Babe: babe::{Module, Call, Storage, Config, Inherent(Timestamp)}, + + Timestamp: timestamp::{Module, Call, Storage, Inherent}, + Indices: indices::{Module, Call, Storage, Config, Event}, + Balances: balances::{Module, Call, Storage, Config, Event}, + TransactionPayment: transaction_payment::{Module, Storage}, + + // Consensus support. + Authorship: authorship::{Module, Call, Storage}, + Staking: staking::{Module, Call, Storage, Config, Event}, + Session: session::{Module, Call, Storage, Event, Config}, + Grandpa: grandpa::{Module, Call, Storage, Config, Event}, + + // Claims. Usable initially. + Claims: claims::{Module, Call, Storage, Event, Config, ValidateUnsigned}, + + // Parachains stuff; slots are disabled (no auctions initially). The rest are safe as they + // have no public dispatchables. + Parachains: parachains::{Module, Call, Storage, Config, Inherent, Origin}, + Attestations: attestations::{Module, Call, Storage}, + Slots: slots::{Module, Call, Storage, Event}, + Registrar: registrar::{Module, Call, Storage, Event, Config}, + + // Vesting. Usable initially, but removed once all vesting is finished. + Vesting: vesting::{Module, Call, Storage, Event, Config}, + } +} + +/// The address format for describing accounts. +pub type Address = ::Source; +/// Block header type as expected by this runtime. +pub type Header = generic::Header; +/// Block type as expected by this runtime. +pub type Block = generic::Block; +/// A Block signed with a Justification +pub type SignedBlock = generic::SignedBlock; +/// BlockId type as expected by this runtime. +pub type BlockId = generic::BlockId; +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( + RestrictFunctionality, + system::CheckVersion, + system::CheckGenesis, + system::CheckEra, + system::CheckNonce, + system::CheckWeight, + transaction_payment::ChargeTransactionPayment::, + registrar::LimitParathreadCommits +); +/// Unchecked extrinsic type as expected by this runtime. +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +/// Extrinsic type that has already been checked. +pub type CheckedExtrinsic = generic::CheckedExtrinsic; +/// Executive: handles dispatch to the various modules. +pub type Executive = executive::Executive, Runtime, AllModules>; + +pub type Hash = ::Hash; +pub type Extrinsic = ::Extrinsic; + +sp_api::impl_runtime_apis! { + impl sp_api::Core for Runtime { + fn version() -> RuntimeVersion { + VERSION + } + + fn execute_block(block: Block) { + Executive::execute_block(block) + } + + fn initialize_block(header: &::Header) { + Executive::initialize_block(header) + } + } + + impl sp_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + Runtime::metadata().into() + } + } + + impl block_builder_api::BlockBuilder for Runtime { + fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { + Executive::apply_extrinsic(extrinsic) + } + + fn finalize_block() -> ::Header { + Executive::finalize_block() + } + + fn inherent_extrinsics(data: inherents::InherentData) -> Vec<::Extrinsic> { + data.create_extrinsics() + } + + fn check_inherents( + block: Block, + data: inherents::InherentData, + ) -> inherents::CheckInherentsResult { + data.check_extrinsics(&block) + } + + fn random_seed() -> ::Hash { + RandomnessCollectiveFlip::random_seed() + } + } + + impl tx_pool_api::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction(tx: ::Extrinsic) -> TransactionValidity { + Executive::validate_transaction(tx) + } + } + + impl parachain::ParachainHost for Runtime { + fn validators() -> Vec { + Parachains::authorities() + } + fn duty_roster() -> parachain::DutyRoster { + Parachains::calculate_duty_roster().0 + } + fn active_parachains() -> Vec<(parachain::Id, Option<(parachain::CollatorId, parachain::Retriable)>)> { + Registrar::active_paras() + } + fn global_validation_schedule() -> parachain::GlobalValidationSchedule { + Parachains::global_validation_schedule() + } + fn local_validation_data(id: parachain::Id) -> Option { + Parachains::local_validation_data(&id) + } + fn parachain_code(id: parachain::Id) -> Option> { + Parachains::parachain_code(&id) + } + fn get_heads(extrinsics: Vec<::Extrinsic>) + -> Option> + { + extrinsics + .into_iter() + .find_map(|ex| match UncheckedExtrinsic::decode(&mut ex.encode().as_slice()) { + Ok(ex) => match ex.function { + Call::Parachains(ParachainsCall::set_heads(heads)) => { + Some(heads.into_iter().map(|c| c.candidate).collect()) + } + _ => None, + } + Err(_) => None, + }) + } + } + + impl fg_primitives::GrandpaApi for Runtime { + fn grandpa_authorities() -> Vec<(GrandpaId, u64)> { + Grandpa::grandpa_authorities() + } + } + + impl babe_primitives::BabeApi for Runtime { + fn configuration() -> babe_primitives::BabeConfiguration { + // The choice of `c` parameter (where `1 - c` represents the + // probability of a slot being empty), is done in accordance to the + // slot duration and expected target block time, for safely + // resisting network delays of maximum two seconds. + // + babe_primitives::BabeConfiguration { + slot_duration: Babe::slot_duration(), + epoch_length: EpochDuration::get(), + c: PRIMARY_PROBABILITY, + genesis_authorities: Babe::authorities(), + randomness: Babe::randomness(), + secondary_slots: true, + } + } + + fn current_epoch_start() -> babe_primitives::SlotNumber { + Babe::current_epoch_start() + } + } + + impl sp_session::SessionKeys for Runtime { + fn generate_session_keys(seed: Option>) -> Vec { + SessionKeys::generate(seed) + } + + fn decode_session_keys( + encoded: Vec, + ) -> Option, sp_core::crypto::KeyTypeId)>> { + SessionKeys::decode_into_raw_public_keys(&encoded) + } + } + + impl system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(account: AccountId) -> Nonce { + System::account_nonce(account) + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi< + Block, + Balance, + UncheckedExtrinsic, + > for Runtime { + fn query_info(uxt: UncheckedExtrinsic, len: u32) -> RuntimeDispatchInfo { + TransactionPayment::query_info(uxt, len) + } + } +}