mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-19 14:35:40 +00:00
introduce errors with info (#1834)
This commit is contained in:
committed by
GitHub
parent
40ea09389c
commit
f345123748
Generated
+58
-290
@@ -224,32 +224,18 @@ dependencies = [
|
|||||||
"futures-core",
|
"futures-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-executor"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "90f47c78ea98277cb1f5e6f60ba4fc762f5eafe9f6511bc2f7dfd8b75c225650"
|
|
||||||
dependencies = [
|
|
||||||
"async-io 0.1.5",
|
|
||||||
"futures-lite 0.1.10",
|
|
||||||
"multitask",
|
|
||||||
"parking 1.0.5",
|
|
||||||
"scoped-tls",
|
|
||||||
"waker-fn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-executor"
|
name = "async-executor"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d373d78ded7d0b3fa8039375718cde0aace493f2e34fb60f51cbf567562ca801"
|
checksum = "d373d78ded7d0b3fa8039375718cde0aace493f2e34fb60f51cbf567562ca801"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-task 4.0.3",
|
"async-task",
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"futures-lite 1.11.2",
|
"futures-lite",
|
||||||
"once_cell 1.4.1",
|
"once_cell 1.4.1",
|
||||||
"vec-arena 1.0.0",
|
"vec-arena",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -258,31 +244,13 @@ version = "1.4.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "124ac8c265e407641c3362b8f4d39cdb4e243885b71eef087be27199790f5a3a"
|
checksum = "124ac8c265e407641c3362b8f4d39cdb4e243885b71eef087be27199790f5a3a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-executor 1.3.0",
|
"async-executor",
|
||||||
"async-io 1.1.0",
|
"async-io",
|
||||||
"futures-lite 1.11.2",
|
"futures-lite",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"once_cell 1.4.1",
|
"once_cell 1.4.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-io"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ca8126ef9fb99355c6fd27575d691be4887b884137a5b6f48c2d961f13590c51"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"concurrent-queue",
|
|
||||||
"futures-lite 0.1.10",
|
|
||||||
"libc",
|
|
||||||
"once_cell 1.4.1",
|
|
||||||
"parking 1.0.5",
|
|
||||||
"socket2",
|
|
||||||
"vec-arena 0.5.0",
|
|
||||||
"wepoll-sys-stjepang",
|
|
||||||
"winapi 0.3.9",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-io"
|
name = "async-io"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -292,14 +260,14 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"futures-lite 1.11.2",
|
"futures-lite",
|
||||||
"libc",
|
"libc",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"once_cell 1.4.1",
|
"once_cell 1.4.1",
|
||||||
"parking 2.0.0",
|
"parking",
|
||||||
"polling",
|
"polling",
|
||||||
"socket2",
|
"socket2",
|
||||||
"vec-arena 1.0.0",
|
"vec-arena",
|
||||||
"waker-fn",
|
"waker-fn",
|
||||||
"wepoll-sys-stjepang",
|
"wepoll-sys-stjepang",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
@@ -321,14 +289,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "a9fa76751505e8df1c7a77762f60486f60c71bbd9b8557f4da6ad47d083732ed"
|
checksum = "a9fa76751505e8df1c7a77762f60486f60c71bbd9b8557f4da6ad47d083732ed"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-global-executor",
|
"async-global-executor",
|
||||||
"async-io 1.1.0",
|
"async-io",
|
||||||
"async-mutex",
|
"async-mutex",
|
||||||
"blocking 1.0.2",
|
"blocking",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-lite 1.11.2",
|
"futures-lite",
|
||||||
"gloo-timers",
|
"gloo-timers",
|
||||||
"kv-log-macro",
|
"kv-log-macro",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
@@ -341,12 +309,6 @@ dependencies = [
|
|||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-task"
|
|
||||||
version = "3.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c17772156ef2829aadc587461c7753af20b7e8db1529bc66855add962a3b35d3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-task"
|
name = "async-task"
|
||||||
version = "4.0.3"
|
version = "4.0.3"
|
||||||
@@ -598,33 +560,6 @@ dependencies = [
|
|||||||
"byte-tools",
|
"byte-tools",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "blocking"
|
|
||||||
version = "0.4.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d2468ff7bf85066b4a3678fede6fe66db31846d753ff0adfbfab2c6a6e81612b"
|
|
||||||
dependencies = [
|
|
||||||
"async-channel",
|
|
||||||
"atomic-waker",
|
|
||||||
"futures-lite 0.1.10",
|
|
||||||
"once_cell 1.4.1",
|
|
||||||
"parking 1.0.5",
|
|
||||||
"waker-fn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "blocking"
|
|
||||||
version = "0.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "76e94bf99b692f54c9d05f97454d3faf11134523fe5b180564a3fb6ed63bcc0a"
|
|
||||||
dependencies = [
|
|
||||||
"async-channel",
|
|
||||||
"atomic-waker",
|
|
||||||
"futures-lite 0.1.10",
|
|
||||||
"once_cell 1.4.1",
|
|
||||||
"waker-fn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blocking"
|
name = "blocking"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
@@ -632,10 +567,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9"
|
checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel",
|
"async-channel",
|
||||||
"async-task 4.0.3",
|
"async-task",
|
||||||
"atomic-waker",
|
"atomic-waker",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"futures-lite 1.11.2",
|
"futures-lite",
|
||||||
"once_cell 1.4.1",
|
"once_cell 1.4.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1107,32 +1042,6 @@ version = "2.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72aa14c04dfae8dd7d8a2b1cb7ca2152618cd01336dbfe704b8dcbf8d41dbd69"
|
checksum = "72aa14c04dfae8dd7d8a2b1cb7ca2152618cd01336dbfe704b8dcbf8d41dbd69"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "derive_more"
|
|
||||||
version = "0.14.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6d944ac6003ed268757ef1ee686753b57efc5fcf0ebe7b64c9fc81e7e32ff839"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2 0.4.30",
|
|
||||||
"quote 0.6.13",
|
|
||||||
"rustc_version",
|
|
||||||
"syn 0.15.44",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "derive_more"
|
|
||||||
version = "0.15.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7a141330240c921ec6d074a3e188a7c7ef95668bb95e7d44fa0e5778ec2a7afe"
|
|
||||||
dependencies = [
|
|
||||||
"lazy_static",
|
|
||||||
"proc-macro2 0.4.30",
|
|
||||||
"quote 0.6.13",
|
|
||||||
"regex",
|
|
||||||
"rustc_version",
|
|
||||||
"syn 0.15.44",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_more"
|
name = "derive_more"
|
||||||
version = "0.99.11"
|
version = "0.99.11"
|
||||||
@@ -1241,12 +1150,6 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4c53dc3a653e0f64081026e4bf048d48fec9fce90c66e8326ca7292df0ff2d82"
|
checksum = "4c53dc3a653e0f64081026e4bf048d48fec9fce90c66e8326ca7292df0ff2d82"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "easy-parallel"
|
|
||||||
version = "3.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1dd4afd79212583ff429b913ad6605242ed7eec277e950b1438f300748f948f4"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ed25519"
|
name = "ed25519"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@@ -1448,15 +1351,16 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "femme"
|
name = "femme"
|
||||||
version = "2.1.0"
|
version = "2.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7b6b21baebbed15551f2170010ca4101b9ed3fdc05822791c8bd4631840eab81"
|
checksum = "2af1a24f391a5a94d756db5092c6576aad494b88a71a5a36b20c67b63e0df034"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
@@ -1829,21 +1733,6 @@ version = "0.3.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789"
|
checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-lite"
|
|
||||||
version = "0.1.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bbe71459749b2e8e66fb95df721b22fa08661ad384a0c5b519e11d3893b4692a"
|
|
||||||
dependencies = [
|
|
||||||
"fastrand",
|
|
||||||
"futures-core",
|
|
||||||
"futures-io",
|
|
||||||
"memchr",
|
|
||||||
"parking 1.0.5",
|
|
||||||
"pin-project-lite",
|
|
||||||
"waker-fn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-lite"
|
name = "futures-lite"
|
||||||
version = "1.11.2"
|
version = "1.11.2"
|
||||||
@@ -1854,7 +1743,7 @@ dependencies = [
|
|||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"memchr",
|
"memchr",
|
||||||
"parking 2.0.0",
|
"parking",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"waker-fn",
|
"waker-fn",
|
||||||
]
|
]
|
||||||
@@ -3641,17 +3530,6 @@ dependencies = [
|
|||||||
"unsigned-varint 0.4.0",
|
"unsigned-varint 0.4.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "multitask"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c09c35271e7dcdb5f709779111f2c8e8ab8e06c1b587c1c6a9e179d865aaa5b4"
|
|
||||||
dependencies = [
|
|
||||||
"async-task 3.0.0",
|
|
||||||
"concurrent-queue",
|
|
||||||
"fastrand",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nalgebra"
|
name = "nalgebra"
|
||||||
version = "0.18.1"
|
version = "0.18.1"
|
||||||
@@ -4544,12 +4422,6 @@ dependencies = [
|
|||||||
"url 2.1.1",
|
"url 2.1.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parking"
|
|
||||||
version = "1.0.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "50d4a6da31f8144a32532fe38fe8fb439a6842e0ec633f0037f0144c14e7f907"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking"
|
name = "parking"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
@@ -4784,25 +4656,18 @@ dependencies = [
|
|||||||
"bitvec",
|
"bitvec",
|
||||||
"env_logger 0.7.1",
|
"env_logger 0.7.1",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"futures-timer 3.0.2",
|
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"maplit",
|
"maplit",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"parking_lot 0.11.0",
|
|
||||||
"polkadot-network-bridge",
|
|
||||||
"polkadot-node-network-protocol",
|
"polkadot-node-network-protocol",
|
||||||
"polkadot-node-primitives",
|
|
||||||
"polkadot-node-subsystem",
|
"polkadot-node-subsystem",
|
||||||
"polkadot-node-subsystem-test-helpers",
|
"polkadot-node-subsystem-test-helpers",
|
||||||
"polkadot-node-subsystem-util",
|
"polkadot-node-subsystem-util",
|
||||||
"polkadot-primitives",
|
"polkadot-primitives",
|
||||||
"sc-keystore",
|
"sc-keystore",
|
||||||
"sc-network",
|
|
||||||
"smol 0.3.3",
|
|
||||||
"sp-application-crypto",
|
"sp-application-crypto",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-keystore",
|
"sp-keystore",
|
||||||
"streamunordered",
|
|
||||||
"tempfile",
|
"tempfile",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -4811,16 +4676,12 @@ name = "polkadot-availability-distribution"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_matches",
|
"assert_matches",
|
||||||
"bitvec",
|
|
||||||
"derive_more 0.99.11",
|
|
||||||
"env_logger 0.7.1",
|
"env_logger 0.7.1",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"futures-timer 3.0.2",
|
"futures-timer 3.0.2",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"parking_lot 0.11.0",
|
|
||||||
"polkadot-erasure-coding",
|
"polkadot-erasure-coding",
|
||||||
"polkadot-network-bridge",
|
|
||||||
"polkadot-node-network-protocol",
|
"polkadot-node-network-protocol",
|
||||||
"polkadot-node-subsystem",
|
"polkadot-node-subsystem",
|
||||||
"polkadot-node-subsystem-test-helpers",
|
"polkadot-node-subsystem-test-helpers",
|
||||||
@@ -4832,7 +4693,7 @@ dependencies = [
|
|||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-keyring",
|
"sp-keyring",
|
||||||
"sp-keystore",
|
"sp-keystore",
|
||||||
"streamunordered",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4840,23 +4701,16 @@ name = "polkadot-cli"
|
|||||||
version = "0.8.25"
|
version = "0.8.25"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"frame-benchmarking-cli",
|
"frame-benchmarking-cli",
|
||||||
"futures 0.3.5",
|
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"polkadot-service",
|
"polkadot-service",
|
||||||
"sc-cli",
|
"sc-cli",
|
||||||
"sc-client-api",
|
|
||||||
"sc-client-db",
|
|
||||||
"sc-executor",
|
|
||||||
"sc-service",
|
"sc-service",
|
||||||
"sc-tracing",
|
"sc-tracing",
|
||||||
"sp-api",
|
|
||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-runtime",
|
|
||||||
"sp-trie",
|
"sp-trie",
|
||||||
"structopt",
|
"structopt",
|
||||||
"substrate-browser-utils",
|
"substrate-browser-utils",
|
||||||
"substrate-build-script-utils",
|
"substrate-build-script-utils",
|
||||||
"tokio 0.2.21",
|
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
]
|
]
|
||||||
@@ -4866,22 +4720,19 @@ name = "polkadot-collator-protocol"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_matches",
|
"assert_matches",
|
||||||
"derive_more 0.99.11",
|
|
||||||
"env_logger 0.7.1",
|
"env_logger 0.7.1",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"futures-timer 3.0.2",
|
"futures-timer 3.0.2",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"parity-scale-codec",
|
|
||||||
"polkadot-network-bridge",
|
|
||||||
"polkadot-node-network-protocol",
|
"polkadot-node-network-protocol",
|
||||||
"polkadot-node-subsystem",
|
"polkadot-node-subsystem",
|
||||||
"polkadot-node-subsystem-test-helpers",
|
"polkadot-node-subsystem-test-helpers",
|
||||||
"polkadot-node-subsystem-util",
|
"polkadot-node-subsystem-util",
|
||||||
"polkadot-primitives",
|
"polkadot-primitives",
|
||||||
"smallvec 1.4.2",
|
"smallvec 1.4.2",
|
||||||
"smol-timeout",
|
|
||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-keyring",
|
"sp-keyring",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4898,12 +4749,12 @@ dependencies = [
|
|||||||
name = "polkadot-erasure-coding"
|
name = "polkadot-erasure-coding"
|
||||||
version = "0.8.25"
|
version = "0.8.25"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.15.0",
|
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"polkadot-primitives",
|
"polkadot-primitives",
|
||||||
"reed-solomon-erasure",
|
"reed-solomon-erasure",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-trie",
|
"sp-trie",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4913,7 +4764,6 @@ dependencies = [
|
|||||||
"assert_matches",
|
"assert_matches",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"futures-timer 3.0.2",
|
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"parking_lot 0.10.2",
|
"parking_lot 0.10.2",
|
||||||
@@ -4926,14 +4776,12 @@ dependencies = [
|
|||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-keyring",
|
"sp-keyring",
|
||||||
"sp-runtime",
|
"sp-runtime",
|
||||||
"streamunordered",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polkadot-node-collation-generation"
|
name = "polkadot-node-collation-generation"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.99.11",
|
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"polkadot-erasure-coding",
|
"polkadot-erasure-coding",
|
||||||
@@ -4943,6 +4791,7 @@ dependencies = [
|
|||||||
"polkadot-node-subsystem-util",
|
"polkadot-node-subsystem-util",
|
||||||
"polkadot-primitives",
|
"polkadot-primitives",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4950,7 +4799,6 @@ name = "polkadot-node-core-av-store"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_matches",
|
"assert_matches",
|
||||||
"derive_more 0.99.11",
|
|
||||||
"env_logger 0.7.1",
|
"env_logger 0.7.1",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"futures-timer 3.0.2",
|
"futures-timer 3.0.2",
|
||||||
@@ -4967,6 +4815,7 @@ dependencies = [
|
|||||||
"polkadot-primitives",
|
"polkadot-primitives",
|
||||||
"smallvec 1.4.2",
|
"smallvec 1.4.2",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4975,7 +4824,6 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_matches",
|
"assert_matches",
|
||||||
"bitvec",
|
"bitvec",
|
||||||
"derive_more 0.99.11",
|
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"polkadot-erasure-coding",
|
"polkadot-erasure-coding",
|
||||||
@@ -4985,14 +4833,12 @@ dependencies = [
|
|||||||
"polkadot-node-subsystem-util",
|
"polkadot-node-subsystem-util",
|
||||||
"polkadot-primitives",
|
"polkadot-primitives",
|
||||||
"polkadot-statement-table",
|
"polkadot-statement-table",
|
||||||
"sc-client-api",
|
|
||||||
"sc-keystore",
|
"sc-keystore",
|
||||||
"sp-api",
|
|
||||||
"sp-application-crypto",
|
"sp-application-crypto",
|
||||||
"sp-blockchain",
|
|
||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-keyring",
|
"sp-keyring",
|
||||||
"sp-keystore",
|
"sp-keystore",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5000,13 +4846,13 @@ name = "polkadot-node-core-bitfield-signing"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitvec",
|
"bitvec",
|
||||||
"derive_more 0.99.11",
|
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"polkadot-node-subsystem",
|
"polkadot-node-subsystem",
|
||||||
"polkadot-node-subsystem-util",
|
"polkadot-node-subsystem-util",
|
||||||
"polkadot-primitives",
|
"polkadot-primitives",
|
||||||
"sp-keystore",
|
"sp-keystore",
|
||||||
|
"thiserror",
|
||||||
"wasm-timer",
|
"wasm-timer",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -5014,7 +4860,6 @@ dependencies = [
|
|||||||
name = "polkadot-node-core-candidate-selection"
|
name = "polkadot-node-core-candidate-selection"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.99.11",
|
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"polkadot-node-primitives",
|
"polkadot-node-primitives",
|
||||||
@@ -5022,6 +4867,7 @@ dependencies = [
|
|||||||
"polkadot-node-subsystem-util",
|
"polkadot-node-subsystem-util",
|
||||||
"polkadot-primitives",
|
"polkadot-primitives",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5029,7 +4875,6 @@ name = "polkadot-node-core-candidate-validation"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_matches",
|
"assert_matches",
|
||||||
"derive_more 0.99.11",
|
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
@@ -5039,7 +4884,6 @@ dependencies = [
|
|||||||
"polkadot-node-subsystem-util",
|
"polkadot-node-subsystem-util",
|
||||||
"polkadot-parachain",
|
"polkadot-parachain",
|
||||||
"polkadot-primitives",
|
"polkadot-primitives",
|
||||||
"sp-blockchain",
|
|
||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-keyring",
|
"sp-keyring",
|
||||||
]
|
]
|
||||||
@@ -5063,16 +4907,13 @@ name = "polkadot-node-core-proposer"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"futures-timer 3.0.2",
|
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"parity-scale-codec",
|
|
||||||
"polkadot-node-subsystem",
|
"polkadot-node-subsystem",
|
||||||
"polkadot-overseer",
|
"polkadot-overseer",
|
||||||
"polkadot-primitives",
|
"polkadot-primitives",
|
||||||
"sc-basic-authorship",
|
"sc-basic-authorship",
|
||||||
"sc-block-builder",
|
"sc-block-builder",
|
||||||
"sc-client-api",
|
"sc-client-api",
|
||||||
"sc-telemetry",
|
|
||||||
"sp-api",
|
"sp-api",
|
||||||
"sp-blockchain",
|
"sp-blockchain",
|
||||||
"sp-consensus",
|
"sp-consensus",
|
||||||
@@ -5080,7 +4921,6 @@ dependencies = [
|
|||||||
"sp-inherents",
|
"sp-inherents",
|
||||||
"sp-runtime",
|
"sp-runtime",
|
||||||
"sp-transaction-pool",
|
"sp-transaction-pool",
|
||||||
"tokio-executor 0.2.0-alpha.6",
|
|
||||||
"wasm-timer",
|
"wasm-timer",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -5089,19 +4929,17 @@ name = "polkadot-node-core-provisioner"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitvec",
|
"bitvec",
|
||||||
"derive_more 0.99.11",
|
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"futures-timer 3.0.2",
|
"futures-timer 3.0.2",
|
||||||
"lazy_static",
|
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"polkadot-node-subsystem",
|
"polkadot-node-subsystem",
|
||||||
"polkadot-node-subsystem-util",
|
"polkadot-node-subsystem-util",
|
||||||
"polkadot-primitives",
|
"polkadot-primitives",
|
||||||
"sc-keystore",
|
"sc-keystore",
|
||||||
"sp-application-crypto",
|
"sp-application-crypto",
|
||||||
"sp-core",
|
|
||||||
"sp-keystore",
|
"sp-keystore",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5109,13 +4947,11 @@ name = "polkadot-node-core-runtime-api"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"polkadot-node-primitives",
|
|
||||||
"polkadot-node-subsystem",
|
"polkadot-node-subsystem",
|
||||||
"polkadot-node-subsystem-test-helpers",
|
"polkadot-node-subsystem-test-helpers",
|
||||||
"polkadot-node-subsystem-util",
|
"polkadot-node-subsystem-util",
|
||||||
"polkadot-primitives",
|
"polkadot-primitives",
|
||||||
"sp-api",
|
"sp-api",
|
||||||
"sp-blockchain",
|
|
||||||
"sp-core",
|
"sp-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -5127,8 +4963,6 @@ dependencies = [
|
|||||||
"polkadot-node-primitives",
|
"polkadot-node-primitives",
|
||||||
"polkadot-primitives",
|
"polkadot-primitives",
|
||||||
"sc-network",
|
"sc-network",
|
||||||
"sp-core",
|
|
||||||
"sp-runtime",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5149,7 +4983,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_matches",
|
"assert_matches",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"futures-timer 3.0.2",
|
"futures-timer 3.0.2",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
@@ -5164,6 +4998,7 @@ dependencies = [
|
|||||||
"sc-network",
|
"sc-network",
|
||||||
"smallvec 1.4.2",
|
"smallvec 1.4.2",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5171,7 +5006,6 @@ name = "polkadot-node-subsystem-test-helpers"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"derive_more 0.99.11",
|
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"futures-timer 3.0.2",
|
"futures-timer 3.0.2",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
@@ -5195,7 +5029,6 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_matches",
|
"assert_matches",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"derive_more 0.99.11",
|
|
||||||
"env_logger 0.7.1",
|
"env_logger 0.7.1",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"futures-timer 3.0.2",
|
"futures-timer 3.0.2",
|
||||||
@@ -5207,14 +5040,13 @@ dependencies = [
|
|||||||
"polkadot-node-subsystem",
|
"polkadot-node-subsystem",
|
||||||
"polkadot-node-subsystem-test-helpers",
|
"polkadot-node-subsystem-test-helpers",
|
||||||
"polkadot-primitives",
|
"polkadot-primitives",
|
||||||
"polkadot-statement-table",
|
|
||||||
"sc-network",
|
"sc-network",
|
||||||
"smallvec 1.4.2",
|
|
||||||
"sp-application-crypto",
|
"sp-application-crypto",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-keystore",
|
"sp-keystore",
|
||||||
"streamunordered",
|
"streamunordered",
|
||||||
"substrate-prometheus-endpoint",
|
"substrate-prometheus-endpoint",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5241,7 +5073,7 @@ dependencies = [
|
|||||||
name = "polkadot-parachain"
|
name = "polkadot-parachain"
|
||||||
version = "0.8.25"
|
version = "0.8.25"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
@@ -5264,19 +5096,13 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_matches",
|
"assert_matches",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"futures-timer 3.0.2",
|
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"parity-scale-codec",
|
|
||||||
"parking_lot 0.10.2",
|
|
||||||
"polkadot-node-network-protocol",
|
"polkadot-node-network-protocol",
|
||||||
"polkadot-node-primitives",
|
|
||||||
"polkadot-node-subsystem",
|
"polkadot-node-subsystem",
|
||||||
"polkadot-node-subsystem-test-helpers",
|
"polkadot-node-subsystem-test-helpers",
|
||||||
"polkadot-node-subsystem-util",
|
"polkadot-node-subsystem-util",
|
||||||
"polkadot-primitives",
|
"polkadot-primitives",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-runtime",
|
|
||||||
"streamunordered",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5570,11 +5396,8 @@ dependencies = [
|
|||||||
"arrayvec 0.5.1",
|
"arrayvec 0.5.1",
|
||||||
"assert_matches",
|
"assert_matches",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"futures-timer 3.0.2",
|
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"parity-scale-codec",
|
|
||||||
"parking_lot 0.10.2",
|
|
||||||
"polkadot-node-network-protocol",
|
"polkadot-node-network-protocol",
|
||||||
"polkadot-node-primitives",
|
"polkadot-node-primitives",
|
||||||
"polkadot-node-subsystem",
|
"polkadot-node-subsystem",
|
||||||
@@ -5586,9 +5409,7 @@ dependencies = [
|
|||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-keyring",
|
"sp-keyring",
|
||||||
"sp-keystore",
|
"sp-keystore",
|
||||||
"sp-runtime",
|
|
||||||
"sp-staking",
|
"sp-staking",
|
||||||
"streamunordered",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5736,7 +5557,6 @@ dependencies = [
|
|||||||
name = "polkadot-validation"
|
name = "polkadot-validation"
|
||||||
version = "0.8.25"
|
version = "0.8.25"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.14.1",
|
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
@@ -5758,6 +5578,7 @@ dependencies = [
|
|||||||
"sp-transaction-pool",
|
"sp-transaction-pool",
|
||||||
"sp-trie",
|
"sp-trie",
|
||||||
"substrate-prometheus-endpoint",
|
"substrate-prometheus-endpoint",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -6590,7 +6411,7 @@ source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e2
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"bytes 0.5.6",
|
"bytes 0.5.6",
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"either",
|
"either",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"futures-timer 3.0.2",
|
"futures-timer 3.0.2",
|
||||||
@@ -6695,7 +6516,7 @@ dependencies = [
|
|||||||
"atty",
|
"atty",
|
||||||
"bip39",
|
"bip39",
|
||||||
"chrono",
|
"chrono",
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"fdlimit",
|
"fdlimit",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"hex",
|
"hex",
|
||||||
@@ -6756,7 +6577,7 @@ name = "sc-client-api"
|
|||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"fnv",
|
"fnv",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"hash-db",
|
"hash-db",
|
||||||
@@ -6834,7 +6655,7 @@ name = "sc-consensus-babe"
|
|||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"fork-tree",
|
"fork-tree",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"futures-timer 3.0.2",
|
"futures-timer 3.0.2",
|
||||||
@@ -6879,7 +6700,7 @@ name = "sc-consensus-babe-rpc"
|
|||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"jsonrpc-core",
|
"jsonrpc-core",
|
||||||
"jsonrpc-core-client",
|
"jsonrpc-core-client",
|
||||||
@@ -6953,7 +6774,7 @@ name = "sc-executor"
|
|||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libsecp256k1",
|
"libsecp256k1",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
@@ -6982,7 +6803,7 @@ name = "sc-executor-common"
|
|||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"parity-wasm",
|
"parity-wasm",
|
||||||
@@ -7032,7 +6853,7 @@ name = "sc-finality-grandpa"
|
|||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"finality-grandpa",
|
"finality-grandpa",
|
||||||
"fork-tree",
|
"fork-tree",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
@@ -7069,7 +6890,7 @@ name = "sc-finality-grandpa-rpc"
|
|||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"finality-grandpa",
|
"finality-grandpa",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"jsonrpc-core",
|
"jsonrpc-core",
|
||||||
@@ -7112,7 +6933,7 @@ version = "2.0.0"
|
|||||||
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"hex",
|
"hex",
|
||||||
@@ -7155,7 +6976,7 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
"bs58",
|
"bs58",
|
||||||
"bytes 0.5.6",
|
"bytes 0.5.6",
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"either",
|
"either",
|
||||||
"erased-serde",
|
"erased-serde",
|
||||||
"fnv",
|
"fnv",
|
||||||
@@ -7301,7 +7122,7 @@ name = "sc-rpc-api"
|
|||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"jsonrpc-core",
|
"jsonrpc-core",
|
||||||
"jsonrpc-core-client",
|
"jsonrpc-core-client",
|
||||||
@@ -7343,7 +7164,7 @@ name = "sc-service"
|
|||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"directories",
|
"directories",
|
||||||
"exit-future",
|
"exit-future",
|
||||||
"futures 0.1.29",
|
"futures 0.1.29",
|
||||||
@@ -7480,7 +7301,7 @@ name = "sc-transaction-graph"
|
|||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"linked-hash-map",
|
"linked-hash-map",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
@@ -7501,7 +7322,7 @@ name = "sc-transaction-pool"
|
|||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"futures-diagnose",
|
"futures-diagnose",
|
||||||
"intervalier",
|
"intervalier",
|
||||||
@@ -7870,53 +7691,6 @@ version = "1.4.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252"
|
checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "smol"
|
|
||||||
version = "0.1.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "620cbb3c6e34da57d3a248cda0cd01cd5848164dc062e764e65d06fe3ea7aed5"
|
|
||||||
dependencies = [
|
|
||||||
"async-task 3.0.0",
|
|
||||||
"blocking 0.4.7",
|
|
||||||
"concurrent-queue",
|
|
||||||
"fastrand",
|
|
||||||
"futures-io",
|
|
||||||
"futures-util",
|
|
||||||
"libc",
|
|
||||||
"once_cell 1.4.1",
|
|
||||||
"scoped-tls",
|
|
||||||
"slab",
|
|
||||||
"socket2",
|
|
||||||
"wepoll-sys-stjepang",
|
|
||||||
"winapi 0.3.9",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "smol"
|
|
||||||
version = "0.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "67583f4ccc13bbb105a0752058d8ad66c47753d85445952809bcaca891954f83"
|
|
||||||
dependencies = [
|
|
||||||
"async-channel",
|
|
||||||
"async-executor 0.1.2",
|
|
||||||
"async-io 0.1.5",
|
|
||||||
"blocking 0.5.0",
|
|
||||||
"cfg-if",
|
|
||||||
"easy-parallel",
|
|
||||||
"futures-lite 0.1.10",
|
|
||||||
"num_cpus",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "smol-timeout"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "024818c1f00b80e8171ddcfcee33860134293aa3aced60c9cbd7a5a2d41db392"
|
|
||||||
dependencies = [
|
|
||||||
"pin-project",
|
|
||||||
"smol 0.1.18",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "snow"
|
name = "snow"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
@@ -7968,7 +7742,7 @@ name = "sp-allocator"
|
|||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-std",
|
"sp-std",
|
||||||
@@ -8067,7 +7841,7 @@ name = "sp-blockchain"
|
|||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"lru 0.4.3",
|
"lru 0.4.3",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
@@ -8093,7 +7867,7 @@ name = "sp-consensus"
|
|||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"futures-timer 3.0.2",
|
"futures-timer 3.0.2",
|
||||||
"libp2p",
|
"libp2p",
|
||||||
@@ -8250,7 +8024,7 @@ name = "sp-inherents"
|
|||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"parking_lot 0.10.2",
|
"parking_lot 0.10.2",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
@@ -8298,7 +8072,7 @@ version = "0.8.0"
|
|||||||
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"merlin",
|
"merlin",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
@@ -8525,7 +8299,7 @@ name = "sp-transaction-pool"
|
|||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"futures 0.3.5",
|
"futures 0.3.5",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
@@ -8777,7 +8551,7 @@ version = "0.8.0"
|
|||||||
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
source = "git+https://github.com/paritytech/substrate#d766e229466d63afadd19097e277d85146fee3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-std",
|
"async-std",
|
||||||
"derive_more 0.99.11",
|
"derive_more",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"hyper 0.13.6",
|
"hyper 0.13.6",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
@@ -8984,18 +8758,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.20"
|
version = "1.0.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08"
|
checksum = "318234ffa22e0920fe9a40d7b8369b5f649d490980cf7aadcf1eb91594869b42"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.20"
|
version = "1.0.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793"
|
checksum = "cae2447b6282786c3493999f40a9be2a6ad20cb8bd268b0a0dbf5a065535c0ab"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.18",
|
"proc-macro2 1.0.18",
|
||||||
"quote 1.0.7",
|
"quote 1.0.7",
|
||||||
@@ -9651,12 +9425,6 @@ version = "0.2.10"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c"
|
checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vec-arena"
|
|
||||||
version = "0.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "17dfb54bf57c9043f4616cb03dab30eff012cc26631b797d8354b916708db919"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vec-arena"
|
name = "vec-arena"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
|||||||
+3
-10
@@ -14,19 +14,12 @@ wasm-opt = false
|
|||||||
crate-type = ["cdylib", "rlib"]
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4.8"
|
log = "0.4.11"
|
||||||
futures = { version = "0.3.4", features = ["compat"] }
|
structopt = { version = "0.3.8", optional = true }
|
||||||
structopt = "0.3.8"
|
|
||||||
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|
||||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|
||||||
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|
||||||
sc-client-db = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|
||||||
sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|
||||||
sc-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sc-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
service = { package = "polkadot-service", path = "../node/service", default-features = false, optional = true }
|
service = { package = "polkadot-service", path = "../node/service", default-features = false, optional = true }
|
||||||
|
|
||||||
tokio = { version = "0.2.13", features = ["rt-threaded"], optional = true }
|
|
||||||
frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
|
frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
|
||||||
sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
|
sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
|
||||||
sc-service = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
|
sc-service = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
|
||||||
@@ -46,7 +39,7 @@ default = [ "wasmtime", "db", "cli", "full-node", "trie-memory-tracker" ]
|
|||||||
wasmtime = [ "sc-cli/wasmtime" ]
|
wasmtime = [ "sc-cli/wasmtime" ]
|
||||||
db = [ "service/db" ]
|
db = [ "service/db" ]
|
||||||
cli = [
|
cli = [
|
||||||
"tokio",
|
"structopt",
|
||||||
"sc-cli",
|
"sc-cli",
|
||||||
"sc-service",
|
"sc-service",
|
||||||
"frame-benchmarking-cli",
|
"frame-benchmarking-cli",
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
//! Polkadot CLI library.
|
//! Polkadot CLI library.
|
||||||
|
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
#![warn(unused_extern_crates)]
|
|
||||||
|
|
||||||
#[cfg(feature = "browser")]
|
#[cfg(feature = "browser")]
|
||||||
mod browser;
|
mod browser;
|
||||||
|
|||||||
@@ -10,4 +10,4 @@ reed_solomon = { package = "reed-solomon-erasure", version = "4.0.2"}
|
|||||||
codec = { package = "parity-scale-codec", version = "1.3.4", default-features = false, features = ["derive"] }
|
codec = { package = "parity-scale-codec", version = "1.3.4", default-features = false, features = ["derive"] }
|
||||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
trie = { package = "sp-trie", git = "https://github.com/paritytech/substrate", branch = "master" }
|
trie = { package = "sp-trie", git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
derive_more = "0.15.0"
|
thiserror = "1.0.21"
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ use primitives::v0::{self, Hash as H256, BlakeTwo256, HashT};
|
|||||||
use primitives::v1;
|
use primitives::v1;
|
||||||
use sp_core::Blake2Hasher;
|
use sp_core::Blake2Hasher;
|
||||||
use trie::{EMPTY_PREFIX, MemoryDB, Trie, TrieMut, trie_types::{TrieDBMut, TrieDB}};
|
use trie::{EMPTY_PREFIX, MemoryDB, Trie, TrieMut, trie_types::{TrieDBMut, TrieDB}};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
use self::wrapped_shard::WrappedShard;
|
use self::wrapped_shard::WrappedShard;
|
||||||
|
|
||||||
@@ -39,35 +40,43 @@ mod wrapped_shard;
|
|||||||
const MAX_VALIDATORS: usize = <galois_16::Field as reed_solomon::Field>::ORDER;
|
const MAX_VALIDATORS: usize = <galois_16::Field as reed_solomon::Field>::ORDER;
|
||||||
|
|
||||||
/// Errors in erasure coding.
|
/// Errors in erasure coding.
|
||||||
#[derive(Debug, Clone, PartialEq, derive_more::Display)]
|
#[derive(Debug, Clone, PartialEq, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Returned when there are too many validators.
|
/// Returned when there are too many validators.
|
||||||
|
#[error("There are too many validators")]
|
||||||
TooManyValidators,
|
TooManyValidators,
|
||||||
/// Cannot encode something for no validators
|
/// Cannot encode something for no validators
|
||||||
|
#[error("Validator set is empty")]
|
||||||
EmptyValidators,
|
EmptyValidators,
|
||||||
/// Cannot reconstruct: wrong number of validators.
|
/// Cannot reconstruct: wrong number of validators.
|
||||||
|
#[error("Validator count mismatches between encoding and decoding")]
|
||||||
WrongValidatorCount,
|
WrongValidatorCount,
|
||||||
/// Not enough chunks present.
|
/// Not enough chunks present.
|
||||||
|
#[error("Not enough chunks to reconstruct message")]
|
||||||
NotEnoughChunks,
|
NotEnoughChunks,
|
||||||
/// Too many chunks present.
|
/// Too many chunks present.
|
||||||
|
#[error("Too many chunks present")]
|
||||||
TooManyChunks,
|
TooManyChunks,
|
||||||
/// Chunks not of uniform length or the chunks are empty.
|
/// Chunks not of uniform length or the chunks are empty.
|
||||||
|
#[error("Chunks are not unform, mismatch in length or are zero sized")]
|
||||||
NonUniformChunks,
|
NonUniformChunks,
|
||||||
/// An uneven byte-length of a shard is not valid for GF(2^16) encoding.
|
/// An uneven byte-length of a shard is not valid for GF(2^16) encoding.
|
||||||
|
#[error("Uneven length is not valid for field GF(2^16)")]
|
||||||
UnevenLength,
|
UnevenLength,
|
||||||
/// Chunk index out of bounds.
|
/// Chunk index out of bounds.
|
||||||
#[display(fmt = "Chunk is out of bounds: {} {}", _0, _1)]
|
#[error("Chunk is out of bounds: {chunk_index} not included in 0..{n_validators}")]
|
||||||
ChunkIndexOutOfBounds(usize, usize),
|
ChunkIndexOutOfBounds{ chunk_index: usize, n_validators: usize },
|
||||||
/// Bad payload in reconstructed bytes.
|
/// Bad payload in reconstructed bytes.
|
||||||
|
#[error("Reconstructed payload invalid")]
|
||||||
BadPayload,
|
BadPayload,
|
||||||
/// Invalid branch proof.
|
/// Invalid branch proof.
|
||||||
|
#[error("Invalid branch proof")]
|
||||||
InvalidBranchProof,
|
InvalidBranchProof,
|
||||||
/// Branch out of bounds.
|
/// Branch out of bounds.
|
||||||
|
#[error("Branch is out of bounds")]
|
||||||
BranchOutOfBounds,
|
BranchOutOfBounds,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for Error { }
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
struct CodeParams {
|
struct CodeParams {
|
||||||
data_shards: usize,
|
data_shards: usize,
|
||||||
@@ -206,7 +215,7 @@ fn reconstruct<'a, I: 'a, T: Decode>(n_validators: usize, chunks: I) -> Result<T
|
|||||||
let mut shard_len = None;
|
let mut shard_len = None;
|
||||||
for (chunk_data, chunk_idx) in chunks.into_iter().take(n_validators) {
|
for (chunk_data, chunk_idx) in chunks.into_iter().take(n_validators) {
|
||||||
if chunk_idx >= n_validators {
|
if chunk_idx >= n_validators {
|
||||||
return Err(Error::ChunkIndexOutOfBounds(chunk_idx, n_validators));
|
return Err(Error::ChunkIndexOutOfBounds{ chunk_index: chunk_idx, n_validators });
|
||||||
}
|
}
|
||||||
|
|
||||||
let shard_len = shard_len.get_or_insert_with(|| chunk_data.len());
|
let shard_len = shard_len.get_or_insert_with(|| chunk_data.len());
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
derive_more = "0.99.9"
|
|
||||||
futures = "0.3.5"
|
futures = "0.3.5"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
polkadot-erasure-coding = { path = "../../erasure-coding" }
|
polkadot-erasure-coding = { path = "../../erasure-coding" }
|
||||||
@@ -14,6 +13,7 @@ polkadot-node-subsystem = { path = "../subsystem" }
|
|||||||
polkadot-node-subsystem-util = { path = "../subsystem-util" }
|
polkadot-node-subsystem-util = { path = "../subsystem-util" }
|
||||||
polkadot-primitives = { path = "../../primitives" }
|
polkadot-primitives = { path = "../../primitives" }
|
||||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
thiserror = "1.0.21"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" }
|
polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" }
|
||||||
|
|||||||
@@ -14,19 +14,20 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, derive_more::From)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Subsystem(polkadot_node_subsystem::SubsystemError),
|
Subsystem(#[from] polkadot_node_subsystem::SubsystemError),
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
OneshotRecv(futures::channel::oneshot::Canceled),
|
OneshotRecv(#[from] futures::channel::oneshot::Canceled),
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Runtime(polkadot_node_subsystem::errors::RuntimeApiError),
|
Runtime(#[from] polkadot_node_subsystem::errors::RuntimeApiError),
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Util(polkadot_node_subsystem_util::Error),
|
Util(#[from] polkadot_node_subsystem_util::Error),
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Erasure(polkadot_erasure_coding::Error),
|
Erasure(#[from] polkadot_erasure_coding::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
derive_more = "0.99.9"
|
|
||||||
futures = "0.3.5"
|
futures = "0.3.5"
|
||||||
futures-timer = "3.0.2"
|
futures-timer = "3.0.2"
|
||||||
kvdb = "0.7.0"
|
kvdb = "0.7.0"
|
||||||
kvdb-rocksdb = "0.9.1"
|
kvdb-rocksdb = "0.9.1"
|
||||||
log = "0.4.8"
|
log = "0.4.11"
|
||||||
|
thiserror = "1.0.21"
|
||||||
|
|
||||||
codec = { package = "parity-scale-codec", version = "1.3.1", features = ["derive"] }
|
codec = { package = "parity-scale-codec", version = "1.3.1", features = ["derive"] }
|
||||||
erasure = { package = "polkadot-erasure-coding", path = "../../../erasure-coding" }
|
erasure = { package = "polkadot-erasure-coding", path = "../../../erasure-coding" }
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ use polkadot_node_subsystem_util::metrics::{self, prometheus};
|
|||||||
use polkadot_subsystem::messages::{
|
use polkadot_subsystem::messages::{
|
||||||
AllMessages, AvailabilityStoreMessage, ChainApiMessage, RuntimeApiMessage, RuntimeApiRequest,
|
AllMessages, AvailabilityStoreMessage, ChainApiMessage, RuntimeApiMessage, RuntimeApiRequest,
|
||||||
};
|
};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
const LOG_TARGET: &str = "availability";
|
const LOG_TARGET: &str = "availability";
|
||||||
|
|
||||||
@@ -53,22 +54,22 @@ mod columns {
|
|||||||
pub const NUM_COLUMNS: u32 = 2;
|
pub const NUM_COLUMNS: u32 = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, derive_more::From)]
|
#[derive(Debug, Error)]
|
||||||
enum Error {
|
enum Error {
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Chain(ChainApiError),
|
RuntimeAPI(#[from] RuntimeApiError),
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Erasure(erasure::Error),
|
ChainAPI(#[from] ChainApiError),
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Io(io::Error),
|
Erasure(#[from] erasure::Error),
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Oneshot(oneshot::Canceled),
|
Io(#[from] io::Error),
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Runtime(RuntimeApiError),
|
Oneshot(#[from] oneshot::Canceled),
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Subsystem(SubsystemError),
|
Subsystem(#[from] SubsystemError),
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Time(SystemTimeError),
|
Time(#[from] SystemTimeError),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper type for delays.
|
/// A wrapper type for delays.
|
||||||
|
|||||||
@@ -6,19 +6,16 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "0.3.5"
|
futures = "0.3.5"
|
||||||
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|
||||||
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|
||||||
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|
||||||
polkadot-primitives = { path = "../../../primitives" }
|
polkadot-primitives = { path = "../../../primitives" }
|
||||||
polkadot-node-primitives = { path = "../../primitives" }
|
polkadot-node-primitives = { path = "../../primitives" }
|
||||||
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
|
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
|
||||||
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
||||||
erasure-coding = { package = "polkadot-erasure-coding", path = "../../../erasure-coding" }
|
erasure-coding = { package = "polkadot-erasure-coding", path = "../../../erasure-coding" }
|
||||||
statement-table = { package = "polkadot-statement-table", path = "../../../statement-table" }
|
statement-table = { package = "polkadot-statement-table", path = "../../../statement-table" }
|
||||||
derive_more = "0.99.9"
|
|
||||||
bitvec = { version = "0.17.4", default-features = false, features = ["alloc"] }
|
bitvec = { version = "0.17.4", default-features = false, features = ["alloc"] }
|
||||||
log = "0.4.8"
|
log = "0.4.11"
|
||||||
|
thiserror = "1.0.21"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
//! Implements a `CandidateBackingSubsystem`.
|
//! Implements a `CandidateBackingSubsystem`.
|
||||||
|
|
||||||
|
#![deny(unused_crate_dependencies)]
|
||||||
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
@@ -64,22 +66,26 @@ use statement_table::{
|
|||||||
SignedStatement as TableSignedStatement, Summary as TableSummary,
|
SignedStatement as TableSignedStatement, Summary as TableSummary,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, derive_more::From)]
|
#[derive(Debug, Error)]
|
||||||
enum Error {
|
enum Error {
|
||||||
|
#[error("Candidate is not found")]
|
||||||
CandidateNotFound,
|
CandidateNotFound,
|
||||||
|
#[error("Signature is invalid")]
|
||||||
InvalidSignature,
|
InvalidSignature,
|
||||||
StoreFailed,
|
#[error("Failed to send candidates {0:?}")]
|
||||||
#[from]
|
Send(Vec<NewBackedCandidate>),
|
||||||
Erasure(erasure_coding::Error),
|
#[error("Oneshot never resolved")]
|
||||||
#[from]
|
Oneshot(#[from] #[source] oneshot::Canceled),
|
||||||
ValidationFailed(ValidationFailed),
|
#[error("Obtaining erasure chunks failed")]
|
||||||
#[from]
|
ObtainErasureChunks(#[from] #[source] erasure_coding::Error),
|
||||||
Oneshot(oneshot::Canceled),
|
#[error(transparent)]
|
||||||
#[from]
|
ValidationFailed(#[from] ValidationFailed),
|
||||||
Mpsc(mpsc::SendError),
|
#[error(transparent)]
|
||||||
#[from]
|
Mpsc(#[from] mpsc::SendError),
|
||||||
UtilError(util::Error),
|
#[error(transparent)]
|
||||||
|
UtilError(#[from] util::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Holds all data needed for candidate backing job operation.
|
/// Holds all data needed for candidate backing job operation.
|
||||||
@@ -468,7 +474,7 @@ impl CandidateBackingJob {
|
|||||||
CandidateBackingMessage::GetBackedCandidates(_, tx) => {
|
CandidateBackingMessage::GetBackedCandidates(_, tx) => {
|
||||||
let backed = self.get_backed();
|
let backed = self.get_backed();
|
||||||
|
|
||||||
tx.send(backed).map_err(|_| oneshot::Canceled)?;
|
tx.send(backed).map_err(|data| Error::Send(data))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -640,7 +646,7 @@ impl CandidateBackingJob {
|
|||||||
)
|
)
|
||||||
).await?;
|
).await?;
|
||||||
|
|
||||||
rx.await?.map_err(|_| Error::StoreFailed)?;
|
let _ = rx.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitvec = "0.17.4"
|
bitvec = "0.17.4"
|
||||||
derive_more = "0.99.9"
|
|
||||||
futures = "0.3.5"
|
futures = "0.3.5"
|
||||||
log = "0.4.8"
|
log = "0.4.11"
|
||||||
polkadot-primitives = { path = "../../../primitives" }
|
polkadot-primitives = { path = "../../../primitives" }
|
||||||
polkadot-node-subsystem = { path = "../../subsystem" }
|
polkadot-node-subsystem = { path = "../../subsystem" }
|
||||||
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
||||||
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
wasm-timer = "0.2.4"
|
wasm-timer = "0.2.4"
|
||||||
|
thiserror = "1.0.21"
|
||||||
|
|||||||
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
//! The bitfield signing subsystem produces `SignedAvailabilityBitfield`s once per block.
|
//! The bitfield signing subsystem produces `SignedAvailabilityBitfield`s once per block.
|
||||||
|
|
||||||
|
#![deny(unused_crate_dependencies, unused_results)]
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
use bitvec::bitvec;
|
use bitvec::bitvec;
|
||||||
use futures::{
|
use futures::{
|
||||||
channel::{mpsc, oneshot},
|
channel::{mpsc, oneshot},
|
||||||
@@ -37,6 +40,7 @@ use polkadot_node_subsystem_util::{
|
|||||||
use polkadot_primitives::v1::{AvailabilityBitfield, CoreState, Hash, ValidatorIndex};
|
use polkadot_primitives::v1::{AvailabilityBitfield, CoreState, Hash, ValidatorIndex};
|
||||||
use std::{convert::TryFrom, pin::Pin, time::Duration};
|
use std::{convert::TryFrom, pin::Pin, time::Duration};
|
||||||
use wasm_timer::{Delay, Instant};
|
use wasm_timer::{Delay, Instant};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
/// Delay between starting a bitfield signing job and its attempting to create a bitfield.
|
/// Delay between starting a bitfield signing job and its attempting to create a bitfield.
|
||||||
const JOB_DELAY: Duration = Duration::from_millis(1500);
|
const JOB_DELAY: Duration = Duration::from_millis(1500);
|
||||||
@@ -45,6 +49,7 @@ const JOB_DELAY: Duration = Duration::from_millis(1500);
|
|||||||
pub struct BitfieldSigningJob;
|
pub struct BitfieldSigningJob;
|
||||||
|
|
||||||
/// Messages which a `BitfieldSigningJob` is prepared to receive.
|
/// Messages which a `BitfieldSigningJob` is prepared to receive.
|
||||||
|
#[allow(missing_docs)]
|
||||||
pub enum ToJob {
|
pub enum ToJob {
|
||||||
BitfieldSigning(BitfieldSigningMessage),
|
BitfieldSigning(BitfieldSigningMessage),
|
||||||
Stop,
|
Stop,
|
||||||
@@ -79,6 +84,7 @@ impl From<BitfieldSigningMessage> for ToJob {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Messages which may be sent from a `BitfieldSigningJob`.
|
/// Messages which may be sent from a `BitfieldSigningJob`.
|
||||||
|
#[allow(missing_docs)]
|
||||||
pub enum FromJob {
|
pub enum FromJob {
|
||||||
AvailabilityStore(AvailabilityStoreMessage),
|
AvailabilityStore(AvailabilityStoreMessage),
|
||||||
BitfieldDistribution(BitfieldDistributionMessage),
|
BitfieldDistribution(BitfieldDistributionMessage),
|
||||||
@@ -112,28 +118,28 @@ impl TryFrom<AllMessages> for FromJob {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Errors we may encounter in the course of executing the `BitfieldSigningSubsystem`.
|
/// Errors we may encounter in the course of executing the `BitfieldSigningSubsystem`.
|
||||||
#[derive(Debug, derive_more::From)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// error propagated from the utility subsystem
|
/// error propagated from the utility subsystem
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Util(util::Error),
|
Util(#[from] util::Error),
|
||||||
/// io error
|
/// io error
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Io(std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
/// a one shot channel was canceled
|
/// a one shot channel was canceled
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Oneshot(oneshot::Canceled),
|
Oneshot(#[from] oneshot::Canceled),
|
||||||
/// a mspc channel failed to send
|
/// a mspc channel failed to send
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
MpscSend(mpsc::SendError),
|
MpscSend(#[from] mpsc::SendError),
|
||||||
/// several errors collected into one
|
/// several errors collected into one
|
||||||
#[from]
|
#[error("Multiple errours occured: {0:?}")]
|
||||||
Multiple(Vec<Error>),
|
Multiple(Vec<Error>),
|
||||||
/// the runtime API failed to return what we wanted
|
/// the runtime API failed to return what we wanted
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Runtime(RuntimeApiError),
|
Runtime(#[from] RuntimeApiError),
|
||||||
/// the keystore failed to process signing request
|
/// the keystore failed to process signing request
|
||||||
#[from]
|
#[error("Keystore failed: {0:?}")]
|
||||||
Keystore(KeystoreError),
|
Keystore(KeystoreError),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,7 +258,7 @@ async fn construct_availability_bitfield(
|
|||||||
if errs.is_empty() {
|
if errs.is_empty() {
|
||||||
Ok(out.into_inner().into())
|
Ok(out.into_inner().into())
|
||||||
} else {
|
} else {
|
||||||
Err(errs.into())
|
Err(Error::Multiple(errs.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
derive_more = "0.99.9"
|
|
||||||
futures = "0.3.5"
|
futures = "0.3.5"
|
||||||
log = "0.4.8"
|
log = "0.4.11"
|
||||||
|
thiserror = "1.0.21"
|
||||||
polkadot-primitives = { path = "../../../primitives" }
|
polkadot-primitives = { path = "../../../primitives" }
|
||||||
polkadot-node-primitives = { path = "../../primitives" }
|
polkadot-node-primitives = { path = "../../primitives" }
|
||||||
polkadot-node-subsystem = { path = "../../subsystem" }
|
polkadot-node-subsystem = { path = "../../subsystem" }
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
//! The provisioner is responsible for assembling a relay chain block
|
//! The provisioner is responsible for assembling a relay chain block
|
||||||
//! from a set of available parachain candidates of its choice.
|
//! from a set of available parachain candidates of its choice.
|
||||||
|
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs, unused_crate_dependencies, unused_results)]
|
||||||
|
|
||||||
use futures::{
|
use futures::{
|
||||||
channel::{mpsc, oneshot},
|
channel::{mpsc, oneshot},
|
||||||
@@ -39,6 +39,7 @@ use polkadot_primitives::v1::{
|
|||||||
CandidateDescriptor, CandidateReceipt, CollatorId, Hash, Id as ParaId, PoV,
|
CandidateDescriptor, CandidateReceipt, CollatorId, Hash, Id as ParaId, PoV,
|
||||||
};
|
};
|
||||||
use std::{convert::TryFrom, pin::Pin, sync::Arc};
|
use std::{convert::TryFrom, pin::Pin, sync::Arc};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
const TARGET: &'static str = "candidate_selection";
|
const TARGET: &'static str = "candidate_selection";
|
||||||
|
|
||||||
@@ -116,18 +117,18 @@ impl TryFrom<AllMessages> for FromJob {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, derive_more::From)]
|
#[derive(Debug, Error)]
|
||||||
enum Error {
|
enum Error {
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Sending(mpsc::SendError),
|
Sending(#[from] mpsc::SendError),
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Util(util::Error),
|
Util(#[from] util::Error),
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
OneshotRecv(oneshot::Canceled),
|
OneshotRecv(#[from] oneshot::Canceled),
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
ChainApi(ChainApiError),
|
ChainApi(#[from] ChainApiError),
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Runtime(RuntimeApiError),
|
Runtime(#[from] RuntimeApiError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JobTrait for CandidateSelectionJob {
|
impl JobTrait for CandidateSelectionJob {
|
||||||
@@ -149,14 +150,13 @@ impl JobTrait for CandidateSelectionJob {
|
|||||||
receiver: mpsc::Receiver<ToJob>,
|
receiver: mpsc::Receiver<ToJob>,
|
||||||
sender: mpsc::Sender<FromJob>,
|
sender: mpsc::Sender<FromJob>,
|
||||||
) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send>> {
|
) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send>> {
|
||||||
async move {
|
Box::pin(async move {
|
||||||
let job = CandidateSelectionJob::new(metrics, sender, receiver);
|
let job = CandidateSelectionJob::new(metrics, sender, receiver);
|
||||||
|
|
||||||
// it isn't necessary to break run_loop into its own function,
|
// it isn't necessary to break run_loop into its own function,
|
||||||
// but it's convenient to separate the concerns in this way
|
// but it's convenient to separate the concerns in this way
|
||||||
job.run_loop().await
|
job.run_loop().await
|
||||||
}
|
})
|
||||||
.boxed()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,9 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
derive_more = "0.99.9"
|
|
||||||
futures = "0.3.5"
|
futures = "0.3.5"
|
||||||
log = "0.4.8"
|
log = "0.4.11"
|
||||||
|
|
||||||
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|
||||||
sp-core = { package = "sp-core", git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-core = { package = "sp-core", git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
parity-scale-codec = { version = "1.3.0", default-features = false, features = ["bit-vec", "derive"] }
|
parity-scale-codec = { version = "1.3.0", default-features = false, features = ["bit-vec", "derive"] }
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,11 @@
|
|||||||
//! according to a validation function. This delegates validation to an underlying
|
//! according to a validation function. This delegates validation to an underlying
|
||||||
//! pool of processes used for execution of the Wasm.
|
//! pool of processes used for execution of the Wasm.
|
||||||
|
|
||||||
|
#![deny(unused_crate_dependencies, unused_results)]
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
use polkadot_subsystem::{
|
use polkadot_subsystem::{
|
||||||
Subsystem, SubsystemContext, SpawnedSubsystem, SubsystemResult,
|
Subsystem, SubsystemContext, SpawnedSubsystem, SubsystemResult, SubsystemError,
|
||||||
FromOverseer, OverseerSignal,
|
FromOverseer, OverseerSignal,
|
||||||
messages::{
|
messages::{
|
||||||
AllMessages, CandidateValidationMessage, RuntimeApiMessage,
|
AllMessages, CandidateValidationMessage, RuntimeApiMessage,
|
||||||
@@ -116,9 +119,13 @@ impl<S, C> Subsystem<C> for CandidateValidationSubsystem<S> where
|
|||||||
S: SpawnNamed + Clone + 'static,
|
S: SpawnNamed + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn start(self, ctx: C) -> SpawnedSubsystem {
|
fn start(self, ctx: C) -> SpawnedSubsystem {
|
||||||
|
let future = run(ctx, self.spawn, self.metrics)
|
||||||
|
.map_err(|e| SubsystemError::with_origin("candidate-validation", e))
|
||||||
|
.map(|_| ())
|
||||||
|
.boxed();
|
||||||
SpawnedSubsystem {
|
SpawnedSubsystem {
|
||||||
name: "candidate-validation-subsystem",
|
name: "candidate-validation-subsystem",
|
||||||
future: run(ctx, self.spawn, self.metrics).map(|_| ()).boxed(),
|
future,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,9 +27,12 @@
|
|||||||
//! * Last finalized block number
|
//! * Last finalized block number
|
||||||
//! * Ancestors
|
//! * Ancestors
|
||||||
|
|
||||||
|
#![deny(unused_crate_dependencies, unused_results)]
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
use polkadot_subsystem::{
|
use polkadot_subsystem::{
|
||||||
FromOverseer, OverseerSignal,
|
FromOverseer, OverseerSignal,
|
||||||
SpawnedSubsystem, Subsystem, SubsystemResult, SubsystemContext,
|
SpawnedSubsystem, Subsystem, SubsystemResult, SubsystemError, SubsystemContext,
|
||||||
messages::ChainApiMessage,
|
messages::ChainApiMessage,
|
||||||
};
|
};
|
||||||
use polkadot_node_subsystem_util::{
|
use polkadot_node_subsystem_util::{
|
||||||
@@ -61,8 +64,12 @@ impl<Client, Context> Subsystem<Context> for ChainApiSubsystem<Client> where
|
|||||||
Context: SubsystemContext<Message = ChainApiMessage>
|
Context: SubsystemContext<Message = ChainApiMessage>
|
||||||
{
|
{
|
||||||
fn start(self, ctx: Context) -> SpawnedSubsystem {
|
fn start(self, ctx: Context) -> SpawnedSubsystem {
|
||||||
|
let future = run(ctx, self)
|
||||||
|
.map_err(|e| SubsystemError::with_origin("chain-api", e))
|
||||||
|
.map(|_| ())
|
||||||
|
.boxed();
|
||||||
SpawnedSubsystem {
|
SpawnedSubsystem {
|
||||||
future: run(ctx, self).map(|_| ()).boxed(),
|
future,
|
||||||
name: "chain-api-subsystem",
|
name: "chain-api-subsystem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,7 +119,10 @@ where
|
|||||||
let maybe_header = subsystem.client.header(BlockId::Hash(hash));
|
let maybe_header = subsystem.client.header(BlockId::Hash(hash));
|
||||||
match maybe_header {
|
match maybe_header {
|
||||||
// propagate the error
|
// propagate the error
|
||||||
Err(e) => Some(Err(e.to_string().into())),
|
Err(e) => {
|
||||||
|
let e = e.to_string().into();
|
||||||
|
Some(Err(e))
|
||||||
|
},
|
||||||
// fewer than `k` ancestors are available
|
// fewer than `k` ancestors are available
|
||||||
Ok(None) => None,
|
Ok(None) => None,
|
||||||
Ok(Some(header)) => {
|
Ok(Some(header)) => {
|
||||||
|
|||||||
@@ -6,16 +6,13 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "0.3.4"
|
futures = "0.3.4"
|
||||||
futures-timer = "3.0.1"
|
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
parity-scale-codec = "1.3.4"
|
|
||||||
polkadot-node-subsystem = { path = "../../subsystem" }
|
polkadot-node-subsystem = { path = "../../subsystem" }
|
||||||
polkadot-overseer = { path = "../../overseer" }
|
polkadot-overseer = { path = "../../overseer" }
|
||||||
polkadot-primitives = { path = "../../../primitives" }
|
polkadot-primitives = { path = "../../../primitives" }
|
||||||
sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sc-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sc-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|
||||||
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
@@ -23,5 +20,4 @@ sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|||||||
sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
tokio-executor = { version = "0.2.0-alpha.6", features = ["blocking"] }
|
|
||||||
wasm-timer = "0.2.4"
|
wasm-timer = "0.2.4"
|
||||||
|
|||||||
@@ -1,3 +1,23 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! The proposer proposes new blocks to include
|
||||||
|
|
||||||
|
#![deny(unused_crate_dependencies, unused_results)]
|
||||||
|
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use futures::select;
|
use futures::select;
|
||||||
use polkadot_node_subsystem::{messages::{AllMessages, ProvisionerInherentData, ProvisionerMessage}, SubsystemError};
|
use polkadot_node_subsystem::{messages::{AllMessages, ProvisionerInherentData, ProvisionerMessage}, SubsystemError};
|
||||||
@@ -123,7 +143,7 @@ where
|
|||||||
let (sender, receiver) = futures::channel::oneshot::channel();
|
let (sender, receiver) = futures::channel::oneshot::channel();
|
||||||
|
|
||||||
overseer.wait_for_activation(parent_header_hash, sender).await?;
|
overseer.wait_for_activation(parent_header_hash, sender).await?;
|
||||||
receiver.await.map_err(Error::ClosedChannelFromProvisioner)?;
|
receiver.await.map_err(Error::ClosedChannelFromProvisioner)??;
|
||||||
|
|
||||||
let (sender, receiver) = futures::channel::oneshot::channel();
|
let (sender, receiver) = futures::channel::oneshot::channel();
|
||||||
// strictly speaking, we don't _have_ to .await this send_msg before opening the
|
// strictly speaking, we don't _have_ to .await this send_msg before opening the
|
||||||
@@ -206,7 +226,7 @@ where
|
|||||||
|
|
||||||
// It would have been more ergonomic to use thiserror to derive the
|
// It would have been more ergonomic to use thiserror to derive the
|
||||||
// From implementations, Display, and std::error::Error, but unfortunately
|
// From implementations, Display, and std::error::Error, but unfortunately
|
||||||
// two of the wrapped errors (sp_inherents::Error, SubsystemError) also
|
// one of the wrapped errors (sp_inherents::Error) also
|
||||||
// don't impl std::error::Error, which breaks the thiserror derive.
|
// don't impl std::error::Error, which breaks the thiserror derive.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
@@ -261,6 +281,7 @@ impl std::error::Error for Error {
|
|||||||
Self::Consensus(err) => Some(err),
|
Self::Consensus(err) => Some(err),
|
||||||
Self::Blockchain(err) => Some(err),
|
Self::Blockchain(err) => Some(err),
|
||||||
Self::ClosedChannelFromProvisioner(err) => Some(err),
|
Self::ClosedChannelFromProvisioner(err) => Some(err),
|
||||||
|
Self::Subsystem(err) => Some(err),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,16 +6,14 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitvec = { version = "0.17.4", default-features = false, features = ["alloc"] }
|
bitvec = { version = "0.17.4", default-features = false, features = ["alloc"] }
|
||||||
derive_more = "0.99.9"
|
|
||||||
futures = "0.3.5"
|
futures = "0.3.5"
|
||||||
log = "0.4.8"
|
log = "0.4.11"
|
||||||
|
thiserror = "1.0.21"
|
||||||
polkadot-primitives = { path = "../../../primitives" }
|
polkadot-primitives = { path = "../../../primitives" }
|
||||||
polkadot-node-subsystem = { path = "../../subsystem" }
|
polkadot-node-subsystem = { path = "../../subsystem" }
|
||||||
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
lazy_static = "1.4"
|
|
||||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|
||||||
sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
//! The provisioner is responsible for assembling a relay chain block
|
//! The provisioner is responsible for assembling a relay chain block
|
||||||
//! from a set of available parachain candidates of its choice.
|
//! from a set of available parachain candidates of its choice.
|
||||||
|
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs, unused_crate_dependencies, unused_results)]
|
||||||
|
|
||||||
use bitvec::vec::BitVec;
|
use bitvec::vec::BitVec;
|
||||||
use futures::{
|
use futures::{
|
||||||
@@ -42,6 +42,7 @@ use polkadot_primitives::v1::{
|
|||||||
SignedAvailabilityBitfield,
|
SignedAvailabilityBitfield,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, convert::TryFrom, pin::Pin};
|
use std::{collections::HashMap, convert::TryFrom, pin::Pin};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
struct ProvisioningJob {
|
struct ProvisioningJob {
|
||||||
relay_parent: Hash,
|
relay_parent: Hash,
|
||||||
@@ -115,19 +116,25 @@ impl TryFrom<AllMessages> for FromJob {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, derive_more::From)]
|
#[derive(Debug, Error)]
|
||||||
enum Error {
|
enum Error {
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Sending(mpsc::SendError),
|
Util(#[from] util::Error),
|
||||||
#[from]
|
|
||||||
Util(util::Error),
|
#[error(transparent)]
|
||||||
#[from]
|
OneshotRecv(#[from] oneshot::Canceled),
|
||||||
OneshotRecv(oneshot::Canceled),
|
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
ChainApi(ChainApiError),
|
ChainApi(#[from] ChainApiError),
|
||||||
#[from]
|
|
||||||
Runtime(RuntimeApiError),
|
#[error(transparent)]
|
||||||
OneshotSend,
|
Runtime(#[from] RuntimeApiError),
|
||||||
|
|
||||||
|
#[error("Failed to send message to ChainAPI")]
|
||||||
|
ChainApiMessageSend(#[source] mpsc::SendError),
|
||||||
|
|
||||||
|
#[error("Failed to send return message with Inherents")]
|
||||||
|
InherentDataReturnChannel,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JobTrait for ProvisioningJob {
|
impl JobTrait for ProvisioningJob {
|
||||||
@@ -230,7 +237,7 @@ impl ProvisioningJob {
|
|||||||
let tail = bad_indices[bad_indices.len() - 1];
|
let tail = bad_indices[bad_indices.len() - 1];
|
||||||
let retain = *idx != tail;
|
let retain = *idx != tail;
|
||||||
if *idx >= tail {
|
if *idx >= tail {
|
||||||
bad_indices.pop();
|
let _ = bad_indices.pop();
|
||||||
}
|
}
|
||||||
retain
|
retain
|
||||||
})
|
})
|
||||||
@@ -299,7 +306,7 @@ async fn send_inherent_data(
|
|||||||
|
|
||||||
return_sender
|
return_sender
|
||||||
.send((bitfields, candidates))
|
.send((bitfields, candidates))
|
||||||
.map_err(|_| Error::OneshotSend)?;
|
.map_err(|_data| Error::InherentDataReturnChannel)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,7 +430,7 @@ async fn get_block_number_under_construction(
|
|||||||
tx,
|
tx,
|
||||||
)))
|
)))
|
||||||
.await
|
.await
|
||||||
.map_err(|_| Error::OneshotSend)?;
|
.map_err(|e| Error::ChainApiMessageSend(e))?;
|
||||||
match rx.await? {
|
match rx.await? {
|
||||||
Ok(Some(n)) => Ok(n + 1),
|
Ok(Some(n)) => Ok(n + 1),
|
||||||
Ok(None) => Ok(0),
|
Ok(None) => Ok(0),
|
||||||
@@ -504,382 +511,4 @@ impl metrics::Metrics for Metrics {
|
|||||||
delegated_subsystem!(ProvisioningJob((), Metrics) <- ToJob as ProvisioningSubsystem);
|
delegated_subsystem!(ProvisioningJob((), Metrics) <- ToJob as ProvisioningSubsystem);
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests;
|
||||||
use super::*;
|
|
||||||
use bitvec::bitvec;
|
|
||||||
use polkadot_primitives::v1::{OccupiedCore, ScheduledCore};
|
|
||||||
|
|
||||||
pub fn occupied_core(para_id: u32) -> CoreState {
|
|
||||||
CoreState::Occupied(OccupiedCore {
|
|
||||||
para_id: para_id.into(),
|
|
||||||
group_responsible: para_id.into(),
|
|
||||||
next_up_on_available: None,
|
|
||||||
occupied_since: 100_u32,
|
|
||||||
time_out_at: 200_u32,
|
|
||||||
next_up_on_time_out: None,
|
|
||||||
availability: default_bitvec(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build_occupied_core<Builder>(para_id: u32, builder: Builder) -> CoreState
|
|
||||||
where
|
|
||||||
Builder: FnOnce(&mut OccupiedCore),
|
|
||||||
{
|
|
||||||
let mut core = match occupied_core(para_id) {
|
|
||||||
CoreState::Occupied(core) => core,
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
builder(&mut core);
|
|
||||||
|
|
||||||
CoreState::Occupied(core)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn default_bitvec() -> CoreAvailability {
|
|
||||||
bitvec![bitvec::order::Lsb0, u8; 0; 32]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn scheduled_core(id: u32) -> ScheduledCore {
|
|
||||||
ScheduledCore {
|
|
||||||
para_id: id.into(),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod select_availability_bitfields {
|
|
||||||
use super::super::*;
|
|
||||||
use super::{default_bitvec, occupied_core};
|
|
||||||
use futures::executor::block_on;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use polkadot_primitives::v1::{SigningContext, ValidatorIndex, ValidatorId};
|
|
||||||
use sp_application_crypto::AppKey;
|
|
||||||
use sp_keystore::{CryptoStore, SyncCryptoStorePtr};
|
|
||||||
use sc_keystore::LocalKeystore;
|
|
||||||
|
|
||||||
async fn signed_bitfield(
|
|
||||||
keystore: &SyncCryptoStorePtr,
|
|
||||||
field: CoreAvailability,
|
|
||||||
validator_idx: ValidatorIndex,
|
|
||||||
) -> SignedAvailabilityBitfield {
|
|
||||||
let public = CryptoStore::sr25519_generate_new(&**keystore, ValidatorId::ID, None)
|
|
||||||
.await
|
|
||||||
.expect("generated sr25519 key");
|
|
||||||
SignedAvailabilityBitfield::sign(
|
|
||||||
&keystore,
|
|
||||||
field.into(),
|
|
||||||
&<SigningContext<Hash>>::default(),
|
|
||||||
validator_idx,
|
|
||||||
&public.into(),
|
|
||||||
).await.expect("Should be signed")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn not_more_than_one_per_validator() {
|
|
||||||
// Configure filesystem-based keystore as generating keys without seed
|
|
||||||
// would trigger the key to be generated on the filesystem.
|
|
||||||
let keystore_path = tempfile::tempdir().expect("Creates keystore path");
|
|
||||||
let keystore : SyncCryptoStorePtr = Arc::new(LocalKeystore::open(keystore_path.path(), None)
|
|
||||||
.expect("Creates keystore"));
|
|
||||||
let bitvec = default_bitvec();
|
|
||||||
|
|
||||||
let cores = vec![occupied_core(0), occupied_core(1)];
|
|
||||||
|
|
||||||
// we pass in three bitfields with two validators
|
|
||||||
// this helps us check the postcondition that we get two bitfields back, for which the validators differ
|
|
||||||
let bitfields = vec![
|
|
||||||
block_on(signed_bitfield(&keystore, bitvec.clone(), 0)),
|
|
||||||
block_on(signed_bitfield(&keystore, bitvec.clone(), 1)),
|
|
||||||
block_on(signed_bitfield(&keystore, bitvec, 1)),
|
|
||||||
];
|
|
||||||
|
|
||||||
let mut selected_bitfields = select_availability_bitfields(&cores, &bitfields);
|
|
||||||
selected_bitfields.sort_by_key(|bitfield| bitfield.validator_index());
|
|
||||||
|
|
||||||
assert_eq!(selected_bitfields.len(), 2);
|
|
||||||
assert_eq!(selected_bitfields[0], bitfields[0]);
|
|
||||||
// we don't know which of the (otherwise equal) bitfields will be selected
|
|
||||||
assert!(selected_bitfields[1] == bitfields[1] || selected_bitfields[1] == bitfields[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn each_corresponds_to_an_occupied_core() {
|
|
||||||
// Configure filesystem-based keystore as generating keys without seed
|
|
||||||
// would trigger the key to be generated on the filesystem.
|
|
||||||
let keystore_path = tempfile::tempdir().expect("Creates keystore path");
|
|
||||||
let keystore : SyncCryptoStorePtr = Arc::new(LocalKeystore::open(keystore_path.path(), None)
|
|
||||||
.expect("Creates keystore"));
|
|
||||||
let bitvec = default_bitvec();
|
|
||||||
|
|
||||||
let cores = vec![CoreState::Free, CoreState::Scheduled(Default::default())];
|
|
||||||
|
|
||||||
let bitfields = vec![
|
|
||||||
block_on(signed_bitfield(&keystore, bitvec.clone(), 0)),
|
|
||||||
block_on(signed_bitfield(&keystore, bitvec.clone(), 1)),
|
|
||||||
block_on(signed_bitfield(&keystore, bitvec, 1)),
|
|
||||||
];
|
|
||||||
|
|
||||||
let mut selected_bitfields = select_availability_bitfields(&cores, &bitfields);
|
|
||||||
selected_bitfields.sort_by_key(|bitfield| bitfield.validator_index());
|
|
||||||
|
|
||||||
// bitfields not corresponding to occupied cores are not selected
|
|
||||||
assert!(selected_bitfields.is_empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn more_set_bits_win_conflicts() {
|
|
||||||
// Configure filesystem-based keystore as generating keys without seed
|
|
||||||
// would trigger the key to be generated on the filesystem.
|
|
||||||
let keystore_path = tempfile::tempdir().expect("Creates keystore path");
|
|
||||||
let keystore : SyncCryptoStorePtr = Arc::new(LocalKeystore::open(keystore_path.path(), None)
|
|
||||||
.expect("Creates keystore"));
|
|
||||||
let bitvec_zero = default_bitvec();
|
|
||||||
let bitvec_one = {
|
|
||||||
let mut bitvec = bitvec_zero.clone();
|
|
||||||
bitvec.set(0, true);
|
|
||||||
bitvec
|
|
||||||
};
|
|
||||||
|
|
||||||
let cores = vec![occupied_core(0)];
|
|
||||||
|
|
||||||
let bitfields = vec![
|
|
||||||
block_on(signed_bitfield(&keystore, bitvec_zero, 0)),
|
|
||||||
block_on(signed_bitfield(&keystore, bitvec_one.clone(), 0)),
|
|
||||||
];
|
|
||||||
|
|
||||||
// this test is probablistic: chances are excellent that it does what it claims to.
|
|
||||||
// it cannot fail unless things are broken.
|
|
||||||
// however, there is a (very small) chance that it passes when things are broken.
|
|
||||||
for _ in 0..64 {
|
|
||||||
let selected_bitfields = select_availability_bitfields(&cores, &bitfields);
|
|
||||||
assert_eq!(selected_bitfields.len(), 1);
|
|
||||||
assert_eq!(selected_bitfields[0].payload().0, bitvec_one);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod select_candidates {
|
|
||||||
use futures_timer::Delay;
|
|
||||||
use super::super::*;
|
|
||||||
use super::{build_occupied_core, default_bitvec, occupied_core, scheduled_core};
|
|
||||||
use polkadot_node_subsystem::messages::RuntimeApiRequest::{
|
|
||||||
AvailabilityCores, PersistedValidationData as PersistedValidationDataReq,
|
|
||||||
};
|
|
||||||
use polkadot_primitives::v1::{
|
|
||||||
BlockNumber, CandidateDescriptor, CommittedCandidateReceipt, PersistedValidationData,
|
|
||||||
};
|
|
||||||
use FromJob::{ChainApi, Runtime};
|
|
||||||
|
|
||||||
const BLOCK_UNDER_PRODUCTION: BlockNumber = 128;
|
|
||||||
|
|
||||||
fn test_harness<OverseerFactory, Overseer, TestFactory, Test>(
|
|
||||||
overseer_factory: OverseerFactory,
|
|
||||||
test_factory: TestFactory,
|
|
||||||
) where
|
|
||||||
OverseerFactory: FnOnce(mpsc::Receiver<FromJob>) -> Overseer,
|
|
||||||
Overseer: Future<Output = ()>,
|
|
||||||
TestFactory: FnOnce(mpsc::Sender<FromJob>) -> Test,
|
|
||||||
Test: Future<Output = ()>,
|
|
||||||
{
|
|
||||||
let (tx, rx) = mpsc::channel(64);
|
|
||||||
let overseer = overseer_factory(rx);
|
|
||||||
let test = test_factory(tx);
|
|
||||||
|
|
||||||
futures::pin_mut!(overseer, test);
|
|
||||||
|
|
||||||
futures::executor::block_on(future::select(overseer, test));
|
|
||||||
}
|
|
||||||
|
|
||||||
// For test purposes, we always return this set of availability cores:
|
|
||||||
//
|
|
||||||
// [
|
|
||||||
// 0: Free,
|
|
||||||
// 1: Scheduled(default),
|
|
||||||
// 2: Occupied(no next_up set),
|
|
||||||
// 3: Occupied(next_up_on_available set but not available),
|
|
||||||
// 4: Occupied(next_up_on_available set and available),
|
|
||||||
// 5: Occupied(next_up_on_time_out set but not timeout),
|
|
||||||
// 6: Occupied(next_up_on_time_out set and timeout but available),
|
|
||||||
// 7: Occupied(next_up_on_time_out set and timeout and not available),
|
|
||||||
// 8: Occupied(both next_up set, available),
|
|
||||||
// 9: Occupied(both next_up set, not available, no timeout),
|
|
||||||
// 10: Occupied(both next_up set, not available, timeout),
|
|
||||||
// 11: Occupied(next_up_on_available and available, but different successor para_id)
|
|
||||||
// ]
|
|
||||||
fn mock_availability_cores() -> Vec<CoreState> {
|
|
||||||
use std::ops::Not;
|
|
||||||
use CoreState::{Free, Scheduled};
|
|
||||||
|
|
||||||
vec![
|
|
||||||
// 0: Free,
|
|
||||||
Free,
|
|
||||||
// 1: Scheduled(default),
|
|
||||||
Scheduled(scheduled_core(1)),
|
|
||||||
// 2: Occupied(no next_up set),
|
|
||||||
occupied_core(2),
|
|
||||||
// 3: Occupied(next_up_on_available set but not available),
|
|
||||||
build_occupied_core(3, |core| {
|
|
||||||
core.next_up_on_available = Some(scheduled_core(3));
|
|
||||||
}),
|
|
||||||
// 4: Occupied(next_up_on_available set and available),
|
|
||||||
build_occupied_core(4, |core| {
|
|
||||||
core.next_up_on_available = Some(scheduled_core(4));
|
|
||||||
core.availability = core.availability.clone().not();
|
|
||||||
}),
|
|
||||||
// 5: Occupied(next_up_on_time_out set but not timeout),
|
|
||||||
build_occupied_core(5, |core| {
|
|
||||||
core.next_up_on_time_out = Some(scheduled_core(5));
|
|
||||||
}),
|
|
||||||
// 6: Occupied(next_up_on_time_out set and timeout but available),
|
|
||||||
build_occupied_core(6, |core| {
|
|
||||||
core.next_up_on_time_out = Some(scheduled_core(6));
|
|
||||||
core.time_out_at = BLOCK_UNDER_PRODUCTION;
|
|
||||||
core.availability = core.availability.clone().not();
|
|
||||||
}),
|
|
||||||
// 7: Occupied(next_up_on_time_out set and timeout and not available),
|
|
||||||
build_occupied_core(7, |core| {
|
|
||||||
core.next_up_on_time_out = Some(scheduled_core(7));
|
|
||||||
core.time_out_at = BLOCK_UNDER_PRODUCTION;
|
|
||||||
}),
|
|
||||||
// 8: Occupied(both next_up set, available),
|
|
||||||
build_occupied_core(8, |core| {
|
|
||||||
core.next_up_on_available = Some(scheduled_core(8));
|
|
||||||
core.next_up_on_time_out = Some(scheduled_core(8));
|
|
||||||
core.availability = core.availability.clone().not();
|
|
||||||
}),
|
|
||||||
// 9: Occupied(both next_up set, not available, no timeout),
|
|
||||||
build_occupied_core(9, |core| {
|
|
||||||
core.next_up_on_available = Some(scheduled_core(9));
|
|
||||||
core.next_up_on_time_out = Some(scheduled_core(9));
|
|
||||||
}),
|
|
||||||
// 10: Occupied(both next_up set, not available, timeout),
|
|
||||||
build_occupied_core(10, |core| {
|
|
||||||
core.next_up_on_available = Some(scheduled_core(10));
|
|
||||||
core.next_up_on_time_out = Some(scheduled_core(10));
|
|
||||||
core.time_out_at = BLOCK_UNDER_PRODUCTION;
|
|
||||||
}),
|
|
||||||
// 11: Occupied(next_up_on_available and available, but different successor para_id)
|
|
||||||
build_occupied_core(11, |core| {
|
|
||||||
core.next_up_on_available = Some(scheduled_core(12));
|
|
||||||
core.availability = core.availability.clone().not();
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn mock_overseer(mut receiver: mpsc::Receiver<FromJob>) {
|
|
||||||
use ChainApiMessage::BlockNumber;
|
|
||||||
use RuntimeApiMessage::Request;
|
|
||||||
|
|
||||||
while let Some(from_job) = receiver.next().await {
|
|
||||||
match from_job {
|
|
||||||
ChainApi(BlockNumber(_relay_parent, tx)) => {
|
|
||||||
tx.send(Ok(Some(BLOCK_UNDER_PRODUCTION - 1))).unwrap()
|
|
||||||
}
|
|
||||||
Runtime(Request(
|
|
||||||
_parent_hash,
|
|
||||||
PersistedValidationDataReq(_para_id, _assumption, tx),
|
|
||||||
)) => tx.send(Ok(Some(Default::default()))).unwrap(),
|
|
||||||
Runtime(Request(_parent_hash, AvailabilityCores(tx))) => {
|
|
||||||
tx.send(Ok(mock_availability_cores())).unwrap()
|
|
||||||
}
|
|
||||||
// non-exhaustive matches are fine for testing
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn handles_overseer_failure() {
|
|
||||||
let overseer = |rx: mpsc::Receiver<FromJob>| async move {
|
|
||||||
// drop the receiver so it closes and the sender can't send, then just sleep long enough that
|
|
||||||
// this is almost certainly not the first of the two futures to complete
|
|
||||||
std::mem::drop(rx);
|
|
||||||
Delay::new(std::time::Duration::from_secs(1)).await;
|
|
||||||
};
|
|
||||||
|
|
||||||
let test = |mut tx: mpsc::Sender<FromJob>| async move {
|
|
||||||
// wait so that the overseer can drop the rx before we attempt to send
|
|
||||||
Delay::new(std::time::Duration::from_millis(50)).await;
|
|
||||||
let result = select_candidates(&[], &[], &[], Default::default(), &mut tx).await;
|
|
||||||
println!("{:?}", result);
|
|
||||||
assert!(std::matches!(result, Err(Error::OneshotSend)));
|
|
||||||
};
|
|
||||||
|
|
||||||
test_harness(overseer, test);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn can_succeed() {
|
|
||||||
test_harness(mock_overseer, |mut tx: mpsc::Sender<FromJob>| async move {
|
|
||||||
let result = select_candidates(&[], &[], &[], Default::default(), &mut tx).await;
|
|
||||||
println!("{:?}", result);
|
|
||||||
assert!(result.is_ok());
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// this tests that only the appropriate candidates get selected.
|
|
||||||
// To accomplish this, we supply a candidate list containing one candidate per possible core;
|
|
||||||
// the candidate selection algorithm must filter them to the appropriate set
|
|
||||||
#[test]
|
|
||||||
fn selects_correct_candidates() {
|
|
||||||
let mock_cores = mock_availability_cores();
|
|
||||||
|
|
||||||
let empty_hash = PersistedValidationData::<BlockNumber>::default().hash();
|
|
||||||
|
|
||||||
let candidate_template = BackedCandidate {
|
|
||||||
candidate: CommittedCandidateReceipt {
|
|
||||||
descriptor: CandidateDescriptor {
|
|
||||||
persisted_validation_data_hash: empty_hash,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
validity_votes: Vec::new(),
|
|
||||||
validator_indices: default_bitvec(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let candidates: Vec<_> = std::iter::repeat(candidate_template)
|
|
||||||
.take(mock_cores.len())
|
|
||||||
.enumerate()
|
|
||||||
.map(|(idx, mut candidate)| {
|
|
||||||
candidate.candidate.descriptor.para_id = idx.into();
|
|
||||||
candidate
|
|
||||||
})
|
|
||||||
.cycle()
|
|
||||||
.take(mock_cores.len() * 3)
|
|
||||||
.enumerate()
|
|
||||||
.map(|(idx, mut candidate)| {
|
|
||||||
if idx < mock_cores.len() {
|
|
||||||
// first go-around: use candidates which should work
|
|
||||||
candidate
|
|
||||||
} else if idx < mock_cores.len() * 2 {
|
|
||||||
// for the second repetition of the candidates, give them the wrong hash
|
|
||||||
candidate.candidate.descriptor.persisted_validation_data_hash
|
|
||||||
= Default::default();
|
|
||||||
candidate
|
|
||||||
} else {
|
|
||||||
// third go-around: right hash, wrong para_id
|
|
||||||
candidate.candidate.descriptor.para_id = idx.into();
|
|
||||||
candidate
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// why those particular indices? see the comments on mock_availability_cores()
|
|
||||||
let expected_candidates: Vec<_> = [1, 4, 7, 8, 10]
|
|
||||||
.iter()
|
|
||||||
.map(|&idx| candidates[idx].clone())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
test_harness(mock_overseer, |mut tx: mpsc::Sender<FromJob>| async move {
|
|
||||||
let result =
|
|
||||||
select_candidates(&mock_cores, &[], &candidates, Default::default(), &mut tx)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
if result.is_err() {
|
|
||||||
println!("{:?}", result);
|
|
||||||
}
|
|
||||||
assert_eq!(result.unwrap(), expected_candidates);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,377 @@
|
|||||||
|
use super::*;
|
||||||
|
use bitvec::bitvec;
|
||||||
|
use polkadot_primitives::v1::{OccupiedCore, ScheduledCore};
|
||||||
|
|
||||||
|
pub fn occupied_core(para_id: u32) -> CoreState {
|
||||||
|
CoreState::Occupied(OccupiedCore {
|
||||||
|
para_id: para_id.into(),
|
||||||
|
group_responsible: para_id.into(),
|
||||||
|
next_up_on_available: None,
|
||||||
|
occupied_since: 100_u32,
|
||||||
|
time_out_at: 200_u32,
|
||||||
|
next_up_on_time_out: None,
|
||||||
|
availability: default_bitvec(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_occupied_core<Builder>(para_id: u32, builder: Builder) -> CoreState
|
||||||
|
where
|
||||||
|
Builder: FnOnce(&mut OccupiedCore),
|
||||||
|
{
|
||||||
|
let mut core = match occupied_core(para_id) {
|
||||||
|
CoreState::Occupied(core) => core,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
builder(&mut core);
|
||||||
|
|
||||||
|
CoreState::Occupied(core)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default_bitvec() -> CoreAvailability {
|
||||||
|
bitvec![bitvec::order::Lsb0, u8; 0; 32]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scheduled_core(id: u32) -> ScheduledCore {
|
||||||
|
ScheduledCore {
|
||||||
|
para_id: id.into(),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod select_availability_bitfields {
|
||||||
|
use super::super::*;
|
||||||
|
use super::{default_bitvec, occupied_core};
|
||||||
|
use futures::executor::block_on;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use polkadot_primitives::v1::{SigningContext, ValidatorIndex, ValidatorId};
|
||||||
|
use sp_application_crypto::AppKey;
|
||||||
|
use sp_keystore::{CryptoStore, SyncCryptoStorePtr};
|
||||||
|
use sc_keystore::LocalKeystore;
|
||||||
|
|
||||||
|
async fn signed_bitfield(
|
||||||
|
keystore: &SyncCryptoStorePtr,
|
||||||
|
field: CoreAvailability,
|
||||||
|
validator_idx: ValidatorIndex,
|
||||||
|
) -> SignedAvailabilityBitfield {
|
||||||
|
let public = CryptoStore::sr25519_generate_new(&**keystore, ValidatorId::ID, None)
|
||||||
|
.await
|
||||||
|
.expect("generated sr25519 key");
|
||||||
|
SignedAvailabilityBitfield::sign(
|
||||||
|
&keystore,
|
||||||
|
field.into(),
|
||||||
|
&<SigningContext<Hash>>::default(),
|
||||||
|
validator_idx,
|
||||||
|
&public.into(),
|
||||||
|
).await.expect("Should be signed")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn not_more_than_one_per_validator() {
|
||||||
|
// Configure filesystem-based keystore as generating keys without seed
|
||||||
|
// would trigger the key to be generated on the filesystem.
|
||||||
|
let keystore_path = tempfile::tempdir().expect("Creates keystore path");
|
||||||
|
let keystore : SyncCryptoStorePtr = Arc::new(LocalKeystore::open(keystore_path.path(), None)
|
||||||
|
.expect("Creates keystore"));
|
||||||
|
let bitvec = default_bitvec();
|
||||||
|
|
||||||
|
let cores = vec![occupied_core(0), occupied_core(1)];
|
||||||
|
|
||||||
|
// we pass in three bitfields with two validators
|
||||||
|
// this helps us check the postcondition that we get two bitfields back, for which the validators differ
|
||||||
|
let bitfields = vec![
|
||||||
|
block_on(signed_bitfield(&keystore, bitvec.clone(), 0)),
|
||||||
|
block_on(signed_bitfield(&keystore, bitvec.clone(), 1)),
|
||||||
|
block_on(signed_bitfield(&keystore, bitvec, 1)),
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut selected_bitfields = select_availability_bitfields(&cores, &bitfields);
|
||||||
|
selected_bitfields.sort_by_key(|bitfield| bitfield.validator_index());
|
||||||
|
|
||||||
|
assert_eq!(selected_bitfields.len(), 2);
|
||||||
|
assert_eq!(selected_bitfields[0], bitfields[0]);
|
||||||
|
// we don't know which of the (otherwise equal) bitfields will be selected
|
||||||
|
assert!(selected_bitfields[1] == bitfields[1] || selected_bitfields[1] == bitfields[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn each_corresponds_to_an_occupied_core() {
|
||||||
|
// Configure filesystem-based keystore as generating keys without seed
|
||||||
|
// would trigger the key to be generated on the filesystem.
|
||||||
|
let keystore_path = tempfile::tempdir().expect("Creates keystore path");
|
||||||
|
let keystore : SyncCryptoStorePtr = Arc::new(LocalKeystore::open(keystore_path.path(), None)
|
||||||
|
.expect("Creates keystore"));
|
||||||
|
let bitvec = default_bitvec();
|
||||||
|
|
||||||
|
let cores = vec![CoreState::Free, CoreState::Scheduled(Default::default())];
|
||||||
|
|
||||||
|
let bitfields = vec![
|
||||||
|
block_on(signed_bitfield(&keystore, bitvec.clone(), 0)),
|
||||||
|
block_on(signed_bitfield(&keystore, bitvec.clone(), 1)),
|
||||||
|
block_on(signed_bitfield(&keystore, bitvec, 1)),
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut selected_bitfields = select_availability_bitfields(&cores, &bitfields);
|
||||||
|
selected_bitfields.sort_by_key(|bitfield| bitfield.validator_index());
|
||||||
|
|
||||||
|
// bitfields not corresponding to occupied cores are not selected
|
||||||
|
assert!(selected_bitfields.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn more_set_bits_win_conflicts() {
|
||||||
|
// Configure filesystem-based keystore as generating keys without seed
|
||||||
|
// would trigger the key to be generated on the filesystem.
|
||||||
|
let keystore_path = tempfile::tempdir().expect("Creates keystore path");
|
||||||
|
let keystore : SyncCryptoStorePtr = Arc::new(LocalKeystore::open(keystore_path.path(), None)
|
||||||
|
.expect("Creates keystore"));
|
||||||
|
let bitvec_zero = default_bitvec();
|
||||||
|
let bitvec_one = {
|
||||||
|
let mut bitvec = bitvec_zero.clone();
|
||||||
|
bitvec.set(0, true);
|
||||||
|
bitvec
|
||||||
|
};
|
||||||
|
|
||||||
|
let cores = vec![occupied_core(0)];
|
||||||
|
|
||||||
|
let bitfields = vec![
|
||||||
|
block_on(signed_bitfield(&keystore, bitvec_zero, 0)),
|
||||||
|
block_on(signed_bitfield(&keystore, bitvec_one.clone(), 0)),
|
||||||
|
];
|
||||||
|
|
||||||
|
// this test is probablistic: chances are excellent that it does what it claims to.
|
||||||
|
// it cannot fail unless things are broken.
|
||||||
|
// however, there is a (very small) chance that it passes when things are broken.
|
||||||
|
for _ in 0..64 {
|
||||||
|
let selected_bitfields = select_availability_bitfields(&cores, &bitfields);
|
||||||
|
assert_eq!(selected_bitfields.len(), 1);
|
||||||
|
assert_eq!(selected_bitfields[0].payload().0, bitvec_one);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod select_candidates {
|
||||||
|
use futures_timer::Delay;
|
||||||
|
use super::super::*;
|
||||||
|
use super::{build_occupied_core, default_bitvec, occupied_core, scheduled_core};
|
||||||
|
use polkadot_node_subsystem::messages::RuntimeApiRequest::{
|
||||||
|
AvailabilityCores, PersistedValidationData as PersistedValidationDataReq,
|
||||||
|
};
|
||||||
|
use polkadot_primitives::v1::{
|
||||||
|
BlockNumber, CandidateDescriptor, CommittedCandidateReceipt, PersistedValidationData,
|
||||||
|
};
|
||||||
|
use FromJob::{ChainApi, Runtime};
|
||||||
|
|
||||||
|
const BLOCK_UNDER_PRODUCTION: BlockNumber = 128;
|
||||||
|
|
||||||
|
fn test_harness<OverseerFactory, Overseer, TestFactory, Test>(
|
||||||
|
overseer_factory: OverseerFactory,
|
||||||
|
test_factory: TestFactory,
|
||||||
|
) where
|
||||||
|
OverseerFactory: FnOnce(mpsc::Receiver<FromJob>) -> Overseer,
|
||||||
|
Overseer: Future<Output = ()>,
|
||||||
|
TestFactory: FnOnce(mpsc::Sender<FromJob>) -> Test,
|
||||||
|
Test: Future<Output = ()>,
|
||||||
|
{
|
||||||
|
let (tx, rx) = mpsc::channel(64);
|
||||||
|
let overseer = overseer_factory(rx);
|
||||||
|
let test = test_factory(tx);
|
||||||
|
|
||||||
|
futures::pin_mut!(overseer, test);
|
||||||
|
|
||||||
|
let _ = futures::executor::block_on(future::select(overseer, test));
|
||||||
|
}
|
||||||
|
|
||||||
|
// For test purposes, we always return this set of availability cores:
|
||||||
|
//
|
||||||
|
// [
|
||||||
|
// 0: Free,
|
||||||
|
// 1: Scheduled(default),
|
||||||
|
// 2: Occupied(no next_up set),
|
||||||
|
// 3: Occupied(next_up_on_available set but not available),
|
||||||
|
// 4: Occupied(next_up_on_available set and available),
|
||||||
|
// 5: Occupied(next_up_on_time_out set but not timeout),
|
||||||
|
// 6: Occupied(next_up_on_time_out set and timeout but available),
|
||||||
|
// 7: Occupied(next_up_on_time_out set and timeout and not available),
|
||||||
|
// 8: Occupied(both next_up set, available),
|
||||||
|
// 9: Occupied(both next_up set, not available, no timeout),
|
||||||
|
// 10: Occupied(both next_up set, not available, timeout),
|
||||||
|
// 11: Occupied(next_up_on_available and available, but different successor para_id)
|
||||||
|
// ]
|
||||||
|
fn mock_availability_cores() -> Vec<CoreState> {
|
||||||
|
use std::ops::Not;
|
||||||
|
use CoreState::{Free, Scheduled};
|
||||||
|
|
||||||
|
vec![
|
||||||
|
// 0: Free,
|
||||||
|
Free,
|
||||||
|
// 1: Scheduled(default),
|
||||||
|
Scheduled(scheduled_core(1)),
|
||||||
|
// 2: Occupied(no next_up set),
|
||||||
|
occupied_core(2),
|
||||||
|
// 3: Occupied(next_up_on_available set but not available),
|
||||||
|
build_occupied_core(3, |core| {
|
||||||
|
core.next_up_on_available = Some(scheduled_core(3));
|
||||||
|
}),
|
||||||
|
// 4: Occupied(next_up_on_available set and available),
|
||||||
|
build_occupied_core(4, |core| {
|
||||||
|
core.next_up_on_available = Some(scheduled_core(4));
|
||||||
|
core.availability = core.availability.clone().not();
|
||||||
|
}),
|
||||||
|
// 5: Occupied(next_up_on_time_out set but not timeout),
|
||||||
|
build_occupied_core(5, |core| {
|
||||||
|
core.next_up_on_time_out = Some(scheduled_core(5));
|
||||||
|
}),
|
||||||
|
// 6: Occupied(next_up_on_time_out set and timeout but available),
|
||||||
|
build_occupied_core(6, |core| {
|
||||||
|
core.next_up_on_time_out = Some(scheduled_core(6));
|
||||||
|
core.time_out_at = BLOCK_UNDER_PRODUCTION;
|
||||||
|
core.availability = core.availability.clone().not();
|
||||||
|
}),
|
||||||
|
// 7: Occupied(next_up_on_time_out set and timeout and not available),
|
||||||
|
build_occupied_core(7, |core| {
|
||||||
|
core.next_up_on_time_out = Some(scheduled_core(7));
|
||||||
|
core.time_out_at = BLOCK_UNDER_PRODUCTION;
|
||||||
|
}),
|
||||||
|
// 8: Occupied(both next_up set, available),
|
||||||
|
build_occupied_core(8, |core| {
|
||||||
|
core.next_up_on_available = Some(scheduled_core(8));
|
||||||
|
core.next_up_on_time_out = Some(scheduled_core(8));
|
||||||
|
core.availability = core.availability.clone().not();
|
||||||
|
}),
|
||||||
|
// 9: Occupied(both next_up set, not available, no timeout),
|
||||||
|
build_occupied_core(9, |core| {
|
||||||
|
core.next_up_on_available = Some(scheduled_core(9));
|
||||||
|
core.next_up_on_time_out = Some(scheduled_core(9));
|
||||||
|
}),
|
||||||
|
// 10: Occupied(both next_up set, not available, timeout),
|
||||||
|
build_occupied_core(10, |core| {
|
||||||
|
core.next_up_on_available = Some(scheduled_core(10));
|
||||||
|
core.next_up_on_time_out = Some(scheduled_core(10));
|
||||||
|
core.time_out_at = BLOCK_UNDER_PRODUCTION;
|
||||||
|
}),
|
||||||
|
// 11: Occupied(next_up_on_available and available, but different successor para_id)
|
||||||
|
build_occupied_core(11, |core| {
|
||||||
|
core.next_up_on_available = Some(scheduled_core(12));
|
||||||
|
core.availability = core.availability.clone().not();
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn mock_overseer(mut receiver: mpsc::Receiver<FromJob>) {
|
||||||
|
use ChainApiMessage::BlockNumber;
|
||||||
|
use RuntimeApiMessage::Request;
|
||||||
|
|
||||||
|
while let Some(from_job) = receiver.next().await {
|
||||||
|
match from_job {
|
||||||
|
ChainApi(BlockNumber(_relay_parent, tx)) => {
|
||||||
|
tx.send(Ok(Some(BLOCK_UNDER_PRODUCTION - 1))).unwrap()
|
||||||
|
}
|
||||||
|
Runtime(Request(
|
||||||
|
_parent_hash,
|
||||||
|
PersistedValidationDataReq(_para_id, _assumption, tx),
|
||||||
|
)) => tx.send(Ok(Some(Default::default()))).unwrap(),
|
||||||
|
Runtime(Request(_parent_hash, AvailabilityCores(tx))) => {
|
||||||
|
tx.send(Ok(mock_availability_cores())).unwrap()
|
||||||
|
}
|
||||||
|
// non-exhaustive matches are fine for testing
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn handles_overseer_failure() {
|
||||||
|
let overseer = |rx: mpsc::Receiver<FromJob>| async move {
|
||||||
|
// drop the receiver so it closes and the sender can't send, then just sleep long enough that
|
||||||
|
// this is almost certainly not the first of the two futures to complete
|
||||||
|
std::mem::drop(rx);
|
||||||
|
Delay::new(std::time::Duration::from_secs(1)).await;
|
||||||
|
};
|
||||||
|
|
||||||
|
let test = |mut tx: mpsc::Sender<FromJob>| async move {
|
||||||
|
// wait so that the overseer can drop the rx before we attempt to send
|
||||||
|
Delay::new(std::time::Duration::from_millis(50)).await;
|
||||||
|
let result = select_candidates(&[], &[], &[], Default::default(), &mut tx).await;
|
||||||
|
println!("{:?}", result);
|
||||||
|
assert!(std::matches!(result, Err(Error::ChainApiMessageSend(_))));
|
||||||
|
};
|
||||||
|
|
||||||
|
test_harness(overseer, test);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_succeed() {
|
||||||
|
test_harness(mock_overseer, |mut tx: mpsc::Sender<FromJob>| async move {
|
||||||
|
let result = select_candidates(&[], &[], &[], Default::default(), &mut tx).await;
|
||||||
|
println!("{:?}", result);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// this tests that only the appropriate candidates get selected.
|
||||||
|
// To accomplish this, we supply a candidate list containing one candidate per possible core;
|
||||||
|
// the candidate selection algorithm must filter them to the appropriate set
|
||||||
|
#[test]
|
||||||
|
fn selects_correct_candidates() {
|
||||||
|
let mock_cores = mock_availability_cores();
|
||||||
|
|
||||||
|
let empty_hash = PersistedValidationData::<BlockNumber>::default().hash();
|
||||||
|
|
||||||
|
let candidate_template = BackedCandidate {
|
||||||
|
candidate: CommittedCandidateReceipt {
|
||||||
|
descriptor: CandidateDescriptor {
|
||||||
|
persisted_validation_data_hash: empty_hash,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
validity_votes: Vec::new(),
|
||||||
|
validator_indices: default_bitvec(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let candidates: Vec<_> = std::iter::repeat(candidate_template)
|
||||||
|
.take(mock_cores.len())
|
||||||
|
.enumerate()
|
||||||
|
.map(|(idx, mut candidate)| {
|
||||||
|
candidate.candidate.descriptor.para_id = idx.into();
|
||||||
|
candidate
|
||||||
|
})
|
||||||
|
.cycle()
|
||||||
|
.take(mock_cores.len() * 3)
|
||||||
|
.enumerate()
|
||||||
|
.map(|(idx, mut candidate)| {
|
||||||
|
if idx < mock_cores.len() {
|
||||||
|
// first go-around: use candidates which should work
|
||||||
|
candidate
|
||||||
|
} else if idx < mock_cores.len() * 2 {
|
||||||
|
// for the second repetition of the candidates, give them the wrong hash
|
||||||
|
candidate.candidate.descriptor.persisted_validation_data_hash
|
||||||
|
= Default::default();
|
||||||
|
candidate
|
||||||
|
} else {
|
||||||
|
// third go-around: right hash, wrong para_id
|
||||||
|
candidate.candidate.descriptor.para_id = idx.into();
|
||||||
|
candidate
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// why those particular indices? see the comments on mock_availability_cores()
|
||||||
|
let expected_candidates: Vec<_> = [1, 4, 7, 8, 10]
|
||||||
|
.iter()
|
||||||
|
.map(|&idx| candidates[idx].clone())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
test_harness(mock_overseer, |mut tx: mpsc::Sender<FromJob>| async move {
|
||||||
|
let result =
|
||||||
|
select_candidates(&mock_cores, &[], &candidates, Default::default(), &mut tx)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if result.is_err() {
|
||||||
|
println!("{:?}", result);
|
||||||
|
}
|
||||||
|
assert_eq!(result.unwrap(), expected_candidates);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,10 +7,8 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "0.3.5"
|
futures = "0.3.5"
|
||||||
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|
||||||
|
|
||||||
polkadot-primitives = { path = "../../../primitives" }
|
polkadot-primitives = { path = "../../../primitives" }
|
||||||
polkadot-node-primitives = { path = "../../primitives" }
|
|
||||||
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
|
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
|
||||||
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,9 @@
|
|||||||
//! This provides a clean, ownerless wrapper around the parachain-related runtime APIs. This crate
|
//! This provides a clean, ownerless wrapper around the parachain-related runtime APIs. This crate
|
||||||
//! can also be used to cache responses from heavy runtime APIs.
|
//! can also be used to cache responses from heavy runtime APIs.
|
||||||
|
|
||||||
|
#![deny(unused_crate_dependencies)]
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
use polkadot_subsystem::{
|
use polkadot_subsystem::{
|
||||||
Subsystem, SpawnedSubsystem, SubsystemResult, SubsystemContext,
|
Subsystem, SpawnedSubsystem, SubsystemResult, SubsystemContext,
|
||||||
FromOverseer, OverseerSignal,
|
FromOverseer, OverseerSignal,
|
||||||
|
|||||||
@@ -7,26 +7,22 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "0.3.5"
|
futures = "0.3.5"
|
||||||
log = "0.4.11"
|
log = "0.4.11"
|
||||||
streamunordered = "0.5.1"
|
|
||||||
codec = { package="parity-scale-codec", version = "1.3.4", features = ["std"] }
|
codec = { package="parity-scale-codec", version = "1.3.4", features = ["std"] }
|
||||||
derive_more = "0.99.9"
|
|
||||||
polkadot-primitives = { path = "../../../primitives" }
|
polkadot-primitives = { path = "../../../primitives" }
|
||||||
polkadot-erasure-coding = { path = "../../../erasure-coding" }
|
polkadot-erasure-coding = { path = "../../../erasure-coding" }
|
||||||
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
|
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
|
||||||
polkadot-network-bridge = { path = "../../network/bridge" }
|
|
||||||
polkadot-node-network-protocol = { path = "../../network/protocol" }
|
polkadot-node-network-protocol = { path = "../../network/protocol" }
|
||||||
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
||||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", features = ["std"] }
|
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", features = ["std"] }
|
||||||
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
thiserror = "1.0.21"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
polkadot-subsystem-testhelpers = { package = "polkadot-node-subsystem-test-helpers", path = "../../subsystem-test-helpers" }
|
polkadot-subsystem-testhelpers = { package = "polkadot-node-subsystem-test-helpers", path = "../../subsystem-test-helpers" }
|
||||||
bitvec = { version = "0.17.4", default-features = false, features = ["alloc"] }
|
|
||||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", features = ["std"] }
|
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", features = ["std"] }
|
||||||
sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
parking_lot = "0.11.0"
|
|
||||||
futures-timer = "3.0.2"
|
futures-timer = "3.0.2"
|
||||||
env_logger = "0.7.1"
|
env_logger = "0.7.1"
|
||||||
assert_matches = "1.3.0"
|
assert_matches = "1.3.0"
|
||||||
|
|||||||
@@ -22,56 +22,99 @@
|
|||||||
//! peers. Verified in this context means, the erasure chunks contained merkle proof
|
//! peers. Verified in this context means, the erasure chunks contained merkle proof
|
||||||
//! is checked.
|
//! is checked.
|
||||||
|
|
||||||
|
#![deny(unused_crate_dependencies, unused_qualifications)]
|
||||||
|
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
use futures::{channel::oneshot, FutureExt};
|
use futures::{channel::oneshot, FutureExt, TryFutureExt};
|
||||||
|
|
||||||
use sp_core::crypto::Public;
|
use sp_core::crypto::Public;
|
||||||
use sp_keystore::{CryptoStore, SyncCryptoStorePtr};
|
use sp_keystore::{CryptoStore, SyncCryptoStorePtr};
|
||||||
|
|
||||||
use log::{trace, warn};
|
use log::{trace, warn};
|
||||||
use polkadot_erasure_coding::branch_hash;
|
use polkadot_erasure_coding::branch_hash;
|
||||||
|
use polkadot_node_network_protocol::{
|
||||||
|
v1 as protocol_v1, NetworkBridgeEvent, PeerId, ReputationChange as Rep, View,
|
||||||
|
};
|
||||||
|
use polkadot_node_subsystem_util::metrics::{self, prometheus};
|
||||||
use polkadot_primitives::v1::{
|
use polkadot_primitives::v1::{
|
||||||
PARACHAIN_KEY_TYPE_ID,
|
BlakeTwo256, CommittedCandidateReceipt, CoreState, ErasureChunk, Hash, HashT, Id as ParaId,
|
||||||
BlakeTwo256, CommittedCandidateReceipt, CoreState, ErasureChunk,
|
SessionIndex, ValidatorId, ValidatorIndex, PARACHAIN_KEY_TYPE_ID,
|
||||||
Hash as Hash, HashT, Id as ParaId,
|
|
||||||
ValidatorId, ValidatorIndex, SessionIndex,
|
|
||||||
};
|
};
|
||||||
use polkadot_subsystem::messages::{
|
use polkadot_subsystem::messages::{
|
||||||
AllMessages, AvailabilityDistributionMessage, NetworkBridgeMessage, RuntimeApiMessage,
|
AllMessages, AvailabilityDistributionMessage, AvailabilityStoreMessage, ChainApiMessage,
|
||||||
RuntimeApiRequest, AvailabilityStoreMessage, ChainApiMessage,
|
NetworkBridgeMessage, RuntimeApiMessage, RuntimeApiRequest,
|
||||||
};
|
};
|
||||||
use polkadot_subsystem::{
|
use polkadot_subsystem::{
|
||||||
errors::{ChainApiError, RuntimeApiError},
|
errors::{ChainApiError, RuntimeApiError},
|
||||||
ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, Subsystem,
|
ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, Subsystem,
|
||||||
SubsystemContext, SubsystemError,
|
SubsystemContext, SubsystemError,
|
||||||
};
|
};
|
||||||
use polkadot_node_subsystem_util::{
|
|
||||||
metrics::{self, prometheus},
|
|
||||||
};
|
|
||||||
use polkadot_node_network_protocol::{
|
|
||||||
v1 as protocol_v1, View, ReputationChange as Rep, PeerId,
|
|
||||||
NetworkBridgeEvent,
|
|
||||||
};
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::io;
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
const TARGET: &'static str = "avad";
|
const TARGET: &'static str = "avad";
|
||||||
|
|
||||||
#[derive(Debug, derive_more::From)]
|
#[derive(Debug, Error)]
|
||||||
enum Error {
|
enum Error {
|
||||||
#[from]
|
#[error("Sending PendingAvailability query failed")]
|
||||||
Erasure(polkadot_erasure_coding::Error),
|
QueryPendingAvailabilitySendQuery(#[source] SubsystemError),
|
||||||
#[from]
|
#[error("Response channel to obtain PendingAvailability failed")]
|
||||||
Io(io::Error),
|
QueryPendingAvailabilityResponseChannel(#[source] oneshot::Canceled),
|
||||||
#[from]
|
#[error("RuntimeAPI to obtain PendingAvailability failed")]
|
||||||
Oneshot(oneshot::Canceled),
|
QueryPendingAvailability(#[source] RuntimeApiError),
|
||||||
#[from]
|
|
||||||
Subsystem(SubsystemError),
|
#[error("Sending StoreChunk query failed")]
|
||||||
#[from]
|
StoreChunkSendQuery(#[source] SubsystemError),
|
||||||
RuntimeApi(RuntimeApiError),
|
#[error("Response channel to obtain StoreChunk failed")]
|
||||||
#[from]
|
StoreChunkResponseChannel(#[source] oneshot::Canceled),
|
||||||
ChainApi(ChainApiError),
|
|
||||||
|
#[error("Sending QueryChunk query failed")]
|
||||||
|
QueryChunkSendQuery(#[source] SubsystemError),
|
||||||
|
#[error("Response channel to obtain QueryChunk failed")]
|
||||||
|
QueryChunkResponseChannel(#[source] oneshot::Canceled),
|
||||||
|
|
||||||
|
#[error("Sending QueryAncestors query failed")]
|
||||||
|
QueryAncestorsSendQuery(#[source] SubsystemError),
|
||||||
|
#[error("Response channel to obtain QueryAncestors failed")]
|
||||||
|
QueryAncestorsResponseChannel(#[source] oneshot::Canceled),
|
||||||
|
#[error("RuntimeAPI to obtain QueryAncestors failed")]
|
||||||
|
QueryAncestors(#[source] ChainApiError),
|
||||||
|
|
||||||
|
#[error("Sending QuerySession query failed")]
|
||||||
|
QuerySessionSendQuery(#[source] SubsystemError),
|
||||||
|
#[error("Response channel to obtain QuerySession failed")]
|
||||||
|
QuerySessionResponseChannel(#[source] oneshot::Canceled),
|
||||||
|
#[error("RuntimeAPI to obtain QuerySession failed")]
|
||||||
|
QuerySession(#[source] RuntimeApiError),
|
||||||
|
|
||||||
|
#[error("Sending QueryValidators query failed")]
|
||||||
|
QueryValidatorsSendQuery(#[source] SubsystemError),
|
||||||
|
#[error("Response channel to obtain QueryValidators failed")]
|
||||||
|
QueryValidatorsResponseChannel(#[source] oneshot::Canceled),
|
||||||
|
#[error("RuntimeAPI to obtain QueryValidators failed")]
|
||||||
|
QueryValidators(#[source] RuntimeApiError),
|
||||||
|
|
||||||
|
#[error("Sending AvailabilityCores query failed")]
|
||||||
|
AvailabilityCoresSendQuery(#[source] SubsystemError),
|
||||||
|
#[error("Response channel to obtain AvailabilityCores failed")]
|
||||||
|
AvailabilityCoresResponseChannel(#[source] oneshot::Canceled),
|
||||||
|
#[error("RuntimeAPI to obtain AvailabilityCores failed")]
|
||||||
|
AvailabilityCores(#[source] RuntimeApiError),
|
||||||
|
|
||||||
|
#[error("Sending AvailabilityCores query failed")]
|
||||||
|
QueryAvailabilitySendQuery(#[source] SubsystemError),
|
||||||
|
#[error("Response channel to obtain AvailabilityCores failed")]
|
||||||
|
QueryAvailabilityResponseChannel(#[source] oneshot::Canceled),
|
||||||
|
|
||||||
|
#[error("Sending out a peer report message")]
|
||||||
|
ReportPeerMessageSend(#[source] SubsystemError),
|
||||||
|
|
||||||
|
#[error("Sending a gossip message")]
|
||||||
|
TrackedGossipMessage(#[source] SubsystemError),
|
||||||
|
|
||||||
|
#[error("Receive channel closed")]
|
||||||
|
IncomingMessageChannel(#[source] SubsystemError),
|
||||||
}
|
}
|
||||||
|
|
||||||
type Result<T> = std::result::Result<T, Error>;
|
type Result<T> = std::result::Result<T, Error>;
|
||||||
@@ -199,22 +242,18 @@ impl ProtocolState {
|
|||||||
where
|
where
|
||||||
Context: SubsystemContext<Message = AvailabilityDistributionMessage>,
|
Context: SubsystemContext<Message = AvailabilityDistributionMessage>,
|
||||||
{
|
{
|
||||||
let candidates =
|
let candidates = query_live_candidates(ctx, self, std::iter::once(relay_parent)).await?;
|
||||||
query_live_candidates(ctx, self, std::iter::once(relay_parent)).await?;
|
|
||||||
|
|
||||||
// register the relation of relay_parent to candidate..
|
// register the relation of relay_parent to candidate..
|
||||||
// ..and the reverse association.
|
// ..and the reverse association.
|
||||||
for (relay_parent_or_ancestor, (receipt_hash, receipt)) in candidates.clone() {
|
for (relay_parent_or_ancestor, (receipt_hash, receipt)) in candidates.clone() {
|
||||||
self
|
self.reverse
|
||||||
.reverse
|
|
||||||
.insert(receipt_hash.clone(), relay_parent_or_ancestor.clone());
|
.insert(receipt_hash.clone(), relay_parent_or_ancestor.clone());
|
||||||
let per_candidate = self.per_candidate.entry(receipt_hash.clone())
|
let per_candidate = self.per_candidate.entry(receipt_hash.clone()).or_default();
|
||||||
.or_default();
|
|
||||||
per_candidate.validator_index = validator_index.clone();
|
per_candidate.validator_index = validator_index.clone();
|
||||||
per_candidate.validators = validators.clone();
|
per_candidate.validators = validators.clone();
|
||||||
|
|
||||||
self
|
self.receipts
|
||||||
.receipts
|
|
||||||
.entry(relay_parent_or_ancestor)
|
.entry(relay_parent_or_ancestor)
|
||||||
.or_default()
|
.or_default()
|
||||||
.insert((receipt_hash, receipt));
|
.insert((receipt_hash, receipt));
|
||||||
@@ -240,8 +279,7 @@ impl ProtocolState {
|
|||||||
.insert(relay_parent);
|
.insert(relay_parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
self.per_relay_parent
|
||||||
.per_relay_parent
|
|
||||||
.entry(relay_parent)
|
.entry(relay_parent)
|
||||||
.or_default()
|
.or_default()
|
||||||
.ancestors = ancestors;
|
.ancestors = ancestors;
|
||||||
@@ -314,17 +352,21 @@ where
|
|||||||
}
|
}
|
||||||
NetworkBridgeEvent::PeerMessage(remote, msg) => {
|
NetworkBridgeEvent::PeerMessage(remote, msg) => {
|
||||||
let gossiped_availability = match msg {
|
let gossiped_availability = match msg {
|
||||||
protocol_v1::AvailabilityDistributionMessage::Chunk(candidate_hash, chunk) =>
|
protocol_v1::AvailabilityDistributionMessage::Chunk(candidate_hash, chunk) => {
|
||||||
AvailabilityGossipMessage { candidate_hash, erasure_chunk: chunk }
|
AvailabilityGossipMessage {
|
||||||
|
candidate_hash,
|
||||||
|
erasure_chunk: chunk,
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
process_incoming_peer_message(ctx, state, remote, gossiped_availability, metrics).await?;
|
process_incoming_peer_message(ctx, state, remote, gossiped_availability, metrics)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Handle the changes necessary when our view changes.
|
/// Handle the changes necessary when our view changes.
|
||||||
async fn handle_our_view_change<Context>(
|
async fn handle_our_view_change<Context>(
|
||||||
ctx: &mut Context,
|
ctx: &mut Context,
|
||||||
@@ -346,19 +388,15 @@ where
|
|||||||
for added in added.iter() {
|
for added in added.iter() {
|
||||||
let added = **added;
|
let added = **added;
|
||||||
let validators = query_validators(ctx, added).await?;
|
let validators = query_validators(ctx, added).await?;
|
||||||
let validator_index = obtain_our_validator_index(
|
let validator_index = obtain_our_validator_index(&validators, keystore.clone()).await;
|
||||||
&validators,
|
state
|
||||||
keystore.clone(),
|
.add_relay_parent(ctx, added, validators, validator_index)
|
||||||
).await;
|
.await?;
|
||||||
state.add_relay_parent(ctx, added, validators, validator_index).await?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle all candidates
|
// handle all candidates
|
||||||
for (candidate_hash, _receipt) in state.cached_live_candidates_unioned(added) {
|
for (candidate_hash, _receipt) in state.cached_live_candidates_unioned(added) {
|
||||||
let per_candidate = state
|
let per_candidate = state.per_candidate.entry(candidate_hash).or_default();
|
||||||
.per_candidate
|
|
||||||
.entry(candidate_hash)
|
|
||||||
.or_default();
|
|
||||||
|
|
||||||
// assure the node has the validator role
|
// assure the node has the validator role
|
||||||
if per_candidate.validator_index.is_none() {
|
if per_candidate.validator_index.is_none() {
|
||||||
@@ -388,19 +426,18 @@ where
|
|||||||
|
|
||||||
// distribute all erasure messages to interested peers
|
// distribute all erasure messages to interested peers
|
||||||
for chunk_index in 0u32..(validator_count as u32) {
|
for chunk_index in 0u32..(validator_count as u32) {
|
||||||
|
|
||||||
// only the peers which did not receive this particular erasure chunk
|
// only the peers which did not receive this particular erasure chunk
|
||||||
let per_candidate = state
|
let per_candidate = state.per_candidate.entry(candidate_hash).or_default();
|
||||||
.per_candidate
|
|
||||||
.entry(candidate_hash)
|
|
||||||
.or_default();
|
|
||||||
|
|
||||||
// obtain the chunks from the cache, if not fallback
|
// obtain the chunks from the cache, if not fallback
|
||||||
// and query the availability store
|
// and query the availability store
|
||||||
let message_id = (candidate_hash, chunk_index);
|
let message_id = (candidate_hash, chunk_index);
|
||||||
let erasure_chunk = if let Some(message) = per_candidate.message_vault.get(&chunk_index) {
|
let erasure_chunk = if let Some(message) = per_candidate.message_vault.get(&chunk_index)
|
||||||
|
{
|
||||||
message.erasure_chunk.clone()
|
message.erasure_chunk.clone()
|
||||||
} else if let Some(erasure_chunk) = query_chunk(ctx, candidate_hash, chunk_index as ValidatorIndex).await? {
|
} else if let Some(erasure_chunk) =
|
||||||
|
query_chunk(ctx, candidate_hash, chunk_index as ValidatorIndex).await?
|
||||||
|
{
|
||||||
erasure_chunk
|
erasure_chunk
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
@@ -415,9 +452,7 @@ where
|
|||||||
!per_candidate
|
!per_candidate
|
||||||
.sent_messages
|
.sent_messages
|
||||||
.get(*peer)
|
.get(*peer)
|
||||||
.filter(|set| {
|
.filter(|set| set.contains(&message_id))
|
||||||
set.contains(&message_id)
|
|
||||||
})
|
|
||||||
.is_some()
|
.is_some()
|
||||||
})
|
})
|
||||||
.map(|peer| peer.clone())
|
.map(|peer| peer.clone())
|
||||||
@@ -427,7 +462,8 @@ where
|
|||||||
erasure_chunk,
|
erasure_chunk,
|
||||||
};
|
};
|
||||||
|
|
||||||
send_tracked_gossip_message_to_peers(ctx, per_candidate, metrics, peers, message).await?;
|
send_tracked_gossip_message_to_peers(ctx, per_candidate, metrics, peers, message)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,7 +486,8 @@ async fn send_tracked_gossip_message_to_peers<Context>(
|
|||||||
where
|
where
|
||||||
Context: SubsystemContext<Message = AvailabilityDistributionMessage>,
|
Context: SubsystemContext<Message = AvailabilityDistributionMessage>,
|
||||||
{
|
{
|
||||||
send_tracked_gossip_messages_to_peers(ctx, per_candidate, metrics, peers, iter::once(message)).await
|
send_tracked_gossip_messages_to_peers(ctx, per_candidate, metrics, peers, iter::once(message))
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@@ -464,7 +501,8 @@ async fn send_tracked_gossip_messages_to_peer<Context>(
|
|||||||
where
|
where
|
||||||
Context: SubsystemContext<Message = AvailabilityDistributionMessage>,
|
Context: SubsystemContext<Message = AvailabilityDistributionMessage>,
|
||||||
{
|
{
|
||||||
send_tracked_gossip_messages_to_peers(ctx, per_candidate, metrics, vec![peer], message_iter).await
|
send_tracked_gossip_messages_to_peers(ctx, per_candidate, metrics, vec![peer], message_iter)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_tracked_gossip_messages_to_peers<Context>(
|
async fn send_tracked_gossip_messages_to_peers<Context>(
|
||||||
@@ -478,7 +516,7 @@ where
|
|||||||
Context: SubsystemContext<Message = AvailabilityDistributionMessage>,
|
Context: SubsystemContext<Message = AvailabilityDistributionMessage>,
|
||||||
{
|
{
|
||||||
if peers.is_empty() {
|
if peers.is_empty() {
|
||||||
return Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
for message in message_iter {
|
for message in message_iter {
|
||||||
for peer in peers.iter() {
|
for peer in peers.iter() {
|
||||||
@@ -506,7 +544,7 @@ where
|
|||||||
),
|
),
|
||||||
))
|
))
|
||||||
.await
|
.await
|
||||||
.map_err::<Error, _>(Into::into)?;
|
.map_err(|e| Error::TrackedGossipMessage(e))?;
|
||||||
|
|
||||||
metrics.on_chunk_distributed();
|
metrics.on_chunk_distributed();
|
||||||
}
|
}
|
||||||
@@ -543,8 +581,7 @@ where
|
|||||||
let per_candidate = state.per_candidate.entry(candidate_hash).or_default();
|
let per_candidate = state.per_candidate.entry(candidate_hash).or_default();
|
||||||
|
|
||||||
// obtain the relevant chunk indices not sent yet
|
// obtain the relevant chunk indices not sent yet
|
||||||
let messages = ((0 as ValidatorIndex)
|
let messages = ((0 as ValidatorIndex)..(per_candidate.validators.len() as ValidatorIndex))
|
||||||
..(per_candidate.validators.len() as ValidatorIndex))
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|erasure_chunk_index: ValidatorIndex| {
|
.filter_map(|erasure_chunk_index: ValidatorIndex| {
|
||||||
let message_id = (candidate_hash, erasure_chunk_index);
|
let message_id = (candidate_hash, erasure_chunk_index);
|
||||||
@@ -567,7 +604,8 @@ where
|
|||||||
.cloned()
|
.cloned()
|
||||||
.collect::<HashSet<_>>();
|
.collect::<HashSet<_>>();
|
||||||
|
|
||||||
send_tracked_gossip_messages_to_peer(ctx, per_candidate, metrics, origin.clone(), messages).await?;
|
send_tracked_gossip_messages_to_peer(ctx, per_candidate, metrics, origin.clone(), messages)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -580,8 +618,13 @@ async fn obtain_our_validator_index(
|
|||||||
keystore: SyncCryptoStorePtr,
|
keystore: SyncCryptoStorePtr,
|
||||||
) -> Option<ValidatorIndex> {
|
) -> Option<ValidatorIndex> {
|
||||||
for (idx, validator) in validators.iter().enumerate() {
|
for (idx, validator) in validators.iter().enumerate() {
|
||||||
if CryptoStore::has_keys(&*keystore, &[(validator.to_raw_vec(), PARACHAIN_KEY_TYPE_ID)]).await {
|
if CryptoStore::has_keys(
|
||||||
return Some(idx as ValidatorIndex)
|
&*keystore,
|
||||||
|
&[(validator.to_raw_vec(), PARACHAIN_KEY_TYPE_ID)],
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return Some(idx as ValidatorIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
@@ -664,8 +707,13 @@ where
|
|||||||
live_candidate.descriptor.relay_parent.clone(),
|
live_candidate.descriptor.relay_parent.clone(),
|
||||||
message.erasure_chunk.index,
|
message.erasure_chunk.index,
|
||||||
message.erasure_chunk.clone(),
|
message.erasure_chunk.clone(),
|
||||||
).await? {
|
)
|
||||||
warn!(target: TARGET, "Failed to store erasure chunk to availability store");
|
.await?
|
||||||
|
{
|
||||||
|
warn!(
|
||||||
|
target: TARGET,
|
||||||
|
"Failed to store erasure chunk to availability store"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -729,7 +777,10 @@ impl AvailabilityDistributionSubsystem {
|
|||||||
// work: process incoming messages from the overseer.
|
// work: process incoming messages from the overseer.
|
||||||
let mut state = ProtocolState::default();
|
let mut state = ProtocolState::default();
|
||||||
loop {
|
loop {
|
||||||
let message = ctx.recv().await.map_err::<Error, _>(Into::into)?;
|
let message = ctx
|
||||||
|
.recv()
|
||||||
|
.await
|
||||||
|
.map_err(|e| Error::IncomingMessageChannel(e))?;
|
||||||
match message {
|
match message {
|
||||||
FromOverseer::Communication {
|
FromOverseer::Communication {
|
||||||
msg: AvailabilityDistributionMessage::NetworkBridgeUpdateV1(event),
|
msg: AvailabilityDistributionMessage::NetworkBridgeUpdateV1(event),
|
||||||
@@ -740,7 +791,9 @@ impl AvailabilityDistributionSubsystem {
|
|||||||
&mut state,
|
&mut state,
|
||||||
&self.metrics,
|
&self.metrics,
|
||||||
event,
|
event,
|
||||||
).await {
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
warn!(
|
warn!(
|
||||||
target: TARGET,
|
target: TARGET,
|
||||||
"Failed to handle incomming network messages: {:?}", e
|
"Failed to handle incomming network messages: {:?}", e
|
||||||
@@ -767,9 +820,15 @@ where
|
|||||||
Context: SubsystemContext<Message = AvailabilityDistributionMessage> + Sync + Send,
|
Context: SubsystemContext<Message = AvailabilityDistributionMessage> + Sync + Send,
|
||||||
{
|
{
|
||||||
fn start(self, ctx: Context) -> SpawnedSubsystem {
|
fn start(self, ctx: Context) -> SpawnedSubsystem {
|
||||||
|
let future = self
|
||||||
|
.run(ctx)
|
||||||
|
.map_err(|e| SubsystemError::with_origin("availability-distribution", e))
|
||||||
|
.map(|_| ())
|
||||||
|
.boxed();
|
||||||
|
|
||||||
SpawnedSubsystem {
|
SpawnedSubsystem {
|
||||||
name: "availability-distribution-subsystem",
|
name: "availability-distribution-subsystem",
|
||||||
future: Box::pin(async move { self.run(ctx) }.map(|_| ())),
|
future,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -816,7 +875,6 @@ where
|
|||||||
HashMap::<Hash, (Hash, CommittedCandidateReceipt)>::with_capacity(capacity);
|
HashMap::<Hash, (Hash, CommittedCandidateReceipt)>::with_capacity(capacity);
|
||||||
|
|
||||||
for relay_parent in iter {
|
for relay_parent in iter {
|
||||||
|
|
||||||
// register one of relay parents (not the ancestors)
|
// register one of relay parents (not the ancestors)
|
||||||
let mut ancestors = query_up_to_k_ancestors_in_same_session(
|
let mut ancestors = query_up_to_k_ancestors_in_same_session(
|
||||||
ctx,
|
ctx,
|
||||||
@@ -827,7 +885,6 @@ where
|
|||||||
|
|
||||||
ancestors.push(relay_parent);
|
ancestors.push(relay_parent);
|
||||||
|
|
||||||
|
|
||||||
// ancestors might overlap, so check the cache too
|
// ancestors might overlap, so check the cache too
|
||||||
let unknown = ancestors
|
let unknown = ancestors
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -841,10 +898,7 @@ where
|
|||||||
// directly extend the live_candidates with the cached value
|
// directly extend the live_candidates with the cached value
|
||||||
live_candidates.extend(receipts.into_iter().map(
|
live_candidates.extend(receipts.into_iter().map(
|
||||||
|(receipt_hash, receipt)| {
|
|(receipt_hash, receipt)| {
|
||||||
(
|
(relay_parent, (receipt_hash.clone(), receipt.clone()))
|
||||||
relay_parent,
|
|
||||||
(receipt_hash.clone(), receipt.clone()),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
Some(())
|
Some(())
|
||||||
@@ -877,10 +931,12 @@ where
|
|||||||
RuntimeApiRequest::AvailabilityCores(tx),
|
RuntimeApiRequest::AvailabilityCores(tx),
|
||||||
)))
|
)))
|
||||||
.await
|
.await
|
||||||
.map_err::<Error, _>(Into::into)?;
|
.map_err(|e| Error::AvailabilityCoresSendQuery(e))?;
|
||||||
|
|
||||||
let all_para_ids: Vec<_> = rx
|
let all_para_ids: Vec<_> = rx
|
||||||
.await??;
|
.await
|
||||||
|
.map_err(|e| Error::AvailabilityCoresResponseChannel(e))?
|
||||||
|
.map_err(|e| Error::AvailabilityCores(e))?;
|
||||||
|
|
||||||
let occupied_para_ids = all_para_ids
|
let occupied_para_ids = all_para_ids
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -910,14 +966,11 @@ where
|
|||||||
NetworkBridgeMessage::ReportPeer(peer, rep),
|
NetworkBridgeMessage::ReportPeer(peer, rep),
|
||||||
))
|
))
|
||||||
.await
|
.await
|
||||||
.map_err::<Error, _>(Into::into)
|
.map_err(|e| Error::ReportPeerMessageSend(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Query the proof of validity for a particular candidate hash.
|
/// Query the proof of validity for a particular candidate hash.
|
||||||
async fn query_data_availability<Context>(
|
async fn query_data_availability<Context>(ctx: &mut Context, candidate_hash: Hash) -> Result<bool>
|
||||||
ctx: &mut Context,
|
|
||||||
candidate_hash: Hash,
|
|
||||||
) -> Result<bool>
|
|
||||||
where
|
where
|
||||||
Context: SubsystemContext<Message = AvailabilityDistributionMessage>,
|
Context: SubsystemContext<Message = AvailabilityDistributionMessage>,
|
||||||
{
|
{
|
||||||
@@ -925,11 +978,12 @@ where
|
|||||||
ctx.send_message(AllMessages::AvailabilityStore(
|
ctx.send_message(AllMessages::AvailabilityStore(
|
||||||
AvailabilityStoreMessage::QueryDataAvailability(candidate_hash, tx),
|
AvailabilityStoreMessage::QueryDataAvailability(candidate_hash, tx),
|
||||||
))
|
))
|
||||||
.await?;
|
.await
|
||||||
rx.await.map_err::<Error, _>(Into::into)
|
.map_err(|e| Error::QueryAvailabilitySendQuery(e))?;
|
||||||
|
rx.await
|
||||||
|
.map_err(|e| Error::QueryAvailabilityResponseChannel(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async fn query_chunk<Context>(
|
async fn query_chunk<Context>(
|
||||||
ctx: &mut Context,
|
ctx: &mut Context,
|
||||||
candidate_hash: Hash,
|
candidate_hash: Hash,
|
||||||
@@ -940,13 +994,13 @@ where
|
|||||||
{
|
{
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
ctx.send_message(AllMessages::AvailabilityStore(
|
ctx.send_message(AllMessages::AvailabilityStore(
|
||||||
AvailabilityStoreMessage::QueryChunk(candidate_hash, validator_index, tx),
|
AvailabilityStoreMessage::QueryChunk(candidate_hash, validator_index, tx),
|
||||||
))
|
))
|
||||||
.await?;
|
.await
|
||||||
rx.await.map_err::<Error, _>(Into::into)
|
.map_err(|e| Error::QueryChunkSendQuery(e))?;
|
||||||
|
rx.await.map_err(|e| Error::QueryChunkResponseChannel(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async fn store_chunk<Context>(
|
async fn store_chunk<Context>(
|
||||||
ctx: &mut Context,
|
ctx: &mut Context,
|
||||||
candidate_hash: Hash,
|
candidate_hash: Hash,
|
||||||
@@ -958,16 +1012,19 @@ where
|
|||||||
Context: SubsystemContext<Message = AvailabilityDistributionMessage>,
|
Context: SubsystemContext<Message = AvailabilityDistributionMessage>,
|
||||||
{
|
{
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
ctx.send_message(AllMessages::AvailabilityStore(
|
ctx.send_message(
|
||||||
AvailabilityStoreMessage::StoreChunk {
|
AllMessages::AvailabilityStore(
|
||||||
candidate_hash,
|
AvailabilityStoreMessage::StoreChunk {
|
||||||
relay_parent,
|
candidate_hash,
|
||||||
validator_index,
|
relay_parent,
|
||||||
chunk: erasure_chunk,
|
validator_index,
|
||||||
tx,
|
chunk: erasure_chunk,
|
||||||
}
|
tx,
|
||||||
)).await?;
|
}
|
||||||
rx.await.map_err::<Error, _>(Into::into)
|
)).await
|
||||||
|
.map_err(|e| Error::StoreChunkSendQuery(e))?;
|
||||||
|
|
||||||
|
rx.await.map_err(|e| Error::StoreChunkResponseChannel(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Request the head data for a particular para.
|
/// Request the head data for a particular para.
|
||||||
@@ -981,12 +1038,15 @@ where
|
|||||||
{
|
{
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
ctx.send_message(AllMessages::RuntimeApi(RuntimeApiMessage::Request(
|
ctx.send_message(AllMessages::RuntimeApi(RuntimeApiMessage::Request(
|
||||||
relay_parent,
|
relay_parent,
|
||||||
RuntimeApiRequest::CandidatePendingAvailability(para, tx),
|
RuntimeApiRequest::CandidatePendingAvailability(para, tx),
|
||||||
)))
|
)))
|
||||||
.await?;
|
.await
|
||||||
rx.await?
|
.map_err(|e| Error::QueryPendingAvailabilitySendQuery(e))?;
|
||||||
.map_err::<Error, _>(Into::into)
|
|
||||||
|
rx.await
|
||||||
|
.map_err(|e| Error::QueryPendingAvailabilityResponseChannel(e))?
|
||||||
|
.map_err(|e| Error::QueryPendingAvailability(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Query the validator set.
|
/// Query the validator set.
|
||||||
@@ -1004,9 +1064,11 @@ where
|
|||||||
));
|
));
|
||||||
|
|
||||||
ctx.send_message(query_validators)
|
ctx.send_message(query_validators)
|
||||||
.await?;
|
.await
|
||||||
rx.await?
|
.map_err(|e| Error::QueryValidatorsSendQuery(e))?;
|
||||||
.map_err::<Error, _>(Into::into)
|
rx.await
|
||||||
|
.map_err(|e| Error::QueryValidatorsResponseChannel(e))?
|
||||||
|
.map_err(|e| Error::QueryValidators(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Query the hash of the `K` ancestors
|
/// Query the hash of the `K` ancestors
|
||||||
@@ -1026,9 +1088,11 @@ where
|
|||||||
});
|
});
|
||||||
|
|
||||||
ctx.send_message(query_ancestors)
|
ctx.send_message(query_ancestors)
|
||||||
.await?;
|
.await
|
||||||
rx.await?
|
.map_err(|e| Error::QueryAncestorsSendQuery(e))?;
|
||||||
.map_err::<Error, _>(Into::into)
|
rx.await
|
||||||
|
.map_err(|e| Error::QueryAncestorsResponseChannel(e))?
|
||||||
|
.map_err(|e| Error::QueryAncestors(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Query the session index of a relay parent
|
/// Query the session index of a relay parent
|
||||||
@@ -1046,9 +1110,11 @@ where
|
|||||||
));
|
));
|
||||||
|
|
||||||
ctx.send_message(query_session_idx_for_child)
|
ctx.send_message(query_session_idx_for_child)
|
||||||
.await?;
|
.await
|
||||||
rx.await?
|
.map_err(|e| Error::QuerySessionSendQuery(e))?;
|
||||||
.map_err::<Error, _>(Into::into)
|
rx.await
|
||||||
|
.map_err(|e| Error::QuerySessionResponseChannel(e))?
|
||||||
|
.map_err(|e| Error::QuerySession(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Queries up to k ancestors with the constraints of equiv session
|
/// Queries up to k ancestors with the constraints of equiv session
|
||||||
@@ -1089,7 +1155,6 @@ where
|
|||||||
Ok(acc)
|
Ok(acc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct MetricsInner {
|
struct MetricsInner {
|
||||||
gossipped_availability_chunks: prometheus::Counter<prometheus::U64>,
|
gossipped_availability_chunks: prometheus::Counter<prometheus::U64>,
|
||||||
@@ -1108,12 +1173,14 @@ impl Metrics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl metrics::Metrics for Metrics {
|
impl metrics::Metrics for Metrics {
|
||||||
fn try_register(registry: &prometheus::Registry) -> std::result::Result<Self, prometheus::PrometheusError> {
|
fn try_register(
|
||||||
|
registry: &prometheus::Registry,
|
||||||
|
) -> std::result::Result<Self, prometheus::PrometheusError> {
|
||||||
let metrics = MetricsInner {
|
let metrics = MetricsInner {
|
||||||
gossipped_availability_chunks: prometheus::register(
|
gossipped_availability_chunks: prometheus::register(
|
||||||
prometheus::Counter::new(
|
prometheus::Counter::new(
|
||||||
"parachain_gossipped_availability_chunks_total",
|
"parachain_gossipped_availability_chunks_total",
|
||||||
"Number of availability chunks gossipped to other peers."
|
"Number of availability chunks gossipped to other peers.",
|
||||||
)?,
|
)?,
|
||||||
registry,
|
registry,
|
||||||
)?,
|
)?,
|
||||||
|
|||||||
@@ -17,22 +17,21 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use assert_matches::assert_matches;
|
use assert_matches::assert_matches;
|
||||||
use polkadot_erasure_coding::{branches, obtain_chunks_v1 as obtain_chunks};
|
use polkadot_erasure_coding::{branches, obtain_chunks_v1 as obtain_chunks};
|
||||||
|
use polkadot_node_network_protocol::ObservedRole;
|
||||||
|
use polkadot_node_subsystem_util::TimeoutExt;
|
||||||
use polkadot_primitives::v1::{
|
use polkadot_primitives::v1::{
|
||||||
AvailableData, BlockData, CandidateCommitments, CandidateDescriptor, GroupIndex,
|
AvailableData, BlockData, CandidateCommitments, CandidateDescriptor, GroupIndex,
|
||||||
GroupRotationInfo, HeadData, PersistedValidationData, OccupiedCore,
|
GroupRotationInfo, HeadData, OccupiedCore, PersistedValidationData, PoV, ScheduledCore,
|
||||||
PoV, ScheduledCore,
|
|
||||||
};
|
};
|
||||||
use polkadot_subsystem_testhelpers::{self as test_helpers};
|
use polkadot_subsystem_testhelpers::{self as test_helpers};
|
||||||
use polkadot_node_subsystem_util::TimeoutExt;
|
|
||||||
use polkadot_node_network_protocol::ObservedRole;
|
|
||||||
|
|
||||||
use futures::{executor, future, Future};
|
use futures::{executor, future, Future};
|
||||||
use futures_timer::Delay;
|
use futures_timer::Delay;
|
||||||
use smallvec::smallvec;
|
|
||||||
use std::{sync::Arc, time::Duration};
|
|
||||||
use sc_keystore::LocalKeystore;
|
use sc_keystore::LocalKeystore;
|
||||||
use sp_keystore::{SyncCryptoStorePtr, SyncCryptoStore};
|
use smallvec::smallvec;
|
||||||
use sp_application_crypto::AppKey;
|
use sp_application_crypto::AppKey;
|
||||||
|
use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr};
|
||||||
|
use std::{sync::Arc, time::Duration};
|
||||||
|
|
||||||
macro_rules! view {
|
macro_rules! view {
|
||||||
( $( $hash:expr ),* $(,)? ) => [
|
( $( $hash:expr ),* $(,)? ) => [
|
||||||
@@ -46,9 +45,9 @@ macro_rules! delay {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chunk_protocol_message(message: AvailabilityGossipMessage)
|
fn chunk_protocol_message(
|
||||||
-> protocol_v1::AvailabilityDistributionMessage
|
message: AvailabilityGossipMessage,
|
||||||
{
|
) -> protocol_v1::AvailabilityDistributionMessage {
|
||||||
protocol_v1::AvailabilityDistributionMessage::Chunk(
|
protocol_v1::AvailabilityDistributionMessage::Chunk(
|
||||||
message.candidate_hash,
|
message.candidate_hash,
|
||||||
message.erasure_chunk,
|
message.erasure_chunk,
|
||||||
@@ -175,8 +174,12 @@ impl Default for TestState {
|
|||||||
|
|
||||||
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::in_memory());
|
let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::in_memory());
|
||||||
|
|
||||||
SyncCryptoStore::sr25519_generate_new(&*keystore, ValidatorId::ID, Some(&validators[0].to_seed()))
|
SyncCryptoStore::sr25519_generate_new(
|
||||||
.expect("Insert key into keystore");
|
&*keystore,
|
||||||
|
ValidatorId::ID,
|
||||||
|
Some(&validators[0].to_seed()),
|
||||||
|
)
|
||||||
|
.expect("Insert key into keystore");
|
||||||
|
|
||||||
let validator_public = validator_pubkeys(&validators);
|
let validator_public = validator_pubkeys(&validators);
|
||||||
|
|
||||||
@@ -867,10 +870,7 @@ fn reputation_verification() {
|
|||||||
overseer_send(
|
overseer_send(
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
AvailabilityDistributionMessage::NetworkBridgeUpdateV1(
|
AvailabilityDistributionMessage::NetworkBridgeUpdateV1(
|
||||||
NetworkBridgeEvent::PeerMessage(
|
NetworkBridgeEvent::PeerMessage(peer_a.clone(), chunk_protocol_message(valid2)),
|
||||||
peer_a.clone(),
|
|
||||||
chunk_protocol_message(valid2),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|||||||
@@ -6,17 +6,12 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "0.3.5"
|
futures = "0.3.5"
|
||||||
futures-timer = "3.0.2"
|
log = "0.4.11"
|
||||||
log = "0.4.8"
|
|
||||||
streamunordered = "0.5.1"
|
|
||||||
codec = { package="parity-scale-codec", version = "1.3.4" }
|
codec = { package="parity-scale-codec", version = "1.3.4" }
|
||||||
node-primitives = { package = "polkadot-node-primitives", path = "../../primitives" }
|
|
||||||
polkadot-primitives = { path = "../../../primitives" }
|
polkadot-primitives = { path = "../../../primitives" }
|
||||||
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
|
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
|
||||||
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
||||||
polkadot-network-bridge = { path = "../../network/bridge" }
|
|
||||||
polkadot-node-network-protocol = { path = "../../network/protocol" }
|
polkadot-node-network-protocol = { path = "../../network/protocol" }
|
||||||
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" }
|
polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" }
|
||||||
@@ -25,9 +20,7 @@ sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|||||||
sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
parking_lot = "0.11.0"
|
|
||||||
maplit = "1.0.2"
|
maplit = "1.0.2"
|
||||||
smol = "0.3.3"
|
|
||||||
env_logger = "0.7.1"
|
env_logger = "0.7.1"
|
||||||
assert_matches = "1.3.0"
|
assert_matches = "1.3.0"
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
|
|||||||
@@ -20,8 +20,10 @@
|
|||||||
//! for a particular relay parent.
|
//! for a particular relay parent.
|
||||||
//! Independently of that, gossips on received messages from peers to other interested peers.
|
//! Independently of that, gossips on received messages from peers to other interested peers.
|
||||||
|
|
||||||
|
#![deny(unused_crate_dependencies)]
|
||||||
|
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
use futures::{channel::oneshot, FutureExt};
|
use futures::{channel::oneshot, FutureExt, TryFutureExt};
|
||||||
|
|
||||||
use log::{trace, warn};
|
use log::{trace, warn};
|
||||||
use polkadot_subsystem::messages::*;
|
use polkadot_subsystem::messages::*;
|
||||||
@@ -33,6 +35,7 @@ use polkadot_node_subsystem_util::{
|
|||||||
};
|
};
|
||||||
use polkadot_primitives::v1::{Hash, SignedAvailabilityBitfield, SigningContext, ValidatorId};
|
use polkadot_primitives::v1::{Hash, SignedAvailabilityBitfield, SigningContext, ValidatorId};
|
||||||
use polkadot_node_network_protocol::{v1 as protocol_v1, PeerId, NetworkBridgeEvent, View, ReputationChange};
|
use polkadot_node_network_protocol::{v1 as protocol_v1, PeerId, NetworkBridgeEvent, View, ReputationChange};
|
||||||
|
use polkadot_subsystem::SubsystemError;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
const COST_SIGNATURE_INVALID: ReputationChange =
|
const COST_SIGNATURE_INVALID: ReputationChange =
|
||||||
@@ -578,9 +581,15 @@ where
|
|||||||
C: SubsystemContext<Message = BitfieldDistributionMessage> + Sync + Send,
|
C: SubsystemContext<Message = BitfieldDistributionMessage> + Sync + Send,
|
||||||
{
|
{
|
||||||
fn start(self, ctx: C) -> SpawnedSubsystem {
|
fn start(self, ctx: C) -> SpawnedSubsystem {
|
||||||
|
let future = self.run(ctx)
|
||||||
|
.map_err(|e| {
|
||||||
|
SubsystemError::with_origin("bitfield-distribution", e)
|
||||||
|
})
|
||||||
|
.map(|_| ()).boxed();
|
||||||
|
|
||||||
SpawnedSubsystem {
|
SpawnedSubsystem {
|
||||||
name: "bitfield-distribution-subsystem",
|
name: "bitfield-distribution-subsystem",
|
||||||
future: Box::pin(async move { Self::run(self, ctx) }.map(|_| ())),
|
future,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
futures = "0.3.5"
|
futures = "0.3.5"
|
||||||
log = "0.4.8"
|
log = "0.4.11"
|
||||||
futures-timer = "3.0.2"
|
|
||||||
streamunordered = "0.5.1"
|
|
||||||
polkadot-primitives = { path = "../../../primitives" }
|
polkadot-primitives = { path = "../../../primitives" }
|
||||||
parity-scale-codec = "1.3.4"
|
parity-scale-codec = "1.3.4"
|
||||||
sc-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sc-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
|||||||
@@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
//! The Network Bridge Subsystem - protocol multiplexer for Polkadot.
|
//! The Network Bridge Subsystem - protocol multiplexer for Polkadot.
|
||||||
|
|
||||||
|
#![deny(unused_crate_dependencies, unused_results)]
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
|
|
||||||
use parity_scale_codec::{Encode, Decode};
|
use parity_scale_codec::{Encode, Decode};
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use futures::future::BoxFuture;
|
use futures::future::BoxFuture;
|
||||||
@@ -219,13 +223,19 @@ impl<Net, AD, Context> Subsystem<Context> for NetworkBridge<Net, AD>
|
|||||||
// Swallow error because failure is fatal to the node and we log with more precision
|
// Swallow error because failure is fatal to the node and we log with more precision
|
||||||
// within `run_network`.
|
// within `run_network`.
|
||||||
let Self { network_service, authority_discovery_service } = self;
|
let Self { network_service, authority_discovery_service } = self;
|
||||||
SpawnedSubsystem {
|
let future = run_network(
|
||||||
name: "network-bridge-subsystem",
|
|
||||||
future: run_network(
|
|
||||||
network_service,
|
network_service,
|
||||||
authority_discovery_service,
|
authority_discovery_service,
|
||||||
ctx,
|
ctx,
|
||||||
).map(|_| ()).boxed(),
|
)
|
||||||
|
.map_err(|e| {
|
||||||
|
SubsystemError::with_origin("network-bridge", e)
|
||||||
|
})
|
||||||
|
.map(|_| ())
|
||||||
|
.boxed();
|
||||||
|
SpawnedSubsystem {
|
||||||
|
name: "network-bridge-subsystem",
|
||||||
|
future,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -654,7 +664,7 @@ where
|
|||||||
match peer_map.entry(peer.clone()) {
|
match peer_map.entry(peer.clone()) {
|
||||||
hash_map::Entry::Occupied(_) => continue,
|
hash_map::Entry::Occupied(_) => continue,
|
||||||
hash_map::Entry::Vacant(vacant) => {
|
hash_map::Entry::Vacant(vacant) => {
|
||||||
vacant.insert(PeerData {
|
let _ = vacant.insert(PeerData {
|
||||||
view: View(Vec::new()),
|
view: View(Vec::new()),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -937,7 +947,7 @@ mod tests {
|
|||||||
futures::pin_mut!(test_fut);
|
futures::pin_mut!(test_fut);
|
||||||
futures::pin_mut!(network_bridge);
|
futures::pin_mut!(network_bridge);
|
||||||
|
|
||||||
executor::block_on(future::select(test_fut, network_bridge));
|
let _ = executor::block_on(future::select(test_fut, network_bridge));
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn assert_sends_validation_event_to_all(
|
async fn assert_sends_validation_event_to_all(
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ impl<N: Network, AD: AuthorityDiscovery> Service<N, AD> {
|
|||||||
Err(e) if e.is_disconnected() => {
|
Err(e) if e.is_disconnected() => {
|
||||||
// the request is already revoked
|
// the request is already revoked
|
||||||
for peer_id in validator_ids {
|
for peer_id in validator_ids {
|
||||||
on_revoke(&mut self.requested_validators, peer_id);
|
let _ = on_revoke(&mut self.requested_validators, peer_id);
|
||||||
}
|
}
|
||||||
return (network_service, authority_discovery_service);
|
return (network_service, authority_discovery_service);
|
||||||
}
|
}
|
||||||
@@ -217,7 +217,7 @@ impl<N: Network, AD: AuthorityDiscovery> Service<N, AD> {
|
|||||||
// They are going to be removed soon though:
|
// They are going to be removed soon though:
|
||||||
// https://github.com/paritytech/substrate/issues/6845
|
// https://github.com/paritytech/substrate/issues/6845
|
||||||
for addr in addresses.into_iter().take(MAX_ADDR_PER_PEER) {
|
for addr in addresses.into_iter().take(MAX_ADDR_PER_PEER) {
|
||||||
multiaddr_to_add.insert(addr);
|
let _ = multiaddr_to_add.insert(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,7 +247,7 @@ impl<N: Network, AD: AuthorityDiscovery> Service<N, AD> {
|
|||||||
let result = authority_discovery_service.get_addresses_by_authority_id(id).await;
|
let result = authority_discovery_service.get_addresses_by_authority_id(id).await;
|
||||||
if let Some(addresses) = result {
|
if let Some(addresses) = result {
|
||||||
for addr in addresses.into_iter().take(MAX_ADDR_PER_PEER) {
|
for addr in addresses.into_iter().take(MAX_ADDR_PER_PEER) {
|
||||||
multiaddr_to_remove.insert(addr);
|
let _ = multiaddr_to_remove.insert(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -283,16 +283,16 @@ impl<N: Network, AD: AuthorityDiscovery> Service<N, AD> {
|
|||||||
let maybe_authority = authority_discovery_service.get_authority_id_by_peer_id(peer_id.clone()).await;
|
let maybe_authority = authority_discovery_service.get_authority_id_by_peer_id(peer_id.clone()).await;
|
||||||
if let Some(authority) = maybe_authority {
|
if let Some(authority) = maybe_authority {
|
||||||
for request in self.non_revoked_discovery_requests.iter_mut() {
|
for request in self.non_revoked_discovery_requests.iter_mut() {
|
||||||
request.on_authority_connected(&authority, peer_id);
|
let _ = request.on_authority_connected(&authority, peer_id);
|
||||||
}
|
}
|
||||||
self.connected_validators.insert(authority, peer_id.clone());
|
let _ = self.connected_validators.insert(authority, peer_id.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn on_peer_disconnected(&mut self, peer_id: &PeerId, authority_discovery_service: &mut AD) {
|
pub async fn on_peer_disconnected(&mut self, peer_id: &PeerId, authority_discovery_service: &mut AD) {
|
||||||
let maybe_authority = authority_discovery_service.get_authority_id_by_peer_id(peer_id.clone()).await;
|
let maybe_authority = authority_discovery_service.get_authority_id_by_peer_id(peer_id.clone()).await;
|
||||||
if let Some(authority) = maybe_authority {
|
if let Some(authority) = maybe_authority {
|
||||||
self.connected_validators.remove(&authority);
|
let _ = self.connected_validators.remove(&authority);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,10 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "0.3.5"
|
futures = "0.3.5"
|
||||||
log = "0.4.11"
|
log = "0.4.11"
|
||||||
derive_more = "0.99.9"
|
thiserror = "1.0.21"
|
||||||
|
|
||||||
codec = { package="parity-scale-codec", version = "1.3.4", features = ["std"] }
|
|
||||||
|
|
||||||
polkadot-primitives = { path = "../../../primitives" }
|
polkadot-primitives = { path = "../../../primitives" }
|
||||||
polkadot-network-bridge = { path = "../../network/bridge" }
|
|
||||||
polkadot-node-network-protocol = { path = "../../network/protocol" }
|
polkadot-node-network-protocol = { path = "../../network/protocol" }
|
||||||
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
||||||
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
|
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
|
||||||
@@ -20,7 +18,6 @@ polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsys
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "0.7.1"
|
env_logger = "0.7.1"
|
||||||
assert_matches = "1.3.0"
|
assert_matches = "1.3.0"
|
||||||
smol-timeout = "0.1.0"
|
|
||||||
smallvec = "1.4.2"
|
smallvec = "1.4.2"
|
||||||
futures-timer = "3.0.2"
|
futures-timer = "3.0.2"
|
||||||
|
|
||||||
|
|||||||
@@ -17,11 +17,12 @@
|
|||||||
//! The Collator Protocol allows collators and validators talk to each other.
|
//! The Collator Protocol allows collators and validators talk to each other.
|
||||||
//! This subsystem implements both sides of the collator protocol.
|
//! This subsystem implements both sides of the collator protocol.
|
||||||
|
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs, unused_crate_dependencies)]
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use futures::{channel::oneshot, FutureExt};
|
use futures::{channel::oneshot, FutureExt};
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
use polkadot_subsystem::{
|
use polkadot_subsystem::{
|
||||||
Subsystem, SubsystemContext, SubsystemError, SpawnedSubsystem,
|
Subsystem, SubsystemContext, SubsystemError, SpawnedSubsystem,
|
||||||
@@ -45,18 +46,18 @@ mod validator_side;
|
|||||||
const TARGET: &'static str = "colp";
|
const TARGET: &'static str = "colp";
|
||||||
const REQUEST_TIMEOUT: Duration = Duration::from_secs(1);
|
const REQUEST_TIMEOUT: Duration = Duration::from_secs(1);
|
||||||
|
|
||||||
#[derive(Debug, derive_more::From)]
|
#[derive(Debug, Error)]
|
||||||
enum Error {
|
enum Error {
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Subsystem(SubsystemError),
|
Subsystem(#[from] SubsystemError),
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Oneshot(oneshot::Canceled),
|
Oneshot(#[from] oneshot::Canceled),
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
RuntimeApi(RuntimeApiError),
|
RuntimeApi(#[from] RuntimeApiError),
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
UtilError(util::Error),
|
UtilError(#[from] util::Error),
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Prometheus(prometheus::PrometheusError),
|
Prometheus(#[from] prometheus::PrometheusError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<util::validator_discovery::Error> for Error {
|
impl From<util::validator_discovery::Error> for Error {
|
||||||
@@ -113,7 +114,9 @@ impl CollatorProtocolSubsystem {
|
|||||||
id,
|
id,
|
||||||
metrics,
|
metrics,
|
||||||
).await,
|
).await,
|
||||||
}
|
}.map_err(|e| {
|
||||||
|
SubsystemError::with_origin("collator-protocol", e).into()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,19 +6,13 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "0.3.5"
|
futures = "0.3.5"
|
||||||
log = "0.4.8"
|
log = "0.4.11"
|
||||||
futures-timer = "3.0.2"
|
|
||||||
streamunordered = "0.5.1"
|
|
||||||
polkadot-primitives = { path = "../../../primitives" }
|
polkadot-primitives = { path = "../../../primitives" }
|
||||||
node-primitives = { package = "polkadot-node-primitives", path = "../../primitives" }
|
|
||||||
parity-scale-codec = "1.3.4"
|
|
||||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|
||||||
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
|
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
|
||||||
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
||||||
polkadot-node-network-protocol = { path = "../../network/protocol" }
|
polkadot-node-network-protocol = { path = "../../network/protocol" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
parking_lot = "0.10.0"
|
|
||||||
assert_matches = "1.3.0"
|
assert_matches = "1.3.0"
|
||||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" }
|
polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" }
|
||||||
|
|||||||
@@ -19,9 +19,13 @@
|
|||||||
//! This is a gossip implementation of code that is responsible for distributing PoVs
|
//! This is a gossip implementation of code that is responsible for distributing PoVs
|
||||||
//! among validators.
|
//! among validators.
|
||||||
|
|
||||||
|
#![deny(unused_crate_dependencies)]
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
use polkadot_primitives::v1::{Hash, PoV, CandidateDescriptor};
|
use polkadot_primitives::v1::{Hash, PoV, CandidateDescriptor};
|
||||||
use polkadot_subsystem::{
|
use polkadot_subsystem::{
|
||||||
ActiveLeavesUpdate, OverseerSignal, SubsystemContext, Subsystem, SubsystemResult, FromOverseer, SpawnedSubsystem,
|
ActiveLeavesUpdate, OverseerSignal, SubsystemContext, Subsystem, SubsystemResult, SubsystemError,
|
||||||
|
FromOverseer, SpawnedSubsystem,
|
||||||
messages::{
|
messages::{
|
||||||
PoVDistributionMessage, RuntimeApiMessage, RuntimeApiRequest, AllMessages, NetworkBridgeMessage,
|
PoVDistributionMessage, RuntimeApiMessage, RuntimeApiRequest, AllMessages, NetworkBridgeMessage,
|
||||||
},
|
},
|
||||||
@@ -60,9 +64,13 @@ impl<C> Subsystem<C> for PoVDistribution
|
|||||||
fn start(self, ctx: C) -> SpawnedSubsystem {
|
fn start(self, ctx: C) -> SpawnedSubsystem {
|
||||||
// Swallow error because failure is fatal to the node and we log with more precision
|
// Swallow error because failure is fatal to the node and we log with more precision
|
||||||
// within `run`.
|
// within `run`.
|
||||||
|
let future = self.run(ctx)
|
||||||
|
.map_err(|e| SubsystemError::with_origin("pov-distribution", e))
|
||||||
|
.map(|_| ())
|
||||||
|
.boxed();
|
||||||
SpawnedSubsystem {
|
SpawnedSubsystem {
|
||||||
name: "pov-distribution-subsystem",
|
name: "pov-distribution-subsystem",
|
||||||
future: self.run(ctx).map(|_| ()).boxed(),
|
future,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -608,918 +616,4 @@ impl metrics::Metrics for Metrics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests;
|
||||||
use super::*;
|
|
||||||
use futures::executor;
|
|
||||||
use polkadot_primitives::v1::BlockData;
|
|
||||||
use assert_matches::assert_matches;
|
|
||||||
|
|
||||||
fn make_pov(data: Vec<u8>) -> PoV {
|
|
||||||
PoV { block_data: BlockData(data) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_peer_state(awaited: Vec<(Hash, Vec<Hash>)>)
|
|
||||||
-> PeerState
|
|
||||||
{
|
|
||||||
PeerState {
|
|
||||||
awaited: awaited.into_iter().map(|(rp, h)| (rp, h.into_iter().collect())).collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn distributes_to_those_awaiting_and_completes_local() {
|
|
||||||
let hash_a: Hash = [0; 32].into();
|
|
||||||
let hash_b: Hash = [1; 32].into();
|
|
||||||
|
|
||||||
let peer_a = PeerId::random();
|
|
||||||
let peer_b = PeerId::random();
|
|
||||||
let peer_c = PeerId::random();
|
|
||||||
|
|
||||||
let (pov_send, pov_recv) = oneshot::channel();
|
|
||||||
let pov = make_pov(vec![1, 2, 3]);
|
|
||||||
let pov_hash = pov.hash();
|
|
||||||
|
|
||||||
let mut state = State {
|
|
||||||
relay_parent_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
let mut b = BlockBasedState {
|
|
||||||
known: HashMap::new(),
|
|
||||||
fetching: HashMap::new(),
|
|
||||||
n_validators: 10,
|
|
||||||
};
|
|
||||||
|
|
||||||
b.fetching.insert(pov_hash, vec![pov_send]);
|
|
||||||
s.insert(hash_a, b);
|
|
||||||
s
|
|
||||||
},
|
|
||||||
peer_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
|
|
||||||
// peer A has hash_a in its view and is awaiting the PoV.
|
|
||||||
s.insert(
|
|
||||||
peer_a.clone(),
|
|
||||||
make_peer_state(vec![(hash_a, vec![pov_hash])]),
|
|
||||||
);
|
|
||||||
|
|
||||||
// peer B has hash_a in its view but is not awaiting.
|
|
||||||
s.insert(
|
|
||||||
peer_b.clone(),
|
|
||||||
make_peer_state(vec![(hash_a, vec![])]),
|
|
||||||
);
|
|
||||||
|
|
||||||
// peer C doesn't have hash_a in its view but is awaiting the PoV under hash_b.
|
|
||||||
s.insert(
|
|
||||||
peer_c.clone(),
|
|
||||||
make_peer_state(vec![(hash_b, vec![pov_hash])]),
|
|
||||||
);
|
|
||||||
|
|
||||||
s
|
|
||||||
},
|
|
||||||
our_view: View(vec![hash_a, hash_b]),
|
|
||||||
metrics: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let pool = sp_core::testing::TaskExecutor::new();
|
|
||||||
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
|
||||||
let mut descriptor = CandidateDescriptor::default();
|
|
||||||
descriptor.pov_hash = pov_hash;
|
|
||||||
|
|
||||||
executor::block_on(async move {
|
|
||||||
handle_distribute(
|
|
||||||
&mut state,
|
|
||||||
&mut ctx,
|
|
||||||
hash_a,
|
|
||||||
descriptor,
|
|
||||||
Arc::new(pov.clone()),
|
|
||||||
).await.unwrap();
|
|
||||||
|
|
||||||
assert!(!state.peer_state[&peer_a].awaited[&hash_a].contains(&pov_hash));
|
|
||||||
assert!(state.peer_state[&peer_c].awaited[&hash_b].contains(&pov_hash));
|
|
||||||
|
|
||||||
// our local sender also completed
|
|
||||||
assert_eq!(&*pov_recv.await.unwrap(), &pov);
|
|
||||||
|
|
||||||
assert_matches!(
|
|
||||||
handle.recv().await,
|
|
||||||
AllMessages::NetworkBridge(
|
|
||||||
NetworkBridgeMessage::SendValidationMessage(peers, message)
|
|
||||||
) => {
|
|
||||||
assert_eq!(peers, vec![peer_a.clone()]);
|
|
||||||
assert_eq!(
|
|
||||||
message,
|
|
||||||
send_pov_message(hash_a, pov_hash, pov.clone()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn we_inform_peers_with_same_view_we_are_awaiting() {
|
|
||||||
let hash_a: Hash = [0; 32].into();
|
|
||||||
let hash_b: Hash = [1; 32].into();
|
|
||||||
|
|
||||||
let peer_a = PeerId::random();
|
|
||||||
let peer_b = PeerId::random();
|
|
||||||
|
|
||||||
let (pov_send, _) = oneshot::channel();
|
|
||||||
let pov = make_pov(vec![1, 2, 3]);
|
|
||||||
let pov_hash = pov.hash();
|
|
||||||
|
|
||||||
let mut state = State {
|
|
||||||
relay_parent_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
let b = BlockBasedState {
|
|
||||||
known: HashMap::new(),
|
|
||||||
fetching: HashMap::new(),
|
|
||||||
n_validators: 10,
|
|
||||||
};
|
|
||||||
|
|
||||||
s.insert(hash_a, b);
|
|
||||||
s
|
|
||||||
},
|
|
||||||
peer_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
|
|
||||||
// peer A has hash_a in its view.
|
|
||||||
s.insert(
|
|
||||||
peer_a.clone(),
|
|
||||||
make_peer_state(vec![(hash_a, vec![])]),
|
|
||||||
);
|
|
||||||
|
|
||||||
// peer B doesn't have hash_a in its view.
|
|
||||||
s.insert(
|
|
||||||
peer_b.clone(),
|
|
||||||
make_peer_state(vec![(hash_b, vec![])]),
|
|
||||||
);
|
|
||||||
|
|
||||||
s
|
|
||||||
},
|
|
||||||
our_view: View(vec![hash_a]),
|
|
||||||
metrics: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let pool = sp_core::testing::TaskExecutor::new();
|
|
||||||
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
|
||||||
let mut descriptor = CandidateDescriptor::default();
|
|
||||||
descriptor.pov_hash = pov_hash;
|
|
||||||
|
|
||||||
executor::block_on(async move {
|
|
||||||
handle_fetch(
|
|
||||||
&mut state,
|
|
||||||
&mut ctx,
|
|
||||||
hash_a,
|
|
||||||
descriptor,
|
|
||||||
pov_send,
|
|
||||||
).await.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(state.relay_parent_state[&hash_a].fetching[&pov_hash].len(), 1);
|
|
||||||
|
|
||||||
assert_matches!(
|
|
||||||
handle.recv().await,
|
|
||||||
AllMessages::NetworkBridge(
|
|
||||||
NetworkBridgeMessage::SendValidationMessage(peers, message)
|
|
||||||
) => {
|
|
||||||
assert_eq!(peers, vec![peer_a.clone()]);
|
|
||||||
assert_eq!(
|
|
||||||
message,
|
|
||||||
awaiting_message(hash_a, vec![pov_hash]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn peer_view_change_leads_to_us_informing() {
|
|
||||||
let hash_a: Hash = [0; 32].into();
|
|
||||||
let hash_b: Hash = [1; 32].into();
|
|
||||||
|
|
||||||
let peer_a = PeerId::random();
|
|
||||||
|
|
||||||
let (pov_a_send, _) = oneshot::channel();
|
|
||||||
|
|
||||||
let pov_a = make_pov(vec![1, 2, 3]);
|
|
||||||
let pov_a_hash = pov_a.hash();
|
|
||||||
|
|
||||||
let pov_b = make_pov(vec![4, 5, 6]);
|
|
||||||
let pov_b_hash = pov_b.hash();
|
|
||||||
|
|
||||||
let mut state = State {
|
|
||||||
relay_parent_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
let mut b = BlockBasedState {
|
|
||||||
known: HashMap::new(),
|
|
||||||
fetching: HashMap::new(),
|
|
||||||
n_validators: 10,
|
|
||||||
};
|
|
||||||
|
|
||||||
// pov_a is still being fetched, whereas the fetch of pov_b has already
|
|
||||||
// completed, as implied by the empty vector.
|
|
||||||
b.fetching.insert(pov_a_hash, vec![pov_a_send]);
|
|
||||||
b.fetching.insert(pov_b_hash, vec![]);
|
|
||||||
|
|
||||||
s.insert(hash_a, b);
|
|
||||||
s
|
|
||||||
},
|
|
||||||
peer_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
|
|
||||||
// peer A doesn't yet have hash_a in its view.
|
|
||||||
s.insert(
|
|
||||||
peer_a.clone(),
|
|
||||||
make_peer_state(vec![(hash_b, vec![])]),
|
|
||||||
);
|
|
||||||
|
|
||||||
s
|
|
||||||
},
|
|
||||||
our_view: View(vec![hash_a]),
|
|
||||||
metrics: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let pool = sp_core::testing::TaskExecutor::new();
|
|
||||||
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
|
||||||
|
|
||||||
executor::block_on(async move {
|
|
||||||
handle_network_update(
|
|
||||||
&mut state,
|
|
||||||
&mut ctx,
|
|
||||||
NetworkBridgeEvent::PeerViewChange(peer_a.clone(), View(vec![hash_a, hash_b])),
|
|
||||||
).await.unwrap();
|
|
||||||
|
|
||||||
assert_matches!(
|
|
||||||
handle.recv().await,
|
|
||||||
AllMessages::NetworkBridge(
|
|
||||||
NetworkBridgeMessage::SendValidationMessage(peers, message)
|
|
||||||
) => {
|
|
||||||
assert_eq!(peers, vec![peer_a.clone()]);
|
|
||||||
assert_eq!(
|
|
||||||
message,
|
|
||||||
awaiting_message(hash_a, vec![pov_a_hash]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn peer_complete_fetch_and_is_rewarded() {
|
|
||||||
let hash_a: Hash = [0; 32].into();
|
|
||||||
|
|
||||||
let peer_a = PeerId::random();
|
|
||||||
let peer_b = PeerId::random();
|
|
||||||
|
|
||||||
let (pov_send, pov_recv) = oneshot::channel();
|
|
||||||
|
|
||||||
let pov = make_pov(vec![1, 2, 3]);
|
|
||||||
let pov_hash = pov.hash();
|
|
||||||
|
|
||||||
let mut state = State {
|
|
||||||
relay_parent_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
let mut b = BlockBasedState {
|
|
||||||
known: HashMap::new(),
|
|
||||||
fetching: HashMap::new(),
|
|
||||||
n_validators: 10,
|
|
||||||
};
|
|
||||||
|
|
||||||
// pov is being fetched.
|
|
||||||
b.fetching.insert(pov_hash, vec![pov_send]);
|
|
||||||
|
|
||||||
s.insert(hash_a, b);
|
|
||||||
s
|
|
||||||
},
|
|
||||||
peer_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
|
|
||||||
// peers A and B are functionally the same.
|
|
||||||
s.insert(
|
|
||||||
peer_a.clone(),
|
|
||||||
make_peer_state(vec![(hash_a, vec![])]),
|
|
||||||
);
|
|
||||||
|
|
||||||
s.insert(
|
|
||||||
peer_b.clone(),
|
|
||||||
make_peer_state(vec![(hash_a, vec![])]),
|
|
||||||
);
|
|
||||||
|
|
||||||
s
|
|
||||||
},
|
|
||||||
our_view: View(vec![hash_a]),
|
|
||||||
metrics: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let pool = sp_core::testing::TaskExecutor::new();
|
|
||||||
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
|
||||||
|
|
||||||
executor::block_on(async move {
|
|
||||||
// Peer A answers our request before peer B.
|
|
||||||
handle_network_update(
|
|
||||||
&mut state,
|
|
||||||
&mut ctx,
|
|
||||||
NetworkBridgeEvent::PeerMessage(
|
|
||||||
peer_a.clone(),
|
|
||||||
send_pov_message(hash_a, pov_hash, pov.clone()),
|
|
||||||
).focus().unwrap(),
|
|
||||||
).await.unwrap();
|
|
||||||
|
|
||||||
handle_network_update(
|
|
||||||
&mut state,
|
|
||||||
&mut ctx,
|
|
||||||
NetworkBridgeEvent::PeerMessage(
|
|
||||||
peer_b.clone(),
|
|
||||||
send_pov_message(hash_a, pov_hash, pov.clone()),
|
|
||||||
).focus().unwrap(),
|
|
||||||
).await.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(&*pov_recv.await.unwrap(), &pov);
|
|
||||||
|
|
||||||
assert_matches!(
|
|
||||||
handle.recv().await,
|
|
||||||
AllMessages::NetworkBridge(
|
|
||||||
NetworkBridgeMessage::ReportPeer(peer, rep)
|
|
||||||
) => {
|
|
||||||
assert_eq!(peer, peer_a);
|
|
||||||
assert_eq!(rep, BENEFIT_FRESH_POV);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_matches!(
|
|
||||||
handle.recv().await,
|
|
||||||
AllMessages::NetworkBridge(
|
|
||||||
NetworkBridgeMessage::ReportPeer(peer, rep)
|
|
||||||
) => {
|
|
||||||
assert_eq!(peer, peer_b);
|
|
||||||
assert_eq!(rep, BENEFIT_LATE_POV);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn peer_punished_for_sending_bad_pov() {
|
|
||||||
let hash_a: Hash = [0; 32].into();
|
|
||||||
|
|
||||||
let peer_a = PeerId::random();
|
|
||||||
|
|
||||||
let (pov_send, _) = oneshot::channel();
|
|
||||||
|
|
||||||
let pov = make_pov(vec![1, 2, 3]);
|
|
||||||
let pov_hash = pov.hash();
|
|
||||||
|
|
||||||
let bad_pov = make_pov(vec![6, 6, 6]);
|
|
||||||
|
|
||||||
let mut state = State {
|
|
||||||
relay_parent_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
let mut b = BlockBasedState {
|
|
||||||
known: HashMap::new(),
|
|
||||||
fetching: HashMap::new(),
|
|
||||||
n_validators: 10,
|
|
||||||
};
|
|
||||||
|
|
||||||
// pov is being fetched.
|
|
||||||
b.fetching.insert(pov_hash, vec![pov_send]);
|
|
||||||
|
|
||||||
s.insert(hash_a, b);
|
|
||||||
s
|
|
||||||
},
|
|
||||||
peer_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
|
|
||||||
s.insert(
|
|
||||||
peer_a.clone(),
|
|
||||||
make_peer_state(vec![(hash_a, vec![])]),
|
|
||||||
);
|
|
||||||
|
|
||||||
s
|
|
||||||
},
|
|
||||||
our_view: View(vec![hash_a]),
|
|
||||||
metrics: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let pool = sp_core::testing::TaskExecutor::new();
|
|
||||||
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
|
||||||
|
|
||||||
executor::block_on(async move {
|
|
||||||
// Peer A answers our request: right relay parent, awaited hash, wrong PoV.
|
|
||||||
handle_network_update(
|
|
||||||
&mut state,
|
|
||||||
&mut ctx,
|
|
||||||
NetworkBridgeEvent::PeerMessage(
|
|
||||||
peer_a.clone(),
|
|
||||||
send_pov_message(hash_a, pov_hash, bad_pov.clone()),
|
|
||||||
).focus().unwrap(),
|
|
||||||
).await.unwrap();
|
|
||||||
|
|
||||||
// didn't complete our sender.
|
|
||||||
assert_eq!(state.relay_parent_state[&hash_a].fetching[&pov_hash].len(), 1);
|
|
||||||
|
|
||||||
assert_matches!(
|
|
||||||
handle.recv().await,
|
|
||||||
AllMessages::NetworkBridge(
|
|
||||||
NetworkBridgeMessage::ReportPeer(peer, rep)
|
|
||||||
) => {
|
|
||||||
assert_eq!(peer, peer_a);
|
|
||||||
assert_eq!(rep, COST_UNEXPECTED_POV);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn peer_punished_for_sending_unexpected_pov() {
|
|
||||||
let hash_a: Hash = [0; 32].into();
|
|
||||||
|
|
||||||
let peer_a = PeerId::random();
|
|
||||||
|
|
||||||
let pov = make_pov(vec![1, 2, 3]);
|
|
||||||
let pov_hash = pov.hash();
|
|
||||||
|
|
||||||
let mut state = State {
|
|
||||||
relay_parent_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
let b = BlockBasedState {
|
|
||||||
known: HashMap::new(),
|
|
||||||
fetching: HashMap::new(),
|
|
||||||
n_validators: 10,
|
|
||||||
};
|
|
||||||
|
|
||||||
s.insert(hash_a, b);
|
|
||||||
s
|
|
||||||
},
|
|
||||||
peer_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
|
|
||||||
s.insert(
|
|
||||||
peer_a.clone(),
|
|
||||||
make_peer_state(vec![(hash_a, vec![])]),
|
|
||||||
);
|
|
||||||
|
|
||||||
s
|
|
||||||
},
|
|
||||||
our_view: View(vec![hash_a]),
|
|
||||||
metrics: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let pool = sp_core::testing::TaskExecutor::new();
|
|
||||||
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
|
||||||
|
|
||||||
executor::block_on(async move {
|
|
||||||
// Peer A answers our request: right relay parent, awaited hash, wrong PoV.
|
|
||||||
handle_network_update(
|
|
||||||
&mut state,
|
|
||||||
&mut ctx,
|
|
||||||
NetworkBridgeEvent::PeerMessage(
|
|
||||||
peer_a.clone(),
|
|
||||||
send_pov_message(hash_a, pov_hash, pov.clone()),
|
|
||||||
).focus().unwrap(),
|
|
||||||
).await.unwrap();
|
|
||||||
|
|
||||||
assert_matches!(
|
|
||||||
handle.recv().await,
|
|
||||||
AllMessages::NetworkBridge(
|
|
||||||
NetworkBridgeMessage::ReportPeer(peer, rep)
|
|
||||||
) => {
|
|
||||||
assert_eq!(peer, peer_a);
|
|
||||||
assert_eq!(rep, COST_UNEXPECTED_POV);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn peer_punished_for_sending_pov_out_of_our_view() {
|
|
||||||
let hash_a: Hash = [0; 32].into();
|
|
||||||
let hash_b: Hash = [1; 32].into();
|
|
||||||
|
|
||||||
let peer_a = PeerId::random();
|
|
||||||
|
|
||||||
let pov = make_pov(vec![1, 2, 3]);
|
|
||||||
let pov_hash = pov.hash();
|
|
||||||
|
|
||||||
let mut state = State {
|
|
||||||
relay_parent_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
let b = BlockBasedState {
|
|
||||||
known: HashMap::new(),
|
|
||||||
fetching: HashMap::new(),
|
|
||||||
n_validators: 10,
|
|
||||||
};
|
|
||||||
|
|
||||||
s.insert(hash_a, b);
|
|
||||||
s
|
|
||||||
},
|
|
||||||
peer_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
|
|
||||||
s.insert(
|
|
||||||
peer_a.clone(),
|
|
||||||
make_peer_state(vec![(hash_a, vec![])]),
|
|
||||||
);
|
|
||||||
|
|
||||||
s
|
|
||||||
},
|
|
||||||
our_view: View(vec![hash_a]),
|
|
||||||
metrics: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let pool = sp_core::testing::TaskExecutor::new();
|
|
||||||
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
|
||||||
|
|
||||||
executor::block_on(async move {
|
|
||||||
// Peer A answers our request: right relay parent, awaited hash, wrong PoV.
|
|
||||||
handle_network_update(
|
|
||||||
&mut state,
|
|
||||||
&mut ctx,
|
|
||||||
NetworkBridgeEvent::PeerMessage(
|
|
||||||
peer_a.clone(),
|
|
||||||
send_pov_message(hash_b, pov_hash, pov.clone()),
|
|
||||||
).focus().unwrap(),
|
|
||||||
).await.unwrap();
|
|
||||||
|
|
||||||
assert_matches!(
|
|
||||||
handle.recv().await,
|
|
||||||
AllMessages::NetworkBridge(
|
|
||||||
NetworkBridgeMessage::ReportPeer(peer, rep)
|
|
||||||
) => {
|
|
||||||
assert_eq!(peer, peer_a);
|
|
||||||
assert_eq!(rep, COST_UNEXPECTED_POV);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn peer_reported_for_awaiting_too_much() {
|
|
||||||
let hash_a: Hash = [0; 32].into();
|
|
||||||
|
|
||||||
let peer_a = PeerId::random();
|
|
||||||
let n_validators = 10;
|
|
||||||
|
|
||||||
let mut state = State {
|
|
||||||
relay_parent_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
let b = BlockBasedState {
|
|
||||||
known: HashMap::new(),
|
|
||||||
fetching: HashMap::new(),
|
|
||||||
n_validators,
|
|
||||||
};
|
|
||||||
|
|
||||||
s.insert(hash_a, b);
|
|
||||||
s
|
|
||||||
},
|
|
||||||
peer_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
|
|
||||||
s.insert(
|
|
||||||
peer_a.clone(),
|
|
||||||
make_peer_state(vec![(hash_a, vec![])]),
|
|
||||||
);
|
|
||||||
|
|
||||||
s
|
|
||||||
},
|
|
||||||
our_view: View(vec![hash_a]),
|
|
||||||
metrics: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let pool = sp_core::testing::TaskExecutor::new();
|
|
||||||
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
|
||||||
|
|
||||||
executor::block_on(async move {
|
|
||||||
let max_plausibly_awaited = n_validators * 2;
|
|
||||||
|
|
||||||
// The peer awaits a plausible (albeit unlikely) amount of PoVs.
|
|
||||||
for i in 0..max_plausibly_awaited {
|
|
||||||
let pov_hash = make_pov(vec![i as u8; 32]).hash();
|
|
||||||
handle_network_update(
|
|
||||||
&mut state,
|
|
||||||
&mut ctx,
|
|
||||||
NetworkBridgeEvent::PeerMessage(
|
|
||||||
peer_a.clone(),
|
|
||||||
awaiting_message(hash_a, vec![pov_hash]),
|
|
||||||
).focus().unwrap(),
|
|
||||||
).await.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(state.peer_state[&peer_a].awaited[&hash_a].len(), max_plausibly_awaited);
|
|
||||||
|
|
||||||
// The last straw:
|
|
||||||
let last_pov_hash = make_pov(vec![max_plausibly_awaited as u8; 32]).hash();
|
|
||||||
handle_network_update(
|
|
||||||
&mut state,
|
|
||||||
&mut ctx,
|
|
||||||
NetworkBridgeEvent::PeerMessage(
|
|
||||||
peer_a.clone(),
|
|
||||||
awaiting_message(hash_a, vec![last_pov_hash]),
|
|
||||||
).focus().unwrap(),
|
|
||||||
).await.unwrap();
|
|
||||||
|
|
||||||
// No more bookkeeping for you!
|
|
||||||
assert_eq!(state.peer_state[&peer_a].awaited[&hash_a].len(), max_plausibly_awaited);
|
|
||||||
|
|
||||||
assert_matches!(
|
|
||||||
handle.recv().await,
|
|
||||||
AllMessages::NetworkBridge(
|
|
||||||
NetworkBridgeMessage::ReportPeer(peer, rep)
|
|
||||||
) => {
|
|
||||||
assert_eq!(peer, peer_a);
|
|
||||||
assert_eq!(rep, COST_APPARENT_FLOOD);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn peer_reported_for_awaiting_outside_their_view() {
|
|
||||||
let hash_a: Hash = [0; 32].into();
|
|
||||||
let hash_b: Hash = [1; 32].into();
|
|
||||||
|
|
||||||
let peer_a = PeerId::random();
|
|
||||||
|
|
||||||
let mut state = State {
|
|
||||||
relay_parent_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
s.insert(hash_a, BlockBasedState {
|
|
||||||
known: HashMap::new(),
|
|
||||||
fetching: HashMap::new(),
|
|
||||||
n_validators: 10,
|
|
||||||
});
|
|
||||||
|
|
||||||
s.insert(hash_b, BlockBasedState {
|
|
||||||
known: HashMap::new(),
|
|
||||||
fetching: HashMap::new(),
|
|
||||||
n_validators: 10,
|
|
||||||
});
|
|
||||||
|
|
||||||
s
|
|
||||||
},
|
|
||||||
peer_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
|
|
||||||
// Peer has only hash A in its view.
|
|
||||||
s.insert(
|
|
||||||
peer_a.clone(),
|
|
||||||
make_peer_state(vec![(hash_a, vec![])]),
|
|
||||||
);
|
|
||||||
|
|
||||||
s
|
|
||||||
},
|
|
||||||
our_view: View(vec![hash_a, hash_b]),
|
|
||||||
metrics: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let pool = sp_core::testing::TaskExecutor::new();
|
|
||||||
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
|
||||||
|
|
||||||
executor::block_on(async move {
|
|
||||||
let pov_hash = make_pov(vec![1, 2, 3]).hash();
|
|
||||||
|
|
||||||
// Hash B is in our view but not the peer's
|
|
||||||
handle_network_update(
|
|
||||||
&mut state,
|
|
||||||
&mut ctx,
|
|
||||||
NetworkBridgeEvent::PeerMessage(
|
|
||||||
peer_a.clone(),
|
|
||||||
awaiting_message(hash_b, vec![pov_hash]),
|
|
||||||
).focus().unwrap(),
|
|
||||||
).await.unwrap();
|
|
||||||
|
|
||||||
assert!(state.peer_state[&peer_a].awaited.get(&hash_b).is_none());
|
|
||||||
|
|
||||||
assert_matches!(
|
|
||||||
handle.recv().await,
|
|
||||||
AllMessages::NetworkBridge(
|
|
||||||
NetworkBridgeMessage::ReportPeer(peer, rep)
|
|
||||||
) => {
|
|
||||||
assert_eq!(peer, peer_a);
|
|
||||||
assert_eq!(rep, COST_AWAITED_NOT_IN_VIEW);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn peer_reported_for_awaiting_outside_our_view() {
|
|
||||||
let hash_a: Hash = [0; 32].into();
|
|
||||||
let hash_b: Hash = [1; 32].into();
|
|
||||||
|
|
||||||
let peer_a = PeerId::random();
|
|
||||||
|
|
||||||
let mut state = State {
|
|
||||||
relay_parent_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
s.insert(hash_a, BlockBasedState {
|
|
||||||
known: HashMap::new(),
|
|
||||||
fetching: HashMap::new(),
|
|
||||||
n_validators: 10,
|
|
||||||
});
|
|
||||||
|
|
||||||
s
|
|
||||||
},
|
|
||||||
peer_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
|
|
||||||
// Peer has hashes A and B in their view.
|
|
||||||
s.insert(
|
|
||||||
peer_a.clone(),
|
|
||||||
make_peer_state(vec![(hash_a, vec![]), (hash_b, vec![])]),
|
|
||||||
);
|
|
||||||
|
|
||||||
s
|
|
||||||
},
|
|
||||||
our_view: View(vec![hash_a]),
|
|
||||||
metrics: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let pool = sp_core::testing::TaskExecutor::new();
|
|
||||||
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
|
||||||
|
|
||||||
executor::block_on(async move {
|
|
||||||
let pov_hash = make_pov(vec![1, 2, 3]).hash();
|
|
||||||
|
|
||||||
// Hash B is in peer's view but not ours.
|
|
||||||
handle_network_update(
|
|
||||||
&mut state,
|
|
||||||
&mut ctx,
|
|
||||||
NetworkBridgeEvent::PeerMessage(
|
|
||||||
peer_a.clone(),
|
|
||||||
awaiting_message(hash_b, vec![pov_hash]),
|
|
||||||
).focus().unwrap(),
|
|
||||||
).await.unwrap();
|
|
||||||
|
|
||||||
// Illegal `awaited` is ignored.
|
|
||||||
assert!(state.peer_state[&peer_a].awaited[&hash_b].is_empty());
|
|
||||||
|
|
||||||
assert_matches!(
|
|
||||||
handle.recv().await,
|
|
||||||
AllMessages::NetworkBridge(
|
|
||||||
NetworkBridgeMessage::ReportPeer(peer, rep)
|
|
||||||
) => {
|
|
||||||
assert_eq!(peer, peer_a);
|
|
||||||
assert_eq!(rep, COST_AWAITED_NOT_IN_VIEW);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn peer_complete_fetch_leads_to_us_completing_others() {
|
|
||||||
let hash_a: Hash = [0; 32].into();
|
|
||||||
|
|
||||||
let peer_a = PeerId::random();
|
|
||||||
let peer_b = PeerId::random();
|
|
||||||
|
|
||||||
let (pov_send, pov_recv) = oneshot::channel();
|
|
||||||
|
|
||||||
let pov = make_pov(vec![1, 2, 3]);
|
|
||||||
let pov_hash = pov.hash();
|
|
||||||
|
|
||||||
let mut state = State {
|
|
||||||
relay_parent_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
let mut b = BlockBasedState {
|
|
||||||
known: HashMap::new(),
|
|
||||||
fetching: HashMap::new(),
|
|
||||||
n_validators: 10,
|
|
||||||
};
|
|
||||||
|
|
||||||
// pov is being fetched.
|
|
||||||
b.fetching.insert(pov_hash, vec![pov_send]);
|
|
||||||
|
|
||||||
s.insert(hash_a, b);
|
|
||||||
s
|
|
||||||
},
|
|
||||||
peer_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
|
|
||||||
s.insert(
|
|
||||||
peer_a.clone(),
|
|
||||||
make_peer_state(vec![(hash_a, vec![])]),
|
|
||||||
);
|
|
||||||
|
|
||||||
// peer B is awaiting peer A's request.
|
|
||||||
s.insert(
|
|
||||||
peer_b.clone(),
|
|
||||||
make_peer_state(vec![(hash_a, vec![pov_hash])]),
|
|
||||||
);
|
|
||||||
|
|
||||||
s
|
|
||||||
},
|
|
||||||
our_view: View(vec![hash_a]),
|
|
||||||
metrics: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let pool = sp_core::testing::TaskExecutor::new();
|
|
||||||
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
|
||||||
|
|
||||||
executor::block_on(async move {
|
|
||||||
handle_network_update(
|
|
||||||
&mut state,
|
|
||||||
&mut ctx,
|
|
||||||
NetworkBridgeEvent::PeerMessage(
|
|
||||||
peer_a.clone(),
|
|
||||||
send_pov_message(hash_a, pov_hash, pov.clone()),
|
|
||||||
).focus().unwrap(),
|
|
||||||
).await.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(&*pov_recv.await.unwrap(), &pov);
|
|
||||||
|
|
||||||
assert_matches!(
|
|
||||||
handle.recv().await,
|
|
||||||
AllMessages::NetworkBridge(
|
|
||||||
NetworkBridgeMessage::ReportPeer(peer, rep)
|
|
||||||
) => {
|
|
||||||
assert_eq!(peer, peer_a);
|
|
||||||
assert_eq!(rep, BENEFIT_FRESH_POV);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_matches!(
|
|
||||||
handle.recv().await,
|
|
||||||
AllMessages::NetworkBridge(
|
|
||||||
NetworkBridgeMessage::SendValidationMessage(peers, message)
|
|
||||||
) => {
|
|
||||||
assert_eq!(peers, vec![peer_b.clone()]);
|
|
||||||
assert_eq!(
|
|
||||||
message,
|
|
||||||
send_pov_message(hash_a, pov_hash, pov.clone()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(!state.peer_state[&peer_b].awaited[&hash_a].contains(&pov_hash));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn peer_completing_request_no_longer_awaiting() {
|
|
||||||
let hash_a: Hash = [0; 32].into();
|
|
||||||
|
|
||||||
let peer_a = PeerId::random();
|
|
||||||
|
|
||||||
let (pov_send, pov_recv) = oneshot::channel();
|
|
||||||
|
|
||||||
let pov = make_pov(vec![1, 2, 3]);
|
|
||||||
let pov_hash = pov.hash();
|
|
||||||
|
|
||||||
let mut state = State {
|
|
||||||
relay_parent_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
let mut b = BlockBasedState {
|
|
||||||
known: HashMap::new(),
|
|
||||||
fetching: HashMap::new(),
|
|
||||||
n_validators: 10,
|
|
||||||
};
|
|
||||||
|
|
||||||
// pov is being fetched.
|
|
||||||
b.fetching.insert(pov_hash, vec![pov_send]);
|
|
||||||
|
|
||||||
s.insert(hash_a, b);
|
|
||||||
s
|
|
||||||
},
|
|
||||||
peer_state: {
|
|
||||||
let mut s = HashMap::new();
|
|
||||||
|
|
||||||
// peer A is registered as awaiting.
|
|
||||||
s.insert(
|
|
||||||
peer_a.clone(),
|
|
||||||
make_peer_state(vec![(hash_a, vec![pov_hash])]),
|
|
||||||
);
|
|
||||||
|
|
||||||
s
|
|
||||||
},
|
|
||||||
our_view: View(vec![hash_a]),
|
|
||||||
metrics: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let pool = sp_core::testing::TaskExecutor::new();
|
|
||||||
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
|
||||||
|
|
||||||
executor::block_on(async move {
|
|
||||||
handle_network_update(
|
|
||||||
&mut state,
|
|
||||||
&mut ctx,
|
|
||||||
NetworkBridgeEvent::PeerMessage(
|
|
||||||
peer_a.clone(),
|
|
||||||
send_pov_message(hash_a, pov_hash, pov.clone()),
|
|
||||||
).focus().unwrap(),
|
|
||||||
).await.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(&*pov_recv.await.unwrap(), &pov);
|
|
||||||
|
|
||||||
assert_matches!(
|
|
||||||
handle.recv().await,
|
|
||||||
AllMessages::NetworkBridge(
|
|
||||||
NetworkBridgeMessage::ReportPeer(peer, rep)
|
|
||||||
) => {
|
|
||||||
assert_eq!(peer, peer_a);
|
|
||||||
assert_eq!(rep, BENEFIT_FRESH_POV);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// We received the PoV from peer A, so we do not consider it awaited by peer A anymore.
|
|
||||||
assert!(!state.peer_state[&peer_a].awaited[&hash_a].contains(&pov_hash));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,913 @@
|
|||||||
|
use super::*;
|
||||||
|
use futures::executor;
|
||||||
|
use polkadot_primitives::v1::BlockData;
|
||||||
|
use assert_matches::assert_matches;
|
||||||
|
|
||||||
|
fn make_pov(data: Vec<u8>) -> PoV {
|
||||||
|
PoV { block_data: BlockData(data) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_peer_state(awaited: Vec<(Hash, Vec<Hash>)>)
|
||||||
|
-> PeerState
|
||||||
|
{
|
||||||
|
PeerState {
|
||||||
|
awaited: awaited.into_iter().map(|(rp, h)| (rp, h.into_iter().collect())).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn distributes_to_those_awaiting_and_completes_local() {
|
||||||
|
let hash_a: Hash = [0; 32].into();
|
||||||
|
let hash_b: Hash = [1; 32].into();
|
||||||
|
|
||||||
|
let peer_a = PeerId::random();
|
||||||
|
let peer_b = PeerId::random();
|
||||||
|
let peer_c = PeerId::random();
|
||||||
|
|
||||||
|
let (pov_send, pov_recv) = oneshot::channel();
|
||||||
|
let pov = make_pov(vec![1, 2, 3]);
|
||||||
|
let pov_hash = pov.hash();
|
||||||
|
|
||||||
|
let mut state = State {
|
||||||
|
relay_parent_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
let mut b = BlockBasedState {
|
||||||
|
known: HashMap::new(),
|
||||||
|
fetching: HashMap::new(),
|
||||||
|
n_validators: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
b.fetching.insert(pov_hash, vec![pov_send]);
|
||||||
|
s.insert(hash_a, b);
|
||||||
|
s
|
||||||
|
},
|
||||||
|
peer_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
|
||||||
|
// peer A has hash_a in its view and is awaiting the PoV.
|
||||||
|
s.insert(
|
||||||
|
peer_a.clone(),
|
||||||
|
make_peer_state(vec![(hash_a, vec![pov_hash])]),
|
||||||
|
);
|
||||||
|
|
||||||
|
// peer B has hash_a in its view but is not awaiting.
|
||||||
|
s.insert(
|
||||||
|
peer_b.clone(),
|
||||||
|
make_peer_state(vec![(hash_a, vec![])]),
|
||||||
|
);
|
||||||
|
|
||||||
|
// peer C doesn't have hash_a in its view but is awaiting the PoV under hash_b.
|
||||||
|
s.insert(
|
||||||
|
peer_c.clone(),
|
||||||
|
make_peer_state(vec![(hash_b, vec![pov_hash])]),
|
||||||
|
);
|
||||||
|
|
||||||
|
s
|
||||||
|
},
|
||||||
|
our_view: View(vec![hash_a, hash_b]),
|
||||||
|
metrics: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pool = sp_core::testing::TaskExecutor::new();
|
||||||
|
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
||||||
|
let mut descriptor = CandidateDescriptor::default();
|
||||||
|
descriptor.pov_hash = pov_hash;
|
||||||
|
|
||||||
|
executor::block_on(async move {
|
||||||
|
handle_distribute(
|
||||||
|
&mut state,
|
||||||
|
&mut ctx,
|
||||||
|
hash_a,
|
||||||
|
descriptor,
|
||||||
|
Arc::new(pov.clone()),
|
||||||
|
).await.unwrap();
|
||||||
|
|
||||||
|
assert!(!state.peer_state[&peer_a].awaited[&hash_a].contains(&pov_hash));
|
||||||
|
assert!(state.peer_state[&peer_c].awaited[&hash_b].contains(&pov_hash));
|
||||||
|
|
||||||
|
// our local sender also completed
|
||||||
|
assert_eq!(&*pov_recv.await.unwrap(), &pov);
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
handle.recv().await,
|
||||||
|
AllMessages::NetworkBridge(
|
||||||
|
NetworkBridgeMessage::SendValidationMessage(peers, message)
|
||||||
|
) => {
|
||||||
|
assert_eq!(peers, vec![peer_a.clone()]);
|
||||||
|
assert_eq!(
|
||||||
|
message,
|
||||||
|
send_pov_message(hash_a, pov_hash, pov.clone()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn we_inform_peers_with_same_view_we_are_awaiting() {
|
||||||
|
let hash_a: Hash = [0; 32].into();
|
||||||
|
let hash_b: Hash = [1; 32].into();
|
||||||
|
|
||||||
|
let peer_a = PeerId::random();
|
||||||
|
let peer_b = PeerId::random();
|
||||||
|
|
||||||
|
let (pov_send, _) = oneshot::channel();
|
||||||
|
let pov = make_pov(vec![1, 2, 3]);
|
||||||
|
let pov_hash = pov.hash();
|
||||||
|
|
||||||
|
let mut state = State {
|
||||||
|
relay_parent_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
let b = BlockBasedState {
|
||||||
|
known: HashMap::new(),
|
||||||
|
fetching: HashMap::new(),
|
||||||
|
n_validators: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
s.insert(hash_a, b);
|
||||||
|
s
|
||||||
|
},
|
||||||
|
peer_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
|
||||||
|
// peer A has hash_a in its view.
|
||||||
|
s.insert(
|
||||||
|
peer_a.clone(),
|
||||||
|
make_peer_state(vec![(hash_a, vec![])]),
|
||||||
|
);
|
||||||
|
|
||||||
|
// peer B doesn't have hash_a in its view.
|
||||||
|
s.insert(
|
||||||
|
peer_b.clone(),
|
||||||
|
make_peer_state(vec![(hash_b, vec![])]),
|
||||||
|
);
|
||||||
|
|
||||||
|
s
|
||||||
|
},
|
||||||
|
our_view: View(vec![hash_a]),
|
||||||
|
metrics: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pool = sp_core::testing::TaskExecutor::new();
|
||||||
|
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
||||||
|
let mut descriptor = CandidateDescriptor::default();
|
||||||
|
descriptor.pov_hash = pov_hash;
|
||||||
|
|
||||||
|
executor::block_on(async move {
|
||||||
|
handle_fetch(
|
||||||
|
&mut state,
|
||||||
|
&mut ctx,
|
||||||
|
hash_a,
|
||||||
|
descriptor,
|
||||||
|
pov_send,
|
||||||
|
).await.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(state.relay_parent_state[&hash_a].fetching[&pov_hash].len(), 1);
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
handle.recv().await,
|
||||||
|
AllMessages::NetworkBridge(
|
||||||
|
NetworkBridgeMessage::SendValidationMessage(peers, message)
|
||||||
|
) => {
|
||||||
|
assert_eq!(peers, vec![peer_a.clone()]);
|
||||||
|
assert_eq!(
|
||||||
|
message,
|
||||||
|
awaiting_message(hash_a, vec![pov_hash]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn peer_view_change_leads_to_us_informing() {
|
||||||
|
let hash_a: Hash = [0; 32].into();
|
||||||
|
let hash_b: Hash = [1; 32].into();
|
||||||
|
|
||||||
|
let peer_a = PeerId::random();
|
||||||
|
|
||||||
|
let (pov_a_send, _) = oneshot::channel();
|
||||||
|
|
||||||
|
let pov_a = make_pov(vec![1, 2, 3]);
|
||||||
|
let pov_a_hash = pov_a.hash();
|
||||||
|
|
||||||
|
let pov_b = make_pov(vec![4, 5, 6]);
|
||||||
|
let pov_b_hash = pov_b.hash();
|
||||||
|
|
||||||
|
let mut state = State {
|
||||||
|
relay_parent_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
let mut b = BlockBasedState {
|
||||||
|
known: HashMap::new(),
|
||||||
|
fetching: HashMap::new(),
|
||||||
|
n_validators: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
// pov_a is still being fetched, whereas the fetch of pov_b has already
|
||||||
|
// completed, as implied by the empty vector.
|
||||||
|
b.fetching.insert(pov_a_hash, vec![pov_a_send]);
|
||||||
|
b.fetching.insert(pov_b_hash, vec![]);
|
||||||
|
|
||||||
|
s.insert(hash_a, b);
|
||||||
|
s
|
||||||
|
},
|
||||||
|
peer_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
|
||||||
|
// peer A doesn't yet have hash_a in its view.
|
||||||
|
s.insert(
|
||||||
|
peer_a.clone(),
|
||||||
|
make_peer_state(vec![(hash_b, vec![])]),
|
||||||
|
);
|
||||||
|
|
||||||
|
s
|
||||||
|
},
|
||||||
|
our_view: View(vec![hash_a]),
|
||||||
|
metrics: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pool = sp_core::testing::TaskExecutor::new();
|
||||||
|
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
||||||
|
|
||||||
|
executor::block_on(async move {
|
||||||
|
handle_network_update(
|
||||||
|
&mut state,
|
||||||
|
&mut ctx,
|
||||||
|
NetworkBridgeEvent::PeerViewChange(peer_a.clone(), View(vec![hash_a, hash_b])),
|
||||||
|
).await.unwrap();
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
handle.recv().await,
|
||||||
|
AllMessages::NetworkBridge(
|
||||||
|
NetworkBridgeMessage::SendValidationMessage(peers, message)
|
||||||
|
) => {
|
||||||
|
assert_eq!(peers, vec![peer_a.clone()]);
|
||||||
|
assert_eq!(
|
||||||
|
message,
|
||||||
|
awaiting_message(hash_a, vec![pov_a_hash]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn peer_complete_fetch_and_is_rewarded() {
|
||||||
|
let hash_a: Hash = [0; 32].into();
|
||||||
|
|
||||||
|
let peer_a = PeerId::random();
|
||||||
|
let peer_b = PeerId::random();
|
||||||
|
|
||||||
|
let (pov_send, pov_recv) = oneshot::channel();
|
||||||
|
|
||||||
|
let pov = make_pov(vec![1, 2, 3]);
|
||||||
|
let pov_hash = pov.hash();
|
||||||
|
|
||||||
|
let mut state = State {
|
||||||
|
relay_parent_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
let mut b = BlockBasedState {
|
||||||
|
known: HashMap::new(),
|
||||||
|
fetching: HashMap::new(),
|
||||||
|
n_validators: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
// pov is being fetched.
|
||||||
|
b.fetching.insert(pov_hash, vec![pov_send]);
|
||||||
|
|
||||||
|
s.insert(hash_a, b);
|
||||||
|
s
|
||||||
|
},
|
||||||
|
peer_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
|
||||||
|
// peers A and B are functionally the same.
|
||||||
|
s.insert(
|
||||||
|
peer_a.clone(),
|
||||||
|
make_peer_state(vec![(hash_a, vec![])]),
|
||||||
|
);
|
||||||
|
|
||||||
|
s.insert(
|
||||||
|
peer_b.clone(),
|
||||||
|
make_peer_state(vec![(hash_a, vec![])]),
|
||||||
|
);
|
||||||
|
|
||||||
|
s
|
||||||
|
},
|
||||||
|
our_view: View(vec![hash_a]),
|
||||||
|
metrics: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pool = sp_core::testing::TaskExecutor::new();
|
||||||
|
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
||||||
|
|
||||||
|
executor::block_on(async move {
|
||||||
|
// Peer A answers our request before peer B.
|
||||||
|
handle_network_update(
|
||||||
|
&mut state,
|
||||||
|
&mut ctx,
|
||||||
|
NetworkBridgeEvent::PeerMessage(
|
||||||
|
peer_a.clone(),
|
||||||
|
send_pov_message(hash_a, pov_hash, pov.clone()),
|
||||||
|
).focus().unwrap(),
|
||||||
|
).await.unwrap();
|
||||||
|
|
||||||
|
handle_network_update(
|
||||||
|
&mut state,
|
||||||
|
&mut ctx,
|
||||||
|
NetworkBridgeEvent::PeerMessage(
|
||||||
|
peer_b.clone(),
|
||||||
|
send_pov_message(hash_a, pov_hash, pov.clone()),
|
||||||
|
).focus().unwrap(),
|
||||||
|
).await.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(&*pov_recv.await.unwrap(), &pov);
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
handle.recv().await,
|
||||||
|
AllMessages::NetworkBridge(
|
||||||
|
NetworkBridgeMessage::ReportPeer(peer, rep)
|
||||||
|
) => {
|
||||||
|
assert_eq!(peer, peer_a);
|
||||||
|
assert_eq!(rep, BENEFIT_FRESH_POV);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
handle.recv().await,
|
||||||
|
AllMessages::NetworkBridge(
|
||||||
|
NetworkBridgeMessage::ReportPeer(peer, rep)
|
||||||
|
) => {
|
||||||
|
assert_eq!(peer, peer_b);
|
||||||
|
assert_eq!(rep, BENEFIT_LATE_POV);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn peer_punished_for_sending_bad_pov() {
|
||||||
|
let hash_a: Hash = [0; 32].into();
|
||||||
|
|
||||||
|
let peer_a = PeerId::random();
|
||||||
|
|
||||||
|
let (pov_send, _) = oneshot::channel();
|
||||||
|
|
||||||
|
let pov = make_pov(vec![1, 2, 3]);
|
||||||
|
let pov_hash = pov.hash();
|
||||||
|
|
||||||
|
let bad_pov = make_pov(vec![6, 6, 6]);
|
||||||
|
|
||||||
|
let mut state = State {
|
||||||
|
relay_parent_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
let mut b = BlockBasedState {
|
||||||
|
known: HashMap::new(),
|
||||||
|
fetching: HashMap::new(),
|
||||||
|
n_validators: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
// pov is being fetched.
|
||||||
|
b.fetching.insert(pov_hash, vec![pov_send]);
|
||||||
|
|
||||||
|
s.insert(hash_a, b);
|
||||||
|
s
|
||||||
|
},
|
||||||
|
peer_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
|
||||||
|
s.insert(
|
||||||
|
peer_a.clone(),
|
||||||
|
make_peer_state(vec![(hash_a, vec![])]),
|
||||||
|
);
|
||||||
|
|
||||||
|
s
|
||||||
|
},
|
||||||
|
our_view: View(vec![hash_a]),
|
||||||
|
metrics: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pool = sp_core::testing::TaskExecutor::new();
|
||||||
|
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
||||||
|
|
||||||
|
executor::block_on(async move {
|
||||||
|
// Peer A answers our request: right relay parent, awaited hash, wrong PoV.
|
||||||
|
handle_network_update(
|
||||||
|
&mut state,
|
||||||
|
&mut ctx,
|
||||||
|
NetworkBridgeEvent::PeerMessage(
|
||||||
|
peer_a.clone(),
|
||||||
|
send_pov_message(hash_a, pov_hash, bad_pov.clone()),
|
||||||
|
).focus().unwrap(),
|
||||||
|
).await.unwrap();
|
||||||
|
|
||||||
|
// didn't complete our sender.
|
||||||
|
assert_eq!(state.relay_parent_state[&hash_a].fetching[&pov_hash].len(), 1);
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
handle.recv().await,
|
||||||
|
AllMessages::NetworkBridge(
|
||||||
|
NetworkBridgeMessage::ReportPeer(peer, rep)
|
||||||
|
) => {
|
||||||
|
assert_eq!(peer, peer_a);
|
||||||
|
assert_eq!(rep, COST_UNEXPECTED_POV);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn peer_punished_for_sending_unexpected_pov() {
|
||||||
|
let hash_a: Hash = [0; 32].into();
|
||||||
|
|
||||||
|
let peer_a = PeerId::random();
|
||||||
|
|
||||||
|
let pov = make_pov(vec![1, 2, 3]);
|
||||||
|
let pov_hash = pov.hash();
|
||||||
|
|
||||||
|
let mut state = State {
|
||||||
|
relay_parent_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
let b = BlockBasedState {
|
||||||
|
known: HashMap::new(),
|
||||||
|
fetching: HashMap::new(),
|
||||||
|
n_validators: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
s.insert(hash_a, b);
|
||||||
|
s
|
||||||
|
},
|
||||||
|
peer_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
|
||||||
|
s.insert(
|
||||||
|
peer_a.clone(),
|
||||||
|
make_peer_state(vec![(hash_a, vec![])]),
|
||||||
|
);
|
||||||
|
|
||||||
|
s
|
||||||
|
},
|
||||||
|
our_view: View(vec![hash_a]),
|
||||||
|
metrics: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pool = sp_core::testing::TaskExecutor::new();
|
||||||
|
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
||||||
|
|
||||||
|
executor::block_on(async move {
|
||||||
|
// Peer A answers our request: right relay parent, awaited hash, wrong PoV.
|
||||||
|
handle_network_update(
|
||||||
|
&mut state,
|
||||||
|
&mut ctx,
|
||||||
|
NetworkBridgeEvent::PeerMessage(
|
||||||
|
peer_a.clone(),
|
||||||
|
send_pov_message(hash_a, pov_hash, pov.clone()),
|
||||||
|
).focus().unwrap(),
|
||||||
|
).await.unwrap();
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
handle.recv().await,
|
||||||
|
AllMessages::NetworkBridge(
|
||||||
|
NetworkBridgeMessage::ReportPeer(peer, rep)
|
||||||
|
) => {
|
||||||
|
assert_eq!(peer, peer_a);
|
||||||
|
assert_eq!(rep, COST_UNEXPECTED_POV);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn peer_punished_for_sending_pov_out_of_our_view() {
|
||||||
|
let hash_a: Hash = [0; 32].into();
|
||||||
|
let hash_b: Hash = [1; 32].into();
|
||||||
|
|
||||||
|
let peer_a = PeerId::random();
|
||||||
|
|
||||||
|
let pov = make_pov(vec![1, 2, 3]);
|
||||||
|
let pov_hash = pov.hash();
|
||||||
|
|
||||||
|
let mut state = State {
|
||||||
|
relay_parent_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
let b = BlockBasedState {
|
||||||
|
known: HashMap::new(),
|
||||||
|
fetching: HashMap::new(),
|
||||||
|
n_validators: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
s.insert(hash_a, b);
|
||||||
|
s
|
||||||
|
},
|
||||||
|
peer_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
|
||||||
|
s.insert(
|
||||||
|
peer_a.clone(),
|
||||||
|
make_peer_state(vec![(hash_a, vec![])]),
|
||||||
|
);
|
||||||
|
|
||||||
|
s
|
||||||
|
},
|
||||||
|
our_view: View(vec![hash_a]),
|
||||||
|
metrics: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pool = sp_core::testing::TaskExecutor::new();
|
||||||
|
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
||||||
|
|
||||||
|
executor::block_on(async move {
|
||||||
|
// Peer A answers our request: right relay parent, awaited hash, wrong PoV.
|
||||||
|
handle_network_update(
|
||||||
|
&mut state,
|
||||||
|
&mut ctx,
|
||||||
|
NetworkBridgeEvent::PeerMessage(
|
||||||
|
peer_a.clone(),
|
||||||
|
send_pov_message(hash_b, pov_hash, pov.clone()),
|
||||||
|
).focus().unwrap(),
|
||||||
|
).await.unwrap();
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
handle.recv().await,
|
||||||
|
AllMessages::NetworkBridge(
|
||||||
|
NetworkBridgeMessage::ReportPeer(peer, rep)
|
||||||
|
) => {
|
||||||
|
assert_eq!(peer, peer_a);
|
||||||
|
assert_eq!(rep, COST_UNEXPECTED_POV);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn peer_reported_for_awaiting_too_much() {
|
||||||
|
let hash_a: Hash = [0; 32].into();
|
||||||
|
|
||||||
|
let peer_a = PeerId::random();
|
||||||
|
let n_validators = 10;
|
||||||
|
|
||||||
|
let mut state = State {
|
||||||
|
relay_parent_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
let b = BlockBasedState {
|
||||||
|
known: HashMap::new(),
|
||||||
|
fetching: HashMap::new(),
|
||||||
|
n_validators,
|
||||||
|
};
|
||||||
|
|
||||||
|
s.insert(hash_a, b);
|
||||||
|
s
|
||||||
|
},
|
||||||
|
peer_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
|
||||||
|
s.insert(
|
||||||
|
peer_a.clone(),
|
||||||
|
make_peer_state(vec![(hash_a, vec![])]),
|
||||||
|
);
|
||||||
|
|
||||||
|
s
|
||||||
|
},
|
||||||
|
our_view: View(vec![hash_a]),
|
||||||
|
metrics: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pool = sp_core::testing::TaskExecutor::new();
|
||||||
|
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
||||||
|
|
||||||
|
executor::block_on(async move {
|
||||||
|
let max_plausibly_awaited = n_validators * 2;
|
||||||
|
|
||||||
|
// The peer awaits a plausible (albeit unlikely) amount of PoVs.
|
||||||
|
for i in 0..max_plausibly_awaited {
|
||||||
|
let pov_hash = make_pov(vec![i as u8; 32]).hash();
|
||||||
|
handle_network_update(
|
||||||
|
&mut state,
|
||||||
|
&mut ctx,
|
||||||
|
NetworkBridgeEvent::PeerMessage(
|
||||||
|
peer_a.clone(),
|
||||||
|
awaiting_message(hash_a, vec![pov_hash]),
|
||||||
|
).focus().unwrap(),
|
||||||
|
).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(state.peer_state[&peer_a].awaited[&hash_a].len(), max_plausibly_awaited);
|
||||||
|
|
||||||
|
// The last straw:
|
||||||
|
let last_pov_hash = make_pov(vec![max_plausibly_awaited as u8; 32]).hash();
|
||||||
|
handle_network_update(
|
||||||
|
&mut state,
|
||||||
|
&mut ctx,
|
||||||
|
NetworkBridgeEvent::PeerMessage(
|
||||||
|
peer_a.clone(),
|
||||||
|
awaiting_message(hash_a, vec![last_pov_hash]),
|
||||||
|
).focus().unwrap(),
|
||||||
|
).await.unwrap();
|
||||||
|
|
||||||
|
// No more bookkeeping for you!
|
||||||
|
assert_eq!(state.peer_state[&peer_a].awaited[&hash_a].len(), max_plausibly_awaited);
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
handle.recv().await,
|
||||||
|
AllMessages::NetworkBridge(
|
||||||
|
NetworkBridgeMessage::ReportPeer(peer, rep)
|
||||||
|
) => {
|
||||||
|
assert_eq!(peer, peer_a);
|
||||||
|
assert_eq!(rep, COST_APPARENT_FLOOD);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn peer_reported_for_awaiting_outside_their_view() {
|
||||||
|
let hash_a: Hash = [0; 32].into();
|
||||||
|
let hash_b: Hash = [1; 32].into();
|
||||||
|
|
||||||
|
let peer_a = PeerId::random();
|
||||||
|
|
||||||
|
let mut state = State {
|
||||||
|
relay_parent_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
s.insert(hash_a, BlockBasedState {
|
||||||
|
known: HashMap::new(),
|
||||||
|
fetching: HashMap::new(),
|
||||||
|
n_validators: 10,
|
||||||
|
});
|
||||||
|
|
||||||
|
s.insert(hash_b, BlockBasedState {
|
||||||
|
known: HashMap::new(),
|
||||||
|
fetching: HashMap::new(),
|
||||||
|
n_validators: 10,
|
||||||
|
});
|
||||||
|
|
||||||
|
s
|
||||||
|
},
|
||||||
|
peer_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
|
||||||
|
// Peer has only hash A in its view.
|
||||||
|
s.insert(
|
||||||
|
peer_a.clone(),
|
||||||
|
make_peer_state(vec![(hash_a, vec![])]),
|
||||||
|
);
|
||||||
|
|
||||||
|
s
|
||||||
|
},
|
||||||
|
our_view: View(vec![hash_a, hash_b]),
|
||||||
|
metrics: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pool = sp_core::testing::TaskExecutor::new();
|
||||||
|
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
||||||
|
|
||||||
|
executor::block_on(async move {
|
||||||
|
let pov_hash = make_pov(vec![1, 2, 3]).hash();
|
||||||
|
|
||||||
|
// Hash B is in our view but not the peer's
|
||||||
|
handle_network_update(
|
||||||
|
&mut state,
|
||||||
|
&mut ctx,
|
||||||
|
NetworkBridgeEvent::PeerMessage(
|
||||||
|
peer_a.clone(),
|
||||||
|
awaiting_message(hash_b, vec![pov_hash]),
|
||||||
|
).focus().unwrap(),
|
||||||
|
).await.unwrap();
|
||||||
|
|
||||||
|
assert!(state.peer_state[&peer_a].awaited.get(&hash_b).is_none());
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
handle.recv().await,
|
||||||
|
AllMessages::NetworkBridge(
|
||||||
|
NetworkBridgeMessage::ReportPeer(peer, rep)
|
||||||
|
) => {
|
||||||
|
assert_eq!(peer, peer_a);
|
||||||
|
assert_eq!(rep, COST_AWAITED_NOT_IN_VIEW);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn peer_reported_for_awaiting_outside_our_view() {
|
||||||
|
let hash_a: Hash = [0; 32].into();
|
||||||
|
let hash_b: Hash = [1; 32].into();
|
||||||
|
|
||||||
|
let peer_a = PeerId::random();
|
||||||
|
|
||||||
|
let mut state = State {
|
||||||
|
relay_parent_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
s.insert(hash_a, BlockBasedState {
|
||||||
|
known: HashMap::new(),
|
||||||
|
fetching: HashMap::new(),
|
||||||
|
n_validators: 10,
|
||||||
|
});
|
||||||
|
|
||||||
|
s
|
||||||
|
},
|
||||||
|
peer_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
|
||||||
|
// Peer has hashes A and B in their view.
|
||||||
|
s.insert(
|
||||||
|
peer_a.clone(),
|
||||||
|
make_peer_state(vec![(hash_a, vec![]), (hash_b, vec![])]),
|
||||||
|
);
|
||||||
|
|
||||||
|
s
|
||||||
|
},
|
||||||
|
our_view: View(vec![hash_a]),
|
||||||
|
metrics: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pool = sp_core::testing::TaskExecutor::new();
|
||||||
|
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
||||||
|
|
||||||
|
executor::block_on(async move {
|
||||||
|
let pov_hash = make_pov(vec![1, 2, 3]).hash();
|
||||||
|
|
||||||
|
// Hash B is in peer's view but not ours.
|
||||||
|
handle_network_update(
|
||||||
|
&mut state,
|
||||||
|
&mut ctx,
|
||||||
|
NetworkBridgeEvent::PeerMessage(
|
||||||
|
peer_a.clone(),
|
||||||
|
awaiting_message(hash_b, vec![pov_hash]),
|
||||||
|
).focus().unwrap(),
|
||||||
|
).await.unwrap();
|
||||||
|
|
||||||
|
// Illegal `awaited` is ignored.
|
||||||
|
assert!(state.peer_state[&peer_a].awaited[&hash_b].is_empty());
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
handle.recv().await,
|
||||||
|
AllMessages::NetworkBridge(
|
||||||
|
NetworkBridgeMessage::ReportPeer(peer, rep)
|
||||||
|
) => {
|
||||||
|
assert_eq!(peer, peer_a);
|
||||||
|
assert_eq!(rep, COST_AWAITED_NOT_IN_VIEW);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn peer_complete_fetch_leads_to_us_completing_others() {
|
||||||
|
let hash_a: Hash = [0; 32].into();
|
||||||
|
|
||||||
|
let peer_a = PeerId::random();
|
||||||
|
let peer_b = PeerId::random();
|
||||||
|
|
||||||
|
let (pov_send, pov_recv) = oneshot::channel();
|
||||||
|
|
||||||
|
let pov = make_pov(vec![1, 2, 3]);
|
||||||
|
let pov_hash = pov.hash();
|
||||||
|
|
||||||
|
let mut state = State {
|
||||||
|
relay_parent_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
let mut b = BlockBasedState {
|
||||||
|
known: HashMap::new(),
|
||||||
|
fetching: HashMap::new(),
|
||||||
|
n_validators: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
// pov is being fetched.
|
||||||
|
b.fetching.insert(pov_hash, vec![pov_send]);
|
||||||
|
|
||||||
|
s.insert(hash_a, b);
|
||||||
|
s
|
||||||
|
},
|
||||||
|
peer_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
|
||||||
|
s.insert(
|
||||||
|
peer_a.clone(),
|
||||||
|
make_peer_state(vec![(hash_a, vec![])]),
|
||||||
|
);
|
||||||
|
|
||||||
|
// peer B is awaiting peer A's request.
|
||||||
|
s.insert(
|
||||||
|
peer_b.clone(),
|
||||||
|
make_peer_state(vec![(hash_a, vec![pov_hash])]),
|
||||||
|
);
|
||||||
|
|
||||||
|
s
|
||||||
|
},
|
||||||
|
our_view: View(vec![hash_a]),
|
||||||
|
metrics: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pool = sp_core::testing::TaskExecutor::new();
|
||||||
|
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
||||||
|
|
||||||
|
executor::block_on(async move {
|
||||||
|
handle_network_update(
|
||||||
|
&mut state,
|
||||||
|
&mut ctx,
|
||||||
|
NetworkBridgeEvent::PeerMessage(
|
||||||
|
peer_a.clone(),
|
||||||
|
send_pov_message(hash_a, pov_hash, pov.clone()),
|
||||||
|
).focus().unwrap(),
|
||||||
|
).await.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(&*pov_recv.await.unwrap(), &pov);
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
handle.recv().await,
|
||||||
|
AllMessages::NetworkBridge(
|
||||||
|
NetworkBridgeMessage::ReportPeer(peer, rep)
|
||||||
|
) => {
|
||||||
|
assert_eq!(peer, peer_a);
|
||||||
|
assert_eq!(rep, BENEFIT_FRESH_POV);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
handle.recv().await,
|
||||||
|
AllMessages::NetworkBridge(
|
||||||
|
NetworkBridgeMessage::SendValidationMessage(peers, message)
|
||||||
|
) => {
|
||||||
|
assert_eq!(peers, vec![peer_b.clone()]);
|
||||||
|
assert_eq!(
|
||||||
|
message,
|
||||||
|
send_pov_message(hash_a, pov_hash, pov.clone()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(!state.peer_state[&peer_b].awaited[&hash_a].contains(&pov_hash));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn peer_completing_request_no_longer_awaiting() {
|
||||||
|
let hash_a: Hash = [0; 32].into();
|
||||||
|
|
||||||
|
let peer_a = PeerId::random();
|
||||||
|
|
||||||
|
let (pov_send, pov_recv) = oneshot::channel();
|
||||||
|
|
||||||
|
let pov = make_pov(vec![1, 2, 3]);
|
||||||
|
let pov_hash = pov.hash();
|
||||||
|
|
||||||
|
let mut state = State {
|
||||||
|
relay_parent_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
let mut b = BlockBasedState {
|
||||||
|
known: HashMap::new(),
|
||||||
|
fetching: HashMap::new(),
|
||||||
|
n_validators: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
// pov is being fetched.
|
||||||
|
b.fetching.insert(pov_hash, vec![pov_send]);
|
||||||
|
|
||||||
|
s.insert(hash_a, b);
|
||||||
|
s
|
||||||
|
},
|
||||||
|
peer_state: {
|
||||||
|
let mut s = HashMap::new();
|
||||||
|
|
||||||
|
// peer A is registered as awaiting.
|
||||||
|
s.insert(
|
||||||
|
peer_a.clone(),
|
||||||
|
make_peer_state(vec![(hash_a, vec![pov_hash])]),
|
||||||
|
);
|
||||||
|
|
||||||
|
s
|
||||||
|
},
|
||||||
|
our_view: View(vec![hash_a]),
|
||||||
|
metrics: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pool = sp_core::testing::TaskExecutor::new();
|
||||||
|
let (mut ctx, mut handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool);
|
||||||
|
|
||||||
|
executor::block_on(async move {
|
||||||
|
handle_network_update(
|
||||||
|
&mut state,
|
||||||
|
&mut ctx,
|
||||||
|
NetworkBridgeEvent::PeerMessage(
|
||||||
|
peer_a.clone(),
|
||||||
|
send_pov_message(hash_a, pov_hash, pov.clone()),
|
||||||
|
).focus().unwrap(),
|
||||||
|
).await.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(&*pov_recv.await.unwrap(), &pov);
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
handle.recv().await,
|
||||||
|
AllMessages::NetworkBridge(
|
||||||
|
NetworkBridgeMessage::ReportPeer(peer, rep)
|
||||||
|
) => {
|
||||||
|
assert_eq!(peer, peer_a);
|
||||||
|
assert_eq!(rep, BENEFIT_FRESH_POV);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// We received the PoV from peer A, so we do not consider it awaited by peer A anymore.
|
||||||
|
assert!(!state.peer_state[&peer_a].awaited[&hash_a].contains(&pov_hash));
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -9,6 +9,4 @@ description = "Primitives types for the Node-side"
|
|||||||
polkadot-primitives = { path = "../../../primitives" }
|
polkadot-primitives = { path = "../../../primitives" }
|
||||||
polkadot-node-primitives = { path = "../../primitives" }
|
polkadot-node-primitives = { path = "../../primitives" }
|
||||||
parity-scale-codec = { version = "1.3.4", default-features = false, features = ["derive"] }
|
parity-scale-codec = { version = "1.3.4", default-features = false, features = ["derive"] }
|
||||||
runtime_primitives = { package = "sp-runtime", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
|
||||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|
||||||
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
|||||||
@@ -16,9 +16,13 @@
|
|||||||
|
|
||||||
//! Network protocol types for parachains.
|
//! Network protocol types for parachains.
|
||||||
|
|
||||||
|
#![deny(unused_crate_dependencies, unused_results)]
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
use polkadot_primitives::v1::Hash;
|
use polkadot_primitives::v1::Hash;
|
||||||
use parity_scale_codec::{Encode, Decode};
|
use parity_scale_codec::{Encode, Decode};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
pub use sc_network::{ReputationChange, PeerId};
|
pub use sc_network::{ReputationChange, PeerId};
|
||||||
|
|
||||||
@@ -32,6 +36,15 @@ pub type ProtocolVersion = u32;
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub struct WrongVariant;
|
pub struct WrongVariant;
|
||||||
|
|
||||||
|
impl fmt::Display for WrongVariant {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(formatter, "Wrong message variant")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for WrongVariant {}
|
||||||
|
|
||||||
|
|
||||||
/// The peer-sets that the network manages. Different subsystems will use different peer-sets.
|
/// The peer-sets that the network manages. Different subsystems will use different peer-sets.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum PeerSet {
|
pub enum PeerSet {
|
||||||
|
|||||||
@@ -7,13 +7,9 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "0.3.5"
|
futures = "0.3.5"
|
||||||
log = "0.4.8"
|
log = "0.4.11"
|
||||||
futures-timer = "3.0.2"
|
|
||||||
streamunordered = "0.5.1"
|
|
||||||
polkadot-primitives = { path = "../../../primitives" }
|
polkadot-primitives = { path = "../../../primitives" }
|
||||||
node-primitives = { package = "polkadot-node-primitives", path = "../../primitives" }
|
node-primitives = { package = "polkadot-node-primitives", path = "../../primitives" }
|
||||||
parity-scale-codec = "1.3.4"
|
|
||||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|
||||||
sp-staking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
sp-staking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||||
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
|
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
|
||||||
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
||||||
@@ -22,7 +18,6 @@ arrayvec = "0.5.1"
|
|||||||
indexmap = "1.4.0"
|
indexmap = "1.4.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
parking_lot = "0.10.0"
|
|
||||||
polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" }
|
polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" }
|
||||||
assert_matches = "1.3.0"
|
assert_matches = "1.3.0"
|
||||||
sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
|||||||
@@ -19,6 +19,9 @@
|
|||||||
//! This is responsible for distributing signed statements about candidate
|
//! This is responsible for distributing signed statements about candidate
|
||||||
//! validity amongst validators.
|
//! validity amongst validators.
|
||||||
|
|
||||||
|
#![deny(unused_crate_dependencies)]
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
use polkadot_subsystem::{
|
use polkadot_subsystem::{
|
||||||
Subsystem, SubsystemResult, SubsystemContext, SpawnedSubsystem,
|
Subsystem, SubsystemResult, SubsystemContext, SpawnedSubsystem,
|
||||||
ActiveLeavesUpdate, FromOverseer, OverseerSignal,
|
ActiveLeavesUpdate, FromOverseer, OverseerSignal,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "0.3.5"
|
futures = "0.3.5"
|
||||||
log = "0.4.8"
|
log = "0.4.11"
|
||||||
futures-timer = "3.0.2"
|
futures-timer = "3.0.2"
|
||||||
streamunordered = "0.5.1"
|
streamunordered = "0.5.1"
|
||||||
polkadot-primitives = { path = "../../primitives" }
|
polkadot-primitives = { path = "../../primitives" }
|
||||||
@@ -21,6 +21,6 @@ sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|||||||
polkadot-node-network-protocol = { path = "../network/protocol" }
|
polkadot-node-network-protocol = { path = "../network/protocol" }
|
||||||
futures = { version = "0.3.5", features = ["thread-pool"] }
|
futures = { version = "0.3.5", features = ["thread-pool"] }
|
||||||
futures-timer = "3.0.2"
|
futures-timer = "3.0.2"
|
||||||
femme = "2.0.1"
|
femme = "2.1.1"
|
||||||
log = "0.4.8"
|
log = "0.4.11"
|
||||||
kv-log-macro = "1.0.6"
|
kv-log-macro = "1.0.7"
|
||||||
|
|||||||
@@ -54,6 +54,11 @@
|
|||||||
//! ..................................................................
|
//! ..................................................................
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
// #![deny(unused_results)]
|
||||||
|
// unused dependencies can not work for test and examples at the same time
|
||||||
|
// yielding false positives
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -96,7 +101,6 @@ const STOP_DELAY: u64 = 1;
|
|||||||
// Target for logs.
|
// Target for logs.
|
||||||
const LOG_TARGET: &'static str = "overseer";
|
const LOG_TARGET: &'static str = "overseer";
|
||||||
|
|
||||||
|
|
||||||
/// A type of messages that are sent from [`Subsystem`] to [`Overseer`].
|
/// A type of messages that are sent from [`Subsystem`] to [`Overseer`].
|
||||||
///
|
///
|
||||||
/// It wraps a system-wide [`AllMessages`] type that represents all possible
|
/// It wraps a system-wide [`AllMessages`] type that represents all possible
|
||||||
@@ -160,7 +164,7 @@ impl From<FinalityNotification<Block>> for BlockInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Some event from outer world.
|
/// Some event from the outer world.
|
||||||
enum Event {
|
enum Event {
|
||||||
BlockImported(BlockInfo),
|
BlockImported(BlockInfo),
|
||||||
BlockFinalized(BlockInfo),
|
BlockFinalized(BlockInfo),
|
||||||
@@ -173,7 +177,7 @@ enum Event {
|
|||||||
enum ExternalRequest {
|
enum ExternalRequest {
|
||||||
WaitForActivation {
|
WaitForActivation {
|
||||||
hash: Hash,
|
hash: Hash,
|
||||||
response_channel: oneshot::Sender<()>,
|
response_channel: oneshot::Sender<SubsystemResult<()>>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +212,7 @@ impl OverseerHandler {
|
|||||||
/// Note that due the fact the overseer doesn't store the whole active-leaves set, only deltas,
|
/// Note that due the fact the overseer doesn't store the whole active-leaves set, only deltas,
|
||||||
/// the response channel may never return if the hash was deactivated before this call.
|
/// the response channel may never return if the hash was deactivated before this call.
|
||||||
/// In this case, it's the caller's responsibility to ensure a timeout is set.
|
/// In this case, it's the caller's responsibility to ensure a timeout is set.
|
||||||
pub async fn wait_for_activation(&mut self, hash: Hash, response_channel: oneshot::Sender<()>) -> SubsystemResult<()> {
|
pub async fn wait_for_activation(&mut self, hash: Hash, response_channel: oneshot::Sender<SubsystemResult<()>>) -> SubsystemResult<()> {
|
||||||
self.events_tx.send(Event::ExternalRequest(ExternalRequest::WaitForActivation {
|
self.events_tx.send(Event::ExternalRequest(ExternalRequest::WaitForActivation {
|
||||||
hash,
|
hash,
|
||||||
response_channel
|
response_channel
|
||||||
@@ -303,7 +307,11 @@ impl<M: Send + 'static> SubsystemContext for OverseerSubsystemContext<M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn recv(&mut self) -> SubsystemResult<FromOverseer<M>> {
|
async fn recv(&mut self) -> SubsystemResult<FromOverseer<M>> {
|
||||||
self.rx.next().await.ok_or(SubsystemError)
|
self.rx.next().await
|
||||||
|
.ok_or(SubsystemError::Context(
|
||||||
|
"No more messages in rx queue to process"
|
||||||
|
.to_owned()
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn spawn(&mut self, name: &'static str, s: Pin<Box<dyn Future<Output = ()> + Send>>)
|
async fn spawn(&mut self, name: &'static str, s: Pin<Box<dyn Future<Output = ()> + Send>>)
|
||||||
@@ -398,7 +406,7 @@ pub struct Overseer<S> {
|
|||||||
s: S,
|
s: S,
|
||||||
|
|
||||||
/// Here we keep handles to spawned subsystems to be notified when they terminate.
|
/// Here we keep handles to spawned subsystems to be notified when they terminate.
|
||||||
running_subsystems: FuturesUnordered<BoxFuture<'static, ()>>,
|
running_subsystems: FuturesUnordered<BoxFuture<'static, SubsystemResult<()>>>,
|
||||||
|
|
||||||
/// Gather running subsystms' outbound streams into one.
|
/// Gather running subsystms' outbound streams into one.
|
||||||
running_subsystems_rx: StreamUnordered<mpsc::Receiver<ToOverseer>>,
|
running_subsystems_rx: StreamUnordered<mpsc::Receiver<ToOverseer>>,
|
||||||
@@ -407,7 +415,7 @@ pub struct Overseer<S> {
|
|||||||
events_rx: mpsc::Receiver<Event>,
|
events_rx: mpsc::Receiver<Event>,
|
||||||
|
|
||||||
/// External listeners waiting for a hash to be in the active-leave set.
|
/// External listeners waiting for a hash to be in the active-leave set.
|
||||||
activation_external_listeners: HashMap<Hash, Vec<oneshot::Sender<()>>>,
|
activation_external_listeners: HashMap<Hash, Vec<oneshot::Sender<SubsystemResult<()>>>>,
|
||||||
|
|
||||||
/// A set of leaves that `Overseer` starts working with.
|
/// A set of leaves that `Overseer` starts working with.
|
||||||
///
|
///
|
||||||
@@ -1267,7 +1275,7 @@ where
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
select! {
|
select! {
|
||||||
_ = self.running_subsystems.next() => {
|
x = self.running_subsystems.next() => {
|
||||||
if self.running_subsystems.is_empty() {
|
if self.running_subsystems.is_empty() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1285,7 +1293,7 @@ where
|
|||||||
|
|
||||||
for (hash, number) in leaves.into_iter() {
|
for (hash, number) in leaves.into_iter() {
|
||||||
update.activated.push(hash);
|
update.activated.push(hash);
|
||||||
self.active_leaves.insert(hash, number);
|
let _ = self.active_leaves.insert(hash, number);
|
||||||
self.on_head_activated(&hash);
|
self.on_head_activated(&hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1331,7 +1339,7 @@ where
|
|||||||
if let Poll::Ready(Some(finished)) = poll!(self.running_subsystems.next()) {
|
if let Poll::Ready(Some(finished)) = poll!(self.running_subsystems.next()) {
|
||||||
log::error!(target: LOG_TARGET, "Subsystem finished unexpectedly {:?}", finished);
|
log::error!(target: LOG_TARGET, "Subsystem finished unexpectedly {:?}", finished);
|
||||||
self.stop().await;
|
self.stop().await;
|
||||||
return Err(SubsystemError);
|
return finished;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Looks like nothing is left to be polled, let's take a break.
|
// Looks like nothing is left to be polled, let's take a break.
|
||||||
@@ -1353,7 +1361,7 @@ where
|
|||||||
match self.active_leaves.entry(block.hash) {
|
match self.active_leaves.entry(block.hash) {
|
||||||
hash_map::Entry::Vacant(entry) => {
|
hash_map::Entry::Vacant(entry) => {
|
||||||
update.activated.push(block.hash);
|
update.activated.push(block.hash);
|
||||||
entry.insert(block.number);
|
let _ = entry.insert(block.number);
|
||||||
self.on_head_activated(&block.hash);
|
self.on_head_activated(&block.hash);
|
||||||
},
|
},
|
||||||
hash_map::Entry::Occupied(entry) => {
|
hash_map::Entry::Occupied(entry) => {
|
||||||
@@ -1541,7 +1549,7 @@ where
|
|||||||
if let Some(listeners) = self.activation_external_listeners.remove(hash) {
|
if let Some(listeners) = self.activation_external_listeners.remove(hash) {
|
||||||
for listener in listeners {
|
for listener in listeners {
|
||||||
// it's fine if the listener is no longer interested
|
// it's fine if the listener is no longer interested
|
||||||
let _ = listener.send(());
|
let _ = listener.send(Ok(()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1567,7 +1575,7 @@ where
|
|||||||
ExternalRequest::WaitForActivation { hash, response_channel } => {
|
ExternalRequest::WaitForActivation { hash, response_channel } => {
|
||||||
if self.active_leaves.get(&hash).is_some() {
|
if self.active_leaves.get(&hash).is_some() {
|
||||||
// it's fine if the listener is no longer interested
|
// it's fine if the listener is no longer interested
|
||||||
let _ = response_channel.send(());
|
let _ = response_channel.send(Ok(()));
|
||||||
} else {
|
} else {
|
||||||
self.activation_external_listeners.entry(hash).or_default().push(response_channel);
|
self.activation_external_listeners.entry(hash).or_default().push(response_channel);
|
||||||
}
|
}
|
||||||
@@ -1586,7 +1594,7 @@ where
|
|||||||
|
|
||||||
fn spawn<S: SpawnNamed, M: Send + 'static>(
|
fn spawn<S: SpawnNamed, M: Send + 'static>(
|
||||||
spawner: &mut S,
|
spawner: &mut S,
|
||||||
futures: &mut FuturesUnordered<BoxFuture<'static, ()>>,
|
futures: &mut FuturesUnordered<BoxFuture<'static, SubsystemResult<()>>>,
|
||||||
streams: &mut StreamUnordered<mpsc::Receiver<ToOverseer>>,
|
streams: &mut StreamUnordered<mpsc::Receiver<ToOverseer>>,
|
||||||
s: impl Subsystem<OverseerSubsystemContext<M>>,
|
s: impl Subsystem<OverseerSubsystemContext<M>>,
|
||||||
) -> SubsystemResult<OverseenSubsystem<M>> {
|
) -> SubsystemResult<OverseenSubsystem<M>> {
|
||||||
@@ -1604,8 +1612,8 @@ fn spawn<S: SpawnNamed, M: Send + 'static>(
|
|||||||
|
|
||||||
spawner.spawn(name, fut);
|
spawner.spawn(name, fut);
|
||||||
|
|
||||||
streams.push(from_rx);
|
let _ = streams.push(from_rx);
|
||||||
futures.push(Box::pin(rx.map(|_| ())));
|
futures.push(Box::pin(rx.map(|e| { log::warn!("Dropping error {:?}", e); Ok(()) })));
|
||||||
|
|
||||||
let instance = Some(SubsystemInstance {
|
let instance = Some(SubsystemInstance {
|
||||||
tx: to_tx,
|
tx: to_tx,
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
//! not shared between the node and the runtime. This crate builds on top of the primitives defined
|
//! not shared between the node and the runtime. This crate builds on top of the primitives defined
|
||||||
//! there.
|
//! there.
|
||||||
|
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
use parity_scale_codec::{Decode, Encode};
|
use parity_scale_codec::{Decode, Encode};
|
||||||
use polkadot_primitives::v1::{
|
use polkadot_primitives::v1::{
|
||||||
|
|||||||
@@ -16,12 +16,14 @@
|
|||||||
|
|
||||||
//! Polkadot service. Specialized wrapper over substrate service.
|
//! Polkadot service. Specialized wrapper over substrate service.
|
||||||
|
|
||||||
|
#![deny(unused_results)]
|
||||||
|
|
||||||
pub mod chain_spec;
|
pub mod chain_spec;
|
||||||
mod grandpa_support;
|
mod grandpa_support;
|
||||||
mod client;
|
mod client;
|
||||||
|
|
||||||
|
|
||||||
use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider};
|
use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider};
|
||||||
|
#[cfg(feature = "full-node")]
|
||||||
use log::info;
|
use log::info;
|
||||||
use polkadot_node_core_proposer::ProposerFactory;
|
use polkadot_node_core_proposer::ProposerFactory;
|
||||||
use polkadot_overseer::{AllSubsystems, BlockInfo, Overseer, OverseerHandler};
|
use polkadot_overseer::{AllSubsystems, BlockInfo, Overseer, OverseerHandler};
|
||||||
@@ -383,7 +385,7 @@ pub fn new_full<RuntimeApi, Executor>(
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
if config.offchain_worker.enabled {
|
if config.offchain_worker.enabled {
|
||||||
service::build_offchain_workers(
|
let _ = service::build_offchain_workers(
|
||||||
&config, backend.clone(), task_manager.spawn_handle(), client.clone(), network.clone(),
|
&config, backend.clone(), task_manager.spawn_handle(), client.clone(), network.clone(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -650,7 +652,7 @@ fn new_light<Runtime, Dispatch>(mut config: Configuration) -> Result<(TaskManage
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
if config.offchain_worker.enabled {
|
if config.offchain_worker.enabled {
|
||||||
service::build_offchain_workers(
|
let _ = service::build_offchain_workers(
|
||||||
&config,
|
&config,
|
||||||
backend.clone(),
|
backend.clone(),
|
||||||
task_manager.spawn_handle(),
|
task_manager.spawn_handle(),
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ description = "Subsystem traits and message definitions"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
derive_more = "0.99.9"
|
|
||||||
futures = "0.3.5"
|
futures = "0.3.5"
|
||||||
futures-timer = "3.0.2"
|
futures-timer = "3.0.2"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
//! Utilities for testing subsystems.
|
//! Utilities for testing subsystems.
|
||||||
|
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
use polkadot_node_subsystem::messages::AllMessages;
|
use polkadot_node_subsystem::messages::AllMessages;
|
||||||
use polkadot_node_subsystem::{
|
use polkadot_node_subsystem::{
|
||||||
FromOverseer, SubsystemContext, SubsystemError, SubsystemResult, Subsystem,
|
FromOverseer, SubsystemContext, SubsystemError, SubsystemResult, Subsystem,
|
||||||
@@ -169,7 +171,8 @@ impl<M: Send + 'static, S: SpawnNamed + Send + 'static> SubsystemContext
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn recv(&mut self) -> SubsystemResult<FromOverseer<M>> {
|
async fn recv(&mut self) -> SubsystemResult<FromOverseer<M>> {
|
||||||
self.rx.next().await.ok_or(SubsystemError)
|
self.rx.next().await
|
||||||
|
.ok_or_else(|| SubsystemError::Context("Receiving end closed".to_owned()))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn spawn(
|
async fn spawn(
|
||||||
|
|||||||
@@ -7,20 +7,18 @@ description = "Subsystem traits and message definitions"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
derive_more = "0.99.9"
|
|
||||||
futures = "0.3.5"
|
futures = "0.3.5"
|
||||||
futures-timer = "3.0.2"
|
futures-timer = "3.0.2"
|
||||||
log = "0.4.8"
|
log = "0.4.11"
|
||||||
|
thiserror = "1.0.21"
|
||||||
parity-scale-codec = "1.3.4"
|
parity-scale-codec = "1.3.4"
|
||||||
parking_lot = { version = "0.10.0", optional = true }
|
parking_lot = { version = "0.10.0", optional = true }
|
||||||
pin-project = "0.4.22"
|
pin-project = "0.4.22"
|
||||||
smallvec = "1.4.1"
|
|
||||||
streamunordered = "0.5.1"
|
streamunordered = "0.5.1"
|
||||||
|
|
||||||
polkadot-node-primitives = { path = "../primitives" }
|
polkadot-node-primitives = { path = "../primitives" }
|
||||||
polkadot-node-subsystem = { path = "../subsystem" }
|
polkadot-node-subsystem = { path = "../subsystem" }
|
||||||
polkadot-primitives = { path = "../../primitives" }
|
polkadot-primitives = { path = "../../primitives" }
|
||||||
polkadot-statement-table = { path = "../../statement-table" }
|
|
||||||
|
|
||||||
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
|||||||
@@ -22,6 +22,10 @@
|
|||||||
//!
|
//!
|
||||||
//! This crate also reexports Prometheus metric types which are expected to be implemented by subsystems.
|
//! This crate also reexports Prometheus metric types which are expected to be implemented by subsystems.
|
||||||
|
|
||||||
|
#![deny(unused_results)]
|
||||||
|
// #![deny(unused_crate_dependencies] causes false positives
|
||||||
|
// https://github.com/rust-lang/rust/issues/57274
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
use polkadot_node_subsystem::{
|
use polkadot_node_subsystem::{
|
||||||
errors::{ChainApiError, RuntimeApiError},
|
errors::{ChainApiError, RuntimeApiError},
|
||||||
@@ -63,6 +67,7 @@ use std::{
|
|||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
use streamunordered::{StreamUnordered, StreamYield};
|
use streamunordered::{StreamUnordered, StreamYield};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
pub mod validator_discovery;
|
pub mod validator_discovery;
|
||||||
|
|
||||||
@@ -82,35 +87,38 @@ pub const JOB_GRACEFUL_STOP_DURATION: Duration = Duration::from_secs(1);
|
|||||||
/// Capacity of channels to and from individual jobs
|
/// Capacity of channels to and from individual jobs
|
||||||
pub const JOB_CHANNEL_CAPACITY: usize = 64;
|
pub const JOB_CHANNEL_CAPACITY: usize = 64;
|
||||||
|
|
||||||
|
|
||||||
/// Utility errors
|
/// Utility errors
|
||||||
#[derive(Debug, derive_more::From)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Attempted to send or receive on a oneshot channel which had been canceled
|
/// Attempted to send or receive on a oneshot channel which had been canceled
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Oneshot(oneshot::Canceled),
|
Oneshot(#[from] oneshot::Canceled),
|
||||||
/// Attempted to send on a MPSC channel which has been canceled
|
/// Attempted to send on a MPSC channel which has been canceled
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Mpsc(mpsc::SendError),
|
Mpsc(#[from] mpsc::SendError),
|
||||||
/// A subsystem error
|
/// A subsystem error
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Subsystem(SubsystemError),
|
Subsystem(#[from] SubsystemError),
|
||||||
/// An error in the Chain API.
|
/// An error in the Chain API.
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
ChainApi(ChainApiError),
|
ChainApi(#[from] ChainApiError),
|
||||||
/// An error in the Runtime API.
|
/// An error in the Runtime API.
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
RuntimeApi(RuntimeApiError),
|
RuntimeApi(#[from] RuntimeApiError),
|
||||||
/// The type system wants this even though it doesn't make sense
|
/// The type system wants this even though it doesn't make sense
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Infallible(std::convert::Infallible),
|
Infallible(#[from] std::convert::Infallible),
|
||||||
/// Attempted to convert from an AllMessages to a FromJob, and failed.
|
/// Attempted to convert from an AllMessages to a FromJob, and failed.
|
||||||
|
#[error("AllMessage not relevant to Job")]
|
||||||
SenderConversion(String),
|
SenderConversion(String),
|
||||||
/// The local node is not a validator.
|
/// The local node is not a validator.
|
||||||
|
#[error("Node is not a validator")]
|
||||||
NotAValidator,
|
NotAValidator,
|
||||||
/// The desired job is not present in the jobs list.
|
/// The desired job is not present in the jobs list.
|
||||||
|
#[error("Relay parent {0} not of interest")]
|
||||||
JobNotFound(Hash),
|
JobNotFound(Hash),
|
||||||
/// Already forwarding errors to another sender
|
/// Already forwarding errors to another sender
|
||||||
|
#[error("AlreadyForwarding")]
|
||||||
AlreadyForwarding,
|
AlreadyForwarding,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,7 +504,7 @@ pub trait JobTrait: Unpin {
|
|||||||
/// Message type from the job. Typically a subset of AllMessages.
|
/// Message type from the job. Typically a subset of AllMessages.
|
||||||
type FromJob: 'static + Into<AllMessages> + Send;
|
type FromJob: 'static + Into<AllMessages> + Send;
|
||||||
/// Job runtime error.
|
/// Job runtime error.
|
||||||
type Error: 'static + std::fmt::Debug + Send;
|
type Error: 'static + std::error::Error + Send;
|
||||||
/// Extra arguments this job needs to run properly.
|
/// Extra arguments this job needs to run properly.
|
||||||
///
|
///
|
||||||
/// If no extra information is needed, it is perfectly acceptable to set it to `()`.
|
/// If no extra information is needed, it is perfectly acceptable to set it to `()`.
|
||||||
@@ -538,13 +546,14 @@ pub trait JobTrait: Unpin {
|
|||||||
/// Error which can be returned by the jobs manager
|
/// Error which can be returned by the jobs manager
|
||||||
///
|
///
|
||||||
/// Wraps the utility error type and the job-specific error
|
/// Wraps the utility error type and the job-specific error
|
||||||
#[derive(Debug, derive_more::From)]
|
#[derive(Debug, Error)]
|
||||||
pub enum JobsError<JobError> {
|
pub enum JobsError<JobError: 'static + std::error::Error> {
|
||||||
/// utility error
|
/// utility error
|
||||||
#[from]
|
#[error("Utility")]
|
||||||
Utility(Error),
|
Utility(#[source] Error),
|
||||||
/// internal job error
|
/// internal job error
|
||||||
Job(JobError),
|
#[error("Internal")]
|
||||||
|
Job(#[source] JobError),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Jobs manager for a subsystem
|
/// Jobs manager for a subsystem
|
||||||
@@ -645,7 +654,7 @@ impl<Spawner: SpawnNamed, Job: 'static + JobTrait> Jobs<Spawner, Job> {
|
|||||||
outgoing_msgs_handle,
|
outgoing_msgs_handle,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.running.insert(parent_hash, handle);
|
let _ = self.running.insert(parent_hash, handle);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -654,7 +663,7 @@ impl<Spawner: SpawnNamed, Job: 'static + JobTrait> Jobs<Spawner, Job> {
|
|||||||
pub async fn stop_job(&mut self, parent_hash: Hash) -> Result<(), Error> {
|
pub async fn stop_job(&mut self, parent_hash: Hash) -> Result<(), Error> {
|
||||||
match self.running.remove(&parent_hash) {
|
match self.running.remove(&parent_hash) {
|
||||||
Some(handle) => {
|
Some(handle) => {
|
||||||
Pin::new(&mut self.outgoing_msgs).remove(handle.outgoing_msgs_handle);
|
let _ = Pin::new(&mut self.outgoing_msgs).remove(handle.outgoing_msgs_handle);
|
||||||
handle.stop().await;
|
handle.stop().await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -830,7 +839,8 @@ where
|
|||||||
let metrics = metrics.clone();
|
let metrics = metrics.clone();
|
||||||
if let Err(e) = jobs.spawn_job(hash, run_args.clone(), metrics) {
|
if let Err(e) = jobs.spawn_job(hash, run_args.clone(), metrics) {
|
||||||
log::error!("Failed to spawn a job: {:?}", e);
|
log::error!("Failed to spawn a job: {:?}", e);
|
||||||
Self::fwd_err(Some(hash), e.into(), err_tx).await;
|
let e = JobsError::Utility(e);
|
||||||
|
Self::fwd_err(Some(hash), e, err_tx).await;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -838,7 +848,8 @@ where
|
|||||||
for hash in deactivated {
|
for hash in deactivated {
|
||||||
if let Err(e) = jobs.stop_job(hash).await {
|
if let Err(e) = jobs.stop_job(hash).await {
|
||||||
log::error!("Failed to stop a job: {:?}", e);
|
log::error!("Failed to stop a job: {:?}", e);
|
||||||
Self::fwd_err(Some(hash), e.into(), err_tx).await;
|
let e = JobsError::Utility(e);
|
||||||
|
Self::fwd_err(Some(hash), e, err_tx).await;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -863,7 +874,8 @@ where
|
|||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
log::error!("failed to stop all jobs on conclude signal: {:?}", e);
|
log::error!("failed to stop all jobs on conclude signal: {:?}", e);
|
||||||
Self::fwd_err(None, Error::from(e).into(), err_tx).await;
|
let e = Error::from(e);
|
||||||
|
Self::fwd_err(None, JobsError::Utility(e), err_tx).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -874,14 +886,16 @@ where
|
|||||||
Some(hash) => {
|
Some(hash) => {
|
||||||
if let Err(err) = jobs.send_msg(hash, to_job).await {
|
if let Err(err) = jobs.send_msg(hash, to_job).await {
|
||||||
log::error!("Failed to send a message to a job: {:?}", err);
|
log::error!("Failed to send a message to a job: {:?}", err);
|
||||||
Self::fwd_err(Some(hash), err.into(), err_tx).await;
|
let e = JobsError::Utility(err);
|
||||||
|
Self::fwd_err(Some(hash), e, err_tx).await;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
if let Err(err) = Job::handle_unanchored_msg(to_job) {
|
if let Err(err) = Job::handle_unanchored_msg(to_job) {
|
||||||
log::error!("Failed to handle unhashed message: {:?}", err);
|
log::error!("Failed to handle unhashed message: {:?}", err);
|
||||||
Self::fwd_err(None, JobsError::Job(err), err_tx).await;
|
let e = JobsError::Job(err);
|
||||||
|
Self::fwd_err(None, e, err_tx).await;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -891,7 +905,8 @@ where
|
|||||||
Ok(Signal(BlockFinalized(_))) => {}
|
Ok(Signal(BlockFinalized(_))) => {}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::error!("error receiving message from subsystem context: {:?}", err);
|
log::error!("error receiving message from subsystem context: {:?}", err);
|
||||||
Self::fwd_err(None, Error::from(err).into(), err_tx).await;
|
let e = JobsError::Utility(Error::from(err));
|
||||||
|
Self::fwd_err(None, e, err_tx).await;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -906,7 +921,8 @@ where
|
|||||||
) {
|
) {
|
||||||
let msg = outgoing.expect("the Jobs stream never ends; qed");
|
let msg = outgoing.expect("the Jobs stream never ends; qed");
|
||||||
if let Err(e) = ctx.send_message(msg.into()).await {
|
if let Err(e) = ctx.send_message(msg.into()).await {
|
||||||
Self::fwd_err(None, Error::from(e).into(), err_tx).await;
|
let e = JobsError::Utility(e.into());
|
||||||
|
Self::fwd_err(None, e, err_tx).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1032,6 +1048,8 @@ pub struct Timeout<F: Future> {
|
|||||||
|
|
||||||
/// Extends `Future` to allow time-limited futures.
|
/// Extends `Future` to allow time-limited futures.
|
||||||
pub trait TimeoutExt: Future {
|
pub trait TimeoutExt: Future {
|
||||||
|
/// Adds a timeout of `duration` to the given `Future`.
|
||||||
|
/// Returns a new `Future`.
|
||||||
fn timeout(self, duration: Duration) -> Timeout<Self>
|
fn timeout(self, duration: Duration) -> Timeout<Self>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
@@ -1066,6 +1084,7 @@ impl<F: Future> Future for Timeout<F> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{Error as UtilError, JobManager, JobTrait, JobsError, TimeoutExt, ToJobTrait};
|
use super::{Error as UtilError, JobManager, JobTrait, JobsError, TimeoutExt, ToJobTrait};
|
||||||
|
use thiserror::Error;
|
||||||
use polkadot_node_subsystem::{
|
use polkadot_node_subsystem::{
|
||||||
messages::{AllMessages, CandidateSelectionMessage},
|
messages::{AllMessages, CandidateSelectionMessage},
|
||||||
ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, Subsystem,
|
ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, Subsystem,
|
||||||
@@ -1156,10 +1175,10 @@ mod tests {
|
|||||||
// Error will mostly be a wrapper to make the try operator more convenient;
|
// Error will mostly be a wrapper to make the try operator more convenient;
|
||||||
// deriving From implementations for most variants is recommended.
|
// deriving From implementations for most variants is recommended.
|
||||||
// It must implement Debug for logging.
|
// It must implement Debug for logging.
|
||||||
#[derive(Debug, derive_more::From)]
|
#[derive(Debug, Error)]
|
||||||
enum Error {
|
enum Error {
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Sending(mpsc::SendError),
|
Sending(#[from]mpsc::SendError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JobTrait for FakeCandidateSelectionJob {
|
impl JobTrait for FakeCandidateSelectionJob {
|
||||||
@@ -1261,7 +1280,7 @@ mod tests {
|
|||||||
fn starting_and_stopping_job_works() {
|
fn starting_and_stopping_job_works() {
|
||||||
let relay_parent: Hash = [0; 32].into();
|
let relay_parent: Hash = [0; 32].into();
|
||||||
let mut run_args = HashMap::new();
|
let mut run_args = HashMap::new();
|
||||||
run_args.insert(
|
let _ = run_args.insert(
|
||||||
relay_parent.clone(),
|
relay_parent.clone(),
|
||||||
vec![FromJob::Test],
|
vec![FromJob::Test],
|
||||||
);
|
);
|
||||||
@@ -1317,7 +1336,7 @@ mod tests {
|
|||||||
fn sending_to_a_non_running_job_do_not_stop_the_subsystem() {
|
fn sending_to_a_non_running_job_do_not_stop_the_subsystem() {
|
||||||
let relay_parent = Hash::repeat_byte(0x01);
|
let relay_parent = Hash::repeat_byte(0x01);
|
||||||
let mut run_args = HashMap::new();
|
let mut run_args = HashMap::new();
|
||||||
run_args.insert(
|
let _ = run_args.insert(
|
||||||
relay_parent.clone(),
|
relay_parent.clone(),
|
||||||
vec![FromJob::Test],
|
vec![FromJob::Test],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ use futures::{
|
|||||||
task::{Poll, self},
|
task::{Poll, self},
|
||||||
stream,
|
stream,
|
||||||
};
|
};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
use polkadot_node_subsystem::{
|
use polkadot_node_subsystem::{
|
||||||
errors::RuntimeApiError, SubsystemError,
|
errors::RuntimeApiError, SubsystemError,
|
||||||
@@ -34,17 +35,17 @@ use polkadot_primitives::v1::{Hash, ValidatorId, AuthorityDiscoveryId};
|
|||||||
use sc_network::PeerId;
|
use sc_network::PeerId;
|
||||||
|
|
||||||
/// Error when making a request to connect to validators.
|
/// Error when making a request to connect to validators.
|
||||||
#[derive(Debug, derive_more::From)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Attempted to send or receive on a oneshot channel which had been canceled
|
/// Attempted to send or receive on a oneshot channel which had been canceled
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Oneshot(oneshot::Canceled),
|
Oneshot(#[from] oneshot::Canceled),
|
||||||
/// A subsystem error.
|
/// A subsystem error.
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
Subsystem(SubsystemError),
|
Subsystem(#[from] SubsystemError),
|
||||||
/// An error in the Runtime API.
|
/// An error in the Runtime API.
|
||||||
#[from]
|
#[error(transparent)]
|
||||||
RuntimeApi(RuntimeApiError),
|
RuntimeApi(#[from] RuntimeApiError),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Utility function to make it easier to connect to validators.
|
/// Utility function to make it easier to connect to validators.
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ polkadot-statement-table = { path = "../../statement-table" }
|
|||||||
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
smallvec = "1.4.1"
|
smallvec = "1.4.1"
|
||||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
thiserror = "1.0.21"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_matches = "1.3.0"
|
assert_matches = "1.3.0"
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ impl core::fmt::Display for RuntimeApiError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for RuntimeApiError {}
|
||||||
|
|
||||||
/// A description of an error causing the chain API request to be unservable.
|
/// A description of an error causing the chain API request to be unservable.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ChainApiError {
|
pub struct ChainApiError {
|
||||||
@@ -55,3 +57,5 @@ impl core::fmt::Display for ChainApiError {
|
|||||||
write!(f, "{}", self.msg)
|
write!(f, "{}", self.msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for ChainApiError {}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ use futures::future::BoxFuture;
|
|||||||
use polkadot_primitives::v1::Hash;
|
use polkadot_primitives::v1::Hash;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::messages::AllMessages;
|
use crate::messages::AllMessages;
|
||||||
|
|
||||||
@@ -105,6 +106,7 @@ pub enum FromOverseer<M> {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// An error type that describes faults that may happen
|
/// An error type that describes faults that may happen
|
||||||
///
|
///
|
||||||
/// These are:
|
/// These are:
|
||||||
@@ -112,30 +114,42 @@ pub enum FromOverseer<M> {
|
|||||||
/// * Subsystems dying when they are not expected to
|
/// * Subsystems dying when they are not expected to
|
||||||
/// * Subsystems not dying when they are told to die
|
/// * Subsystems not dying when they are told to die
|
||||||
/// * etc.
|
/// * etc.
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Error, Debug)]
|
||||||
pub struct SubsystemError;
|
pub enum SubsystemError {
|
||||||
|
/// A notification connection is no longer valid.
|
||||||
|
#[error(transparent)]
|
||||||
|
NotifyCancellation(#[from] oneshot::Canceled),
|
||||||
|
|
||||||
impl From<mpsc::SendError> for SubsystemError {
|
/// Queue does not accept another item.
|
||||||
fn from(_: mpsc::SendError) -> Self {
|
#[error(transparent)]
|
||||||
Self
|
QueueError(#[from] mpsc::SendError),
|
||||||
}
|
|
||||||
|
/// An attempt to spawn a futures task did not succeed.
|
||||||
|
#[error(transparent)]
|
||||||
|
TaskSpawn(#[from] futures::task::SpawnError),
|
||||||
|
|
||||||
|
/// An infallable error.
|
||||||
|
#[error(transparent)]
|
||||||
|
Infallible(#[from] std::convert::Infallible),
|
||||||
|
|
||||||
|
/// An other error lacking particular type information.
|
||||||
|
#[error("Failed to {0}")]
|
||||||
|
Context(String),
|
||||||
|
|
||||||
|
/// Per origin (or subsystem) annotations to wrap an error.
|
||||||
|
#[error("Error originated in {origin}")]
|
||||||
|
FromOrigin {
|
||||||
|
/// An additional anotation tag for the origin of `source`.
|
||||||
|
origin: &'static str,
|
||||||
|
/// The wrapped error. Marked as source for tracking the error chain.
|
||||||
|
#[source] source: Box<dyn std::error::Error + Send>
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<oneshot::Canceled> for SubsystemError {
|
impl SubsystemError {
|
||||||
fn from(_: oneshot::Canceled) -> Self {
|
/// Adds a `str` as `origin` to the given error `err`.
|
||||||
Self
|
pub fn with_origin<E: 'static + Send + std::error::Error>(origin: &'static str, err: E) -> Self {
|
||||||
}
|
Self::FromOrigin { origin, source: Box::new(err) }
|
||||||
}
|
|
||||||
|
|
||||||
impl From<futures::task::SpawnError> for SubsystemError {
|
|
||||||
fn from(_: futures::task::SpawnError) -> Self {
|
|
||||||
Self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<std::convert::Infallible> for SubsystemError {
|
|
||||||
fn from(e: std::convert::Infallible) -> Self {
|
|
||||||
match e {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
//! Subsystems' APIs are defined separately from their implementation, leading to easier mocking.
|
//! Subsystems' APIs are defined separately from their implementation, leading to easier mocking.
|
||||||
|
|
||||||
use futures::channel::{mpsc, oneshot};
|
use futures::channel::{mpsc, oneshot};
|
||||||
|
use thiserror::Error;
|
||||||
use polkadot_node_network_protocol::{
|
use polkadot_node_network_protocol::{
|
||||||
v1 as protocol_v1, NetworkBridgeEvent, ReputationChange, PeerId,
|
v1 as protocol_v1, NetworkBridgeEvent, ReputationChange, PeerId,
|
||||||
};
|
};
|
||||||
@@ -97,7 +97,8 @@ impl CandidateBackingMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Blanket error for validation failing for internal reasons.
|
/// Blanket error for validation failing for internal reasons.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Error)]
|
||||||
|
#[error("Validation failed with {0:?}")]
|
||||||
pub struct ValidationFailed(pub String);
|
pub struct ValidationFailed(pub String);
|
||||||
|
|
||||||
/// Messages received by the Validation subsystem.
|
/// Messages received by the Validation subsystem.
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ sp-wasm-interface = { git = "https://github.com/paritytech/substrate", branch =
|
|||||||
polkadot-core-primitives = { path = "../core-primitives", default-features = false }
|
polkadot-core-primitives = { path = "../core-primitives", default-features = false }
|
||||||
|
|
||||||
# all optional crates.
|
# all optional crates.
|
||||||
derive_more = { version = "0.99.2", optional = true }
|
derive_more = { version = "0.99.11", optional = true }
|
||||||
serde = { version = "1.0.102", default-features = false, features = [ "derive" ], optional = true }
|
serde = { version = "1.0.102", default-features = false, features = [ "derive" ], optional = true }
|
||||||
sp-externalities = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
|
sp-externalities = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
|
||||||
sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
|
sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ consensus = { package = "sp-consensus", git = "https://github.com/paritytech/sub
|
|||||||
runtime_primitives = { package = "sp-runtime", git = "https://github.com/paritytech/substrate", branch = "master" }
|
runtime_primitives = { package = "sp-runtime", git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
futures = "0.3.4"
|
futures = "0.3.4"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
derive_more = "0.14.1"
|
|
||||||
codec = { package = "parity-scale-codec", version = "1.3.4", default-features = false, features = ["derive"] }
|
codec = { package = "parity-scale-codec", version = "1.3.4", default-features = false, features = ["derive"] }
|
||||||
grandpa = { package = "sc-finality-grandpa", git = "https://github.com/paritytech/substrate", branch = "master" }
|
grandpa = { package = "sc-finality-grandpa", git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
inherents = { package = "sp-inherents", git = "https://github.com/paritytech/substrate", branch = "master" }
|
inherents = { package = "sp-inherents", git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
@@ -26,6 +25,7 @@ block-builder = { package = "sc-block-builder", git = "https://github.com/parity
|
|||||||
trie = { package = "sp-trie", git = "https://github.com/paritytech/substrate", branch = "master" }
|
trie = { package = "sp-trie", git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
babe-primitives = { package = "sp-consensus-babe", git = "https://github.com/paritytech/substrate", branch = "master" }
|
babe-primitives = { package = "sp-consensus-babe", git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
prometheus-endpoint = { package = "substrate-prometheus-endpoint", git = "https://github.com/paritytech/substrate", branch = "master" }
|
prometheus-endpoint = { package = "substrate-prometheus-endpoint", git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
thiserror = "1.0.21"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
|||||||
@@ -16,24 +16,25 @@
|
|||||||
|
|
||||||
//! Errors that can occur during the validation process.
|
//! Errors that can occur during the validation process.
|
||||||
|
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
/// Error type for validation
|
/// Error type for validation
|
||||||
#[derive(Debug, derive_more::Display, derive_more::From)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Client error
|
/// Client error
|
||||||
Client(sp_blockchain::Error),
|
#[error(transparent)]
|
||||||
|
Client(#[from] sp_blockchain::Error),
|
||||||
/// Consensus error
|
/// Consensus error
|
||||||
Consensus(consensus::error::Error),
|
#[error(transparent)]
|
||||||
|
Consensus(#[from] consensus::error::Error),
|
||||||
/// Unexpected error checking inherents
|
/// Unexpected error checking inherents
|
||||||
#[display(fmt = "Unexpected error while checking inherents: {}", _0)]
|
#[error("Unexpected error while checking inherents: {0}")]
|
||||||
InherentError(inherents::Error),
|
InherentError(inherents::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for Error {
|
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
impl std::convert::From<inherents::Error> for Error {
|
||||||
match self {
|
fn from(inner: inherents::Error) -> Self {
|
||||||
Error::Client(ref err) => Some(err),
|
Self::InherentError(inner)
|
||||||
Error::Consensus(ref err) => Some(err),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user