mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-08 11:18:01 +00:00
Malus: add disputed block percentage (#6100)
* Malus: add disputed block percentage * Bump clap to support value_parser with range * Add rand crate and use Bernoulli and Distribution * Add conditional logic based on sampled value from Bernoulli distribution * Add SuggestGarbageCandidateOptions struct * Cleanup tests * * Replace unwrap with expect and meaningful error message * * Remove Inner * Remove intercept_outgoing * * Rename sampled variable * Move info! logs to include candidate hash of malicious candidate * * Add percentage option to dispute_ancestor * * Support static probability for `ReplaceValidationResult` proxy * Update some comments and docs * * Add `--percentage` to `back-garbage-candidate` variant * Rename structs for consistency * * Add probabilistic behavior to `dispute-ancestor` variant * Add probabilistic behavior to `back-garbage-candidate` variant * Rename structs in dispute variant * * More descriptive comments * * cargo +nightly fmt --all * * Move Bernoulli distributrion to ReplaceValidationResult constructor * Rename random_bool to behave_maliciously * * Remove dangling comment * * Consistent log * * Add logs based on sampled value * * Cargo +nightly fmt --all * * Remove unused percentage attributed after moving Bernoulli to constructor * Squashed commit of the following: commite4361b6d80Author: Chris Sosnin <48099298+slumber@users.noreply.github.com> Date: Mon Oct 10 10:06:44 2022 +0400 Fix flaky test (#6131) * Split test + decrease test timeout * fmt * spellcheck commitf614752c22Author: girazoki <gorka.irazoki@gmail.com> Date: Mon Oct 10 06:39:30 2022 +0200 Add event to asset claim (#6029) commit71197818a4Author: Leszek Wiesner <leszek@jsgenesis.com> Date: Mon Oct 10 00:23:54 2022 +0200 Companion for 12109 (#5929) * Update following `pallet-vesting` configurable `WithdrawReasons` * Update lib.rs * Update lib.rs * Update lib.rs * update lockfile for {"substrate"} * fix warning Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> Co-authored-by: parity-processbot <> commit607350449cAuthor: Bastian Köcher <info@kchr.de> Date: Fri Oct 7 13:40:40 2022 +0200 Companion for upgrading pin-project (#6118) * Companion for upgrading pin-project This will remove some warnings with the latest rustc nightly/stable. https://github.com/paritytech/substrate/pull/12426 * update lockfile for {"substrate"} Co-authored-by: parity-processbot <> commitc8151aed3cAuthor: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Thu Oct 6 19:20:58 2022 +0200 Maximum value for `MultiplierUpdate` (#6021) * update multiplier * fix * update lockfile for {"substrate"} * fmt * fix typo Co-authored-by: parity-processbot <> commit8d1c16dc0dAuthor: Adrian Catangiu <adrian@parity.io> Date: Thu Oct 6 12:58:39 2022 +0300 service: use MmrRootProvider as custom BEEFY payload provider (companion for 12428) (#6112) * service: use MmrRootProvider as custom BEEFY payload provider * update lockfile for {"substrate"} Co-authored-by: parity-processbot <> commit910e21847fAuthor: Branislav Kontur <bkontur@gmail.com> Date: Thu Oct 6 10:03:34 2022 +0200 Skip `unexpected metric type` * Dump more info for `unexpected metric type` * Skip `unexpected metric type` commitaf6a5cd96aAuthor: Andronik <write@reusable.software> Date: Thu Oct 6 00:36:51 2022 +0200 update kvdb & co (#6111) * toml changes * REVERTME: patch * adapt parachains db interface * fix Cargo.toml patch after master rebase * fix av-store * fix chain-selection * fix parachains-db? * Revert "fix Cargo.toml patch after master rebase" This reverts commit 3afcbf033c86027b3f2b909d83ec703591bdd287. * Revert "REVERTME: patch" This reverts commit 464b717cf4142d3d09c3d77b83700b632d8c5f54. * Use `Ok` imported from prelude Co-authored-by: Bastian Köcher <info@kchr.de> * update lockfile for {"substrate"} * Revert "update lockfile for {"substrate"}" This reverts commit fdc623de226f7645741b86c4b1a7d030fed2172d. * cargo update -p sp-io Co-authored-by: Bastian Köcher <info@kchr.de> Co-authored-by: parity-processbot <> commit9a3cf4cd1fAuthor: Gavin Wood <gavin@parity.io> Date: Wed Oct 5 22:17:59 2022 +0100 Companion for #11649: Bound uses of `Call` (#5729) * Fixes * Clear out old weights Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Resolve merges Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Fix weight traits Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * polkadot runtime: Clippy Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * rococo runtime: update pallet configs Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Add preimage migration Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Add all migrations Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Democracy is not on Westend Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * [Migration] Refund stored multisig calls (#6075) * Add Preimages to referenda config Needed since Gov V2 just merged. Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Update weights Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Add multisig migration to Westend+Rococo Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Fix Executive syntax Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Bump Substrate Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: parity-processbot <> Co-authored-by: Roman Useinov <roman.useinov@gmail.com> commit4aea71a95fAuthor: Alexander Theißen <alex.theissen@me.com> Date: Wed Oct 5 15:15:07 2022 +0200 Pass through `runtime-benchmark` feature (#6110) commit42c043d7f4Author: Keith Yeung <kungfukeith11@gmail.com> Date: Wed Oct 5 17:47:15 2022 +0800 Properly migrate weights to v2 (#6091) * Create migration for config pallet * Use XcmWeight in XCM pallet extrinsics * Link to PR in doc comment * cargo fmt * Fix tests * Fix tests * Remove unused import * Update runtime/parachains/src/configuration/migration.rs Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Add missing on_runtime_upgrade implementation * Use new migration API * cargo fmt * Fix log message Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> commitb13e07bc47Author: Chris Sosnin <48099298+slumber@users.noreply.github.com> Date: Wed Oct 5 11:48:50 2022 +0400 Buffered connection management for collator-protocol (#6022) * Extract metrics into a separate module * Introduce validators buffer * Integrate buffer into the subsystem * Only reconnect on new advertisements * Test * comma * doc comment * Make capacity buffer compile time non-zero * Add doc comments * nits * remove derives * review * better naming * check timeout * Extract interval stream into lib * Ensure collator disconnects after timeout * spellcheck * rename buf * Remove double interval * Add a log on timeout * Cleanup buffer on timeout commite0e836671fAuthor: Robert Klotzner <eskimor@users.noreply.github.com> Date: Tue Oct 4 18:47:52 2022 +0200 Add unknown words (#6105) commit938bc96a2cAuthor: Robert Klotzner <eskimor@users.noreply.github.com> Date: Tue Oct 4 18:02:05 2022 +0200 Batch vote import in dispute-distribution (#5894) * Start work on batching in dispute-distribution. * Guide work. * More guide changes. Still very much WIP. * Finish guide changes. * Clarification * Adjust argument about slashing. * WIP: Add constants to receiver. * Maintain order of disputes. * dispute-distribuion sender Rate limit. * Cleanup * WIP: dispute-distribution receiver. - [ ] Rate limiting - [ ] Batching * WIP: Batching. * fmt * Update `PeerQueues` to maintain more invariants. * WIP: Batching. * Small cleanup * Batching logic. * Some integration work. * Finish. Missing: Tests * Typo. * Docs. * Report missing metric. * Doc pass. * Tests for waiting_queue. * Speed up some crypto by 10x. * Fix redundant import. * Add some tracing. * Better sender rate limit * Some tests. * Tests * Add logging to rate limiter * Update roadmap/implementers-guide/src/node/disputes/dispute-distribution.md Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io> * Update roadmap/implementers-guide/src/node/disputes/dispute-distribution.md Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io> * Update node/network/dispute-distribution/src/receiver/mod.rs Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io> * Review feedback. * Also log peer in log messages. * Fix indentation. * waker -> timer * Guide improvement. * Remove obsolete comment. * waker -> timer * Fix spell complaints. * Fix Cargo.lock Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io> commita64cc4a860Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue Oct 4 11:28:21 2022 +0000 Bump lru from 0.7.8 to 0.8.0 (#6060) * Bump lru from 0.7.8 to 0.8.0 Bumps [lru](https://github.com/jeromefroe/lru-rs) from 0.7.8 to 0.8.0. - [Release notes](https://github.com/jeromefroe/lru-rs/releases) - [Changelog](https://github.com/jeromefroe/lru-rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/jeromefroe/lru-rs/compare/0.7.8...0.8.0) --- updated-dependencies: - dependency-name: lru dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * Change `LruCache` paramerter to `NonZeroUsize` * Change type of `session_cache_lru_size` to `NonZeroUsize` * Add expects instead of unwrap Co-authored-by: Bastian Köcher <info@kchr.de> * Use match to get rid of expects Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Sebastian Kunert <skunert49@gmail.com> Co-authored-by: Bastian Köcher <info@kchr.de> commit7114a8cfcaAuthor: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Date: Tue Oct 4 13:36:42 2022 +0300 Keep sessions in window for the full unfinalized chain (#6054) * Impl dynamic window size. Keep sessions for unfinalized chain Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * feedback Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Stretch also in contructor plus tests Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * review feedback Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * fix approval-voting tests Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * grunting: dispute coordinator tests Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> commitab8f04f827Author: Serban Iorga <serban@parity.io> Date: Tue Oct 4 12:25:48 2022 +0300 Companion for BEEFY: Simplify hashing for pallet-beefy-mmr (#6098) * beefy-mmr: Simplify hashing * update lockfile for {"substrate"} Co-authored-by: parity-processbot <> * Revert "Squashed commit of the following:" This reverts commit 5001fa5d1dcd366029d156f81c40b99ca29d8f77. * Companion for BEEFY: Simplify hashing for pallet-beefy-mmr (#6098) * beefy-mmr: Simplify hashing * update lockfile for {"substrate"} Co-authored-by: parity-processbot <> * Keep sessions in window for the full unfinalized chain (#6054) * Impl dynamic window size. Keep sessions for unfinalized chain Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * feedback Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Stretch also in contructor plus tests Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * review feedback Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * fix approval-voting tests Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * grunting: dispute coordinator tests Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Bump lru from 0.7.8 to 0.8.0 (#6060) * Bump lru from 0.7.8 to 0.8.0 Bumps [lru](https://github.com/jeromefroe/lru-rs) from 0.7.8 to 0.8.0. - [Release notes](https://github.com/jeromefroe/lru-rs/releases) - [Changelog](https://github.com/jeromefroe/lru-rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/jeromefroe/lru-rs/compare/0.7.8...0.8.0) --- updated-dependencies: - dependency-name: lru dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * Change `LruCache` paramerter to `NonZeroUsize` * Change type of `session_cache_lru_size` to `NonZeroUsize` * Add expects instead of unwrap Co-authored-by: Bastian Köcher <info@kchr.de> * Use match to get rid of expects Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Sebastian Kunert <skunert49@gmail.com> Co-authored-by: Bastian Köcher <info@kchr.de> * Batch vote import in dispute-distribution (#5894) * Start work on batching in dispute-distribution. * Guide work. * More guide changes. Still very much WIP. * Finish guide changes. * Clarification * Adjust argument about slashing. * WIP: Add constants to receiver. * Maintain order of disputes. * dispute-distribuion sender Rate limit. * Cleanup * WIP: dispute-distribution receiver. - [ ] Rate limiting - [ ] Batching * WIP: Batching. * fmt * Update `PeerQueues` to maintain more invariants. * WIP: Batching. * Small cleanup * Batching logic. * Some integration work. * Finish. Missing: Tests * Typo. * Docs. * Report missing metric. * Doc pass. * Tests for waiting_queue. * Speed up some crypto by 10x. * Fix redundant import. * Add some tracing. * Better sender rate limit * Some tests. * Tests * Add logging to rate limiter * Update roadmap/implementers-guide/src/node/disputes/dispute-distribution.md Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io> * Update roadmap/implementers-guide/src/node/disputes/dispute-distribution.md Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io> * Update node/network/dispute-distribution/src/receiver/mod.rs Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io> * Review feedback. * Also log peer in log messages. * Fix indentation. * waker -> timer * Guide improvement. * Remove obsolete comment. * waker -> timer * Fix spell complaints. * Fix Cargo.lock Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io> * Add unknown words (#6105) * Buffered connection management for collator-protocol (#6022) * Extract metrics into a separate module * Introduce validators buffer * Integrate buffer into the subsystem * Only reconnect on new advertisements * Test * comma * doc comment * Make capacity buffer compile time non-zero * Add doc comments * nits * remove derives * review * better naming * check timeout * Extract interval stream into lib * Ensure collator disconnects after timeout * spellcheck * rename buf * Remove double interval * Add a log on timeout * Cleanup buffer on timeout * Properly migrate weights to v2 (#6091) * Create migration for config pallet * Use XcmWeight in XCM pallet extrinsics * Link to PR in doc comment * cargo fmt * Fix tests * Fix tests * Remove unused import * Update runtime/parachains/src/configuration/migration.rs Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Add missing on_runtime_upgrade implementation * Use new migration API * cargo fmt * Fix log message Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Pass through `runtime-benchmark` feature (#6110) * Companion for #11649: Bound uses of `Call` (#5729) * Fixes * Clear out old weights Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Resolve merges Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Fix weight traits Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * polkadot runtime: Clippy Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * rococo runtime: update pallet configs Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Add preimage migration Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Add all migrations Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Democracy is not on Westend Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * [Migration] Refund stored multisig calls (#6075) * Add Preimages to referenda config Needed since Gov V2 just merged. Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Update weights Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Add multisig migration to Westend+Rococo Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Fix Executive syntax Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Bump Substrate Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: parity-processbot <> Co-authored-by: Roman Useinov <roman.useinov@gmail.com> * update kvdb & co (#6111) * toml changes * REVERTME: patch * adapt parachains db interface * fix Cargo.toml patch after master rebase * fix av-store * fix chain-selection * fix parachains-db? * Revert "fix Cargo.toml patch after master rebase" This reverts commit 3afcbf033c86027b3f2b909d83ec703591bdd287. * Revert "REVERTME: patch" This reverts commit 464b717cf4142d3d09c3d77b83700b632d8c5f54. * Use `Ok` imported from prelude Co-authored-by: Bastian Köcher <info@kchr.de> * update lockfile for {"substrate"} * Revert "update lockfile for {"substrate"}" This reverts commit fdc623de226f7645741b86c4b1a7d030fed2172d. * cargo update -p sp-io Co-authored-by: Bastian Köcher <info@kchr.de> Co-authored-by: parity-processbot <> * Skip `unexpected metric type` * Dump more info for `unexpected metric type` * Skip `unexpected metric type` * service: use MmrRootProvider as custom BEEFY payload provider (companion for 12428) (#6112) * service: use MmrRootProvider as custom BEEFY payload provider * update lockfile for {"substrate"} Co-authored-by: parity-processbot <> * Maximum value for `MultiplierUpdate` (#6021) * update multiplier * fix * update lockfile for {"substrate"} * fmt * fix typo Co-authored-by: parity-processbot <> * Companion for upgrading pin-project (#6118) * Companion for upgrading pin-project This will remove some warnings with the latest rustc nightly/stable. https://github.com/paritytech/substrate/pull/12426 * update lockfile for {"substrate"} Co-authored-by: parity-processbot <> * Companion for 12109 (#5929) * Update following `pallet-vesting` configurable `WithdrawReasons` * Update lib.rs * Update lib.rs * Update lib.rs * update lockfile for {"substrate"} * fix warning Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> Co-authored-by: parity-processbot <> * Add event to asset claim (#6029) * Fix flaky test (#6131) * Split test + decrease test timeout * fmt * spellcheck * ci/guide: install mdbook-graphviz (#6119) * ci/guide: install mdbook-graphviz * install graphviz in build-implementers-guide * Update scripts/ci/gitlab/pipeline/build.yml Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> * Revert "Squashed commit of the following:" This reverts commit 5001fa5d1dcd366029d156f81c40b99ca29d8f77. * * Remove unused imports * * cargo +nightly fmt --all * Make tweaks based on PR comments * unit test related to gum formatting * cargo +nightly fmt --all * Resolve merge conflicts * cargo +nightly fmt --all * Fix tests so they use cli rather than cmd * CI unused import check fix * Move info! log to startup * make info log more comprehensible Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Serban Iorga <serban@parity.io> Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Sebastian Kunert <skunert49@gmail.com> Co-authored-by: Bastian Köcher <info@kchr.de> Co-authored-by: Robert Klotzner <eskimor@users.noreply.github.com> Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io> Co-authored-by: Chris Sosnin <48099298+slumber@users.noreply.github.com> Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Alexander Theißen <alex.theissen@me.com> Co-authored-by: Gavin Wood <gavin@parity.io> Co-authored-by: Roman Useinov <roman.useinov@gmail.com> Co-authored-by: Andronik <write@reusable.software> Co-authored-by: Branislav Kontur <bkontur@gmail.com> Co-authored-by: Adrian Catangiu <adrian@parity.io> Co-authored-by: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Co-authored-by: Leszek Wiesner <leszek@jsgenesis.com> Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> Co-authored-by: girazoki <gorka.irazoki@gmail.com> Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
a7780e0797
commit
b3532393b8
Generated
+10
-9
@@ -922,16 +922,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.1.18"
|
||||
version = "3.2.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b"
|
||||
checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"clap_derive",
|
||||
"clap_lex",
|
||||
"indexmap",
|
||||
"lazy_static",
|
||||
"once_cell",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
"textwrap",
|
||||
@@ -939,9 +939,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "3.1.18"
|
||||
version = "3.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25320346e922cffe59c0bbc5410c8d8784509efb321488971081313cb1e1a33c"
|
||||
checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
@@ -952,9 +952,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.2.0"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213"
|
||||
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
@@ -7470,6 +7470,7 @@ dependencies = [
|
||||
"polkadot-node-subsystem-types",
|
||||
"polkadot-node-subsystem-util",
|
||||
"polkadot-primitives",
|
||||
"rand 0.8.5",
|
||||
"sp-core",
|
||||
"sp-keystore",
|
||||
"tracing-gum",
|
||||
@@ -11391,9 +11392,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.15.0"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
||||
checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
|
||||
@@ -29,11 +29,12 @@ assert_matches = "1.5"
|
||||
async-trait = "0.1.57"
|
||||
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
clap = { version = "3.1", features = ["derive"] }
|
||||
clap = { version = "3.2.21", features = ["derive"] }
|
||||
futures = "0.3.21"
|
||||
futures-timer = "3.0.2"
|
||||
gum = { package = "tracing-gum", path = "../gum/" }
|
||||
erasure = { package = "polkadot-erasure-coding", path = "../../erasure-coding" }
|
||||
rand = "0.8.5"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
use clap::Parser;
|
||||
use color_eyre::eyre;
|
||||
use polkadot_cli::Cli;
|
||||
|
||||
pub(crate) mod interceptor;
|
||||
pub(crate) mod shared;
|
||||
@@ -33,9 +32,9 @@ use variants::*;
|
||||
#[clap(rename_all = "kebab-case")]
|
||||
enum NemesisVariant {
|
||||
/// Suggest a candidate with an invalid proof of validity.
|
||||
SuggestGarbageCandidate(Cli),
|
||||
SuggestGarbageCandidate(SuggestGarbageCandidateOptions),
|
||||
/// Back a candidate with a specifically crafted proof of validity.
|
||||
BackGarbageCandidate(Cli),
|
||||
BackGarbageCandidate(BackGarbageCandidateOptions),
|
||||
/// Delayed disputing of ancestors that are perfectly fine.
|
||||
DisputeAncestor(DisputeAncestorOptions),
|
||||
|
||||
@@ -62,16 +61,31 @@ impl MalusCli {
|
||||
fn launch(self) -> eyre::Result<()> {
|
||||
let finality_delay = self.finality_delay;
|
||||
match self.variant {
|
||||
NemesisVariant::BackGarbageCandidate(cli) =>
|
||||
polkadot_cli::run_node(cli, BackGarbageCandidate, finality_delay)?,
|
||||
NemesisVariant::SuggestGarbageCandidate(cli) =>
|
||||
polkadot_cli::run_node(cli, BackGarbageCandidateWrapper, finality_delay)?,
|
||||
NemesisVariant::DisputeAncestor(opts) => {
|
||||
let DisputeAncestorOptions { fake_validation, fake_validation_error, cli } = opts;
|
||||
NemesisVariant::BackGarbageCandidate(opts) => {
|
||||
let BackGarbageCandidateOptions { percentage, cli } = opts;
|
||||
|
||||
polkadot_cli::run_node(cli, BackGarbageCandidates { percentage }, finality_delay)?
|
||||
},
|
||||
NemesisVariant::SuggestGarbageCandidate(opts) => {
|
||||
let SuggestGarbageCandidateOptions { percentage, cli } = opts;
|
||||
|
||||
polkadot_cli::run_node(
|
||||
cli,
|
||||
DisputeValidCandidates { fake_validation, fake_validation_error },
|
||||
SuggestGarbageCandidates { percentage },
|
||||
finality_delay,
|
||||
)?
|
||||
},
|
||||
NemesisVariant::DisputeAncestor(opts) => {
|
||||
let DisputeAncestorOptions {
|
||||
fake_validation,
|
||||
fake_validation_error,
|
||||
percentage,
|
||||
cli,
|
||||
} = opts;
|
||||
|
||||
polkadot_cli::run_node(
|
||||
cli,
|
||||
DisputeValidCandidates { fake_validation, fake_validation_error, percentage },
|
||||
finality_delay,
|
||||
)?
|
||||
},
|
||||
@@ -129,4 +143,77 @@ mod tests {
|
||||
assert!(run.cli.run.base.bob);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn percentage_works_suggest_garbage() {
|
||||
let cli = MalusCli::try_parse_from(IntoIterator::into_iter([
|
||||
"malus",
|
||||
"suggest-garbage-candidate",
|
||||
"--percentage",
|
||||
"100",
|
||||
"--bob",
|
||||
]))
|
||||
.unwrap();
|
||||
assert_matches::assert_matches!(cli, MalusCli {
|
||||
variant: NemesisVariant::SuggestGarbageCandidate(run),
|
||||
..
|
||||
} => {
|
||||
assert!(run.cli.run.base.bob);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn percentage_works_dispute_ancestor() {
|
||||
let cli = MalusCli::try_parse_from(IntoIterator::into_iter([
|
||||
"malus",
|
||||
"dispute-ancestor",
|
||||
"--percentage",
|
||||
"100",
|
||||
"--bob",
|
||||
]))
|
||||
.unwrap();
|
||||
assert_matches::assert_matches!(cli, MalusCli {
|
||||
variant: NemesisVariant::DisputeAncestor(run),
|
||||
..
|
||||
} => {
|
||||
assert!(run.cli.run.base.bob);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn percentage_works_back_garbage() {
|
||||
let cli = MalusCli::try_parse_from(IntoIterator::into_iter([
|
||||
"malus",
|
||||
"back-garbage-candidate",
|
||||
"--percentage",
|
||||
"100",
|
||||
"--bob",
|
||||
]))
|
||||
.unwrap();
|
||||
assert_matches::assert_matches!(cli, MalusCli {
|
||||
variant: NemesisVariant::BackGarbageCandidate(run),
|
||||
..
|
||||
} => {
|
||||
assert!(run.cli.run.base.bob);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn validate_range_for_percentage() {
|
||||
let cli = MalusCli::try_parse_from(IntoIterator::into_iter([
|
||||
"malus",
|
||||
"suggest-garbage-candidate",
|
||||
"--percentage",
|
||||
"101",
|
||||
"--bob",
|
||||
]))
|
||||
.unwrap();
|
||||
assert_matches::assert_matches!(cli, MalusCli {
|
||||
variant: NemesisVariant::DisputeAncestor(run),
|
||||
..
|
||||
} => {
|
||||
assert!(run.cli.run.base.bob);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ use polkadot_cli::{
|
||||
OverseerConnector, OverseerGen, OverseerGenArgs, OverseerHandle, ParachainHost,
|
||||
ProvideRuntimeApi,
|
||||
},
|
||||
Cli,
|
||||
};
|
||||
use polkadot_node_subsystem::SpawnGlue;
|
||||
use sp_core::traits::SpawnNamed;
|
||||
@@ -36,11 +37,27 @@ use crate::{
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug, clap::Parser)]
|
||||
#[clap(rename_all = "kebab-case")]
|
||||
#[allow(missing_docs)]
|
||||
pub struct BackGarbageCandidateOptions {
|
||||
/// Determines the percentage of garbage candidates that should be backed.
|
||||
/// Defaults to 100% of garbage candidates being backed.
|
||||
#[clap(short, long, ignore_case = true, default_value_t = 100, value_parser = clap::value_parser!(u8).range(0..=100))]
|
||||
pub percentage: u8,
|
||||
|
||||
#[clap(flatten)]
|
||||
pub cli: Cli,
|
||||
}
|
||||
|
||||
/// Generates an overseer that replaces the candidate validation subsystem with our malicious
|
||||
/// variant.
|
||||
pub(crate) struct BackGarbageCandidate;
|
||||
pub(crate) struct BackGarbageCandidates {
|
||||
/// The probability of behaving maliciously.
|
||||
pub percentage: u8,
|
||||
}
|
||||
|
||||
impl OverseerGen for BackGarbageCandidate {
|
||||
impl OverseerGen for BackGarbageCandidates {
|
||||
fn generate<'a, Spawner, RuntimeClient>(
|
||||
&self,
|
||||
connector: OverseerConnector,
|
||||
@@ -55,6 +72,7 @@ impl OverseerGen for BackGarbageCandidate {
|
||||
let validation_filter = ReplaceValidationResult::new(
|
||||
FakeCandidateValidation::BackingAndApprovalValid,
|
||||
FakeCandidateValidationError::InvalidOutputs,
|
||||
f64::from(self.percentage),
|
||||
SpawnGlue(spawner),
|
||||
);
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ use polkadot_primitives::v2::{
|
||||
|
||||
use futures::channel::oneshot;
|
||||
|
||||
use rand::distributions::{Bernoulli, Distribution};
|
||||
|
||||
#[derive(clap::ArgEnum, Clone, Copy, Debug, PartialEq)]
|
||||
#[clap(rename_all = "kebab-case")]
|
||||
#[non_exhaustive]
|
||||
@@ -109,6 +111,7 @@ impl Into<InvalidCandidate> for FakeCandidateValidationError {
|
||||
pub struct ReplaceValidationResult<Spawner> {
|
||||
fake_validation: FakeCandidateValidation,
|
||||
fake_validation_error: FakeCandidateValidationError,
|
||||
distribution: Bernoulli,
|
||||
spawner: Spawner,
|
||||
}
|
||||
|
||||
@@ -119,9 +122,12 @@ where
|
||||
pub fn new(
|
||||
fake_validation: FakeCandidateValidation,
|
||||
fake_validation_error: FakeCandidateValidationError,
|
||||
percentage: f64,
|
||||
spawner: Spawner,
|
||||
) -> Self {
|
||||
Self { fake_validation, fake_validation_error, spawner }
|
||||
let distribution = Bernoulli::new(percentage / 100.0)
|
||||
.expect("Invalid probability! Percentage must be in range [0..=100].");
|
||||
Self { fake_validation, fake_validation_error, distribution, spawner }
|
||||
}
|
||||
|
||||
/// Creates and sends the validation response for a given candidate. Queries the runtime to obtain the validation data for the
|
||||
@@ -202,13 +208,14 @@ where
|
||||
{
|
||||
type Message = CandidateValidationMessage;
|
||||
|
||||
// Capture all candidate validation requests and depending on configuration fail them.
|
||||
// Capture all (approval and backing) candidate validation requests and depending on configuration fail them.
|
||||
fn intercept_incoming(
|
||||
&self,
|
||||
subsystem_sender: &mut Sender,
|
||||
msg: FromOrchestra<Self::Message>,
|
||||
) -> Option<FromOrchestra<Self::Message>> {
|
||||
match msg {
|
||||
// Message sent by the approval voting subsystem
|
||||
FromOrchestra::Communication {
|
||||
msg:
|
||||
CandidateValidationMessage::ValidateFromExhaustive(
|
||||
@@ -236,28 +243,84 @@ where
|
||||
),
|
||||
})
|
||||
}
|
||||
create_validation_response(
|
||||
validation_data,
|
||||
candidate_receipt.descriptor,
|
||||
sender,
|
||||
);
|
||||
None
|
||||
// Create the fake response with probability `p` if the `PoV` is malicious,
|
||||
// where 'p' defaults to 100% for suggest-garbage-candidate variant.
|
||||
let behave_maliciously = self.distribution.sample(&mut rand::thread_rng());
|
||||
match behave_maliciously {
|
||||
true => {
|
||||
gum::info!(
|
||||
target: MALUS,
|
||||
?behave_maliciously,
|
||||
"😈 Creating malicious ValidationResult::Valid message with fake candidate commitments.",
|
||||
);
|
||||
|
||||
create_validation_response(
|
||||
validation_data,
|
||||
candidate_receipt.descriptor,
|
||||
sender,
|
||||
);
|
||||
None
|
||||
},
|
||||
false => {
|
||||
// Behave normally with probability `(1-p)` for a malicious `PoV`.
|
||||
gum::info!(
|
||||
target: MALUS,
|
||||
?behave_maliciously,
|
||||
"😈 Passing CandidateValidationMessage::ValidateFromExhaustive to the candidate validation subsystem.",
|
||||
);
|
||||
|
||||
Some(FromOrchestra::Communication {
|
||||
msg: CandidateValidationMessage::ValidateFromExhaustive(
|
||||
validation_data,
|
||||
validation_code,
|
||||
candidate_receipt,
|
||||
pov,
|
||||
timeout,
|
||||
sender,
|
||||
),
|
||||
})
|
||||
},
|
||||
}
|
||||
},
|
||||
FakeCandidateValidation::ApprovalInvalid |
|
||||
FakeCandidateValidation::BackingAndApprovalInvalid => {
|
||||
let validation_result =
|
||||
ValidationResult::Invalid(InvalidCandidate::InvalidOutputs);
|
||||
// Set the validation result to invalid with probability `p` and trigger a dispute
|
||||
let behave_maliciously = self.distribution.sample(&mut rand::thread_rng());
|
||||
match behave_maliciously {
|
||||
true => {
|
||||
let validation_result =
|
||||
ValidationResult::Invalid(InvalidCandidate::InvalidOutputs);
|
||||
|
||||
gum::debug!(
|
||||
target: MALUS,
|
||||
para_id = ?candidate_receipt.descriptor.para_id,
|
||||
"ValidateFromExhaustive result: {:?}",
|
||||
&validation_result
|
||||
);
|
||||
// We're not even checking the candidate, this makes us appear faster than honest validators.
|
||||
sender.send(Ok(validation_result)).unwrap();
|
||||
None
|
||||
gum::info!(
|
||||
target: MALUS,
|
||||
?behave_maliciously,
|
||||
para_id = ?candidate_receipt.descriptor.para_id,
|
||||
"😈 Maliciously sending invalid validation result: {:?}.",
|
||||
&validation_result,
|
||||
);
|
||||
|
||||
// We're not even checking the candidate, this makes us appear faster than honest validators.
|
||||
sender.send(Ok(validation_result)).unwrap();
|
||||
None
|
||||
},
|
||||
false => {
|
||||
// Behave normally with probability `(1-p)`
|
||||
gum::info!(target: MALUS, "😈 'Decided' to not act maliciously.",);
|
||||
|
||||
Some(FromOrchestra::Communication {
|
||||
msg: CandidateValidationMessage::ValidateFromExhaustive(
|
||||
validation_data,
|
||||
validation_code,
|
||||
candidate_receipt,
|
||||
pov,
|
||||
timeout,
|
||||
sender,
|
||||
),
|
||||
})
|
||||
},
|
||||
}
|
||||
},
|
||||
// Handle FakeCandidateValidation::Disabled
|
||||
_ => Some(FromOrchestra::Communication {
|
||||
msg: CandidateValidationMessage::ValidateFromExhaustive(
|
||||
validation_data,
|
||||
@@ -270,6 +333,7 @@ where
|
||||
}),
|
||||
}
|
||||
},
|
||||
// Behaviour related to the backing subsystem
|
||||
FromOrchestra::Communication {
|
||||
msg:
|
||||
CandidateValidationMessage::ValidateFromChainState(
|
||||
@@ -293,27 +357,68 @@ where
|
||||
),
|
||||
})
|
||||
}
|
||||
self.send_validation_response(
|
||||
candidate_receipt.descriptor,
|
||||
subsystem_sender.clone(),
|
||||
response_sender,
|
||||
);
|
||||
None
|
||||
// If the `PoV` is malicious, back the candidate with some probability `p`,
|
||||
// where 'p' defaults to 100% for suggest-garbage-candidate variant.
|
||||
let behave_maliciously = self.distribution.sample(&mut rand::thread_rng());
|
||||
match behave_maliciously {
|
||||
true => {
|
||||
gum::info!(
|
||||
target: MALUS,
|
||||
?behave_maliciously,
|
||||
"😈 Backing candidate with malicious PoV.",
|
||||
);
|
||||
|
||||
self.send_validation_response(
|
||||
candidate_receipt.descriptor,
|
||||
subsystem_sender.clone(),
|
||||
response_sender,
|
||||
);
|
||||
None
|
||||
},
|
||||
// If the `PoV` is malicious, we behave normally with some probability `(1-p)`
|
||||
false => Some(FromOrchestra::Communication {
|
||||
msg: CandidateValidationMessage::ValidateFromChainState(
|
||||
candidate_receipt,
|
||||
pov,
|
||||
timeout,
|
||||
response_sender,
|
||||
),
|
||||
}),
|
||||
}
|
||||
},
|
||||
FakeCandidateValidation::BackingInvalid |
|
||||
FakeCandidateValidation::BackingAndApprovalInvalid => {
|
||||
let validation_result =
|
||||
ValidationResult::Invalid(self.fake_validation_error.clone().into());
|
||||
gum::debug!(
|
||||
target: MALUS,
|
||||
para_id = ?candidate_receipt.descriptor.para_id,
|
||||
"ValidateFromChainState result: {:?}",
|
||||
&validation_result
|
||||
);
|
||||
// Maliciously set the validation result to invalid for a valid candidate with probability `p`
|
||||
let behave_maliciously = self.distribution.sample(&mut rand::thread_rng());
|
||||
match behave_maliciously {
|
||||
true => {
|
||||
let validation_result = ValidationResult::Invalid(
|
||||
self.fake_validation_error.clone().into(),
|
||||
);
|
||||
gum::info!(
|
||||
target: MALUS,
|
||||
para_id = ?candidate_receipt.descriptor.para_id,
|
||||
"😈 Maliciously sending invalid validation result: {:?}.",
|
||||
&validation_result,
|
||||
);
|
||||
// We're not even checking the candidate, this makes us appear faster than honest validators.
|
||||
response_sender.send(Ok(validation_result)).unwrap();
|
||||
None
|
||||
},
|
||||
// With some probability `(1-p)` we behave normally
|
||||
false => {
|
||||
gum::info!(target: MALUS, "😈 'Decided' to not act maliciously.",);
|
||||
|
||||
// We're not even checking the candidate, this makes us appear faster than honest validators.
|
||||
response_sender.send(Ok(validation_result)).unwrap();
|
||||
None
|
||||
Some(FromOrchestra::Communication {
|
||||
msg: CandidateValidationMessage::ValidateFromChainState(
|
||||
candidate_receipt,
|
||||
pov,
|
||||
timeout,
|
||||
response_sender,
|
||||
),
|
||||
})
|
||||
},
|
||||
}
|
||||
},
|
||||
_ => Some(FromOrchestra::Communication {
|
||||
msg: CandidateValidationMessage::ValidateFromChainState(
|
||||
|
||||
@@ -55,6 +55,11 @@ pub struct DisputeAncestorOptions {
|
||||
#[clap(long, arg_enum, ignore_case = true, default_value_t = FakeCandidateValidationError::InvalidOutputs)]
|
||||
pub fake_validation_error: FakeCandidateValidationError,
|
||||
|
||||
/// Determines the percentage of candidates that should be disputed. Allows for fine-tuning
|
||||
/// the intensity of the behavior of the malicious node. Value must be in the range [0..=100].
|
||||
#[clap(short, long, ignore_case = true, default_value_t = 100, value_parser = clap::value_parser!(u8).range(0..=100))]
|
||||
pub percentage: u8,
|
||||
|
||||
#[clap(flatten)]
|
||||
pub cli: Cli,
|
||||
}
|
||||
@@ -64,6 +69,8 @@ pub(crate) struct DisputeValidCandidates {
|
||||
pub fake_validation: FakeCandidateValidation,
|
||||
/// Fake validation error config.
|
||||
pub fake_validation_error: FakeCandidateValidationError,
|
||||
/// The probability of behaving maliciously.
|
||||
pub percentage: u8,
|
||||
}
|
||||
|
||||
impl OverseerGen for DisputeValidCandidates {
|
||||
@@ -81,6 +88,7 @@ impl OverseerGen for DisputeValidCandidates {
|
||||
let validation_filter = ReplaceValidationResult::new(
|
||||
self.fake_validation,
|
||||
self.fake_validation_error,
|
||||
f64::from(self.percentage),
|
||||
SpawnGlue(spawner.clone()),
|
||||
);
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ mod dispute_valid_candidates;
|
||||
mod suggest_garbage_candidate;
|
||||
|
||||
pub(crate) use self::{
|
||||
back_garbage_candidate::BackGarbageCandidate,
|
||||
back_garbage_candidate::{BackGarbageCandidateOptions, BackGarbageCandidates},
|
||||
dispute_valid_candidates::{DisputeAncestorOptions, DisputeValidCandidates},
|
||||
suggest_garbage_candidate::BackGarbageCandidateWrapper,
|
||||
suggest_garbage_candidate::{SuggestGarbageCandidateOptions, SuggestGarbageCandidates},
|
||||
};
|
||||
pub(crate) use common::*;
|
||||
|
||||
@@ -29,14 +29,17 @@ use polkadot_cli::{
|
||||
OverseerConnector, OverseerGen, OverseerGenArgs, OverseerHandle, ParachainHost,
|
||||
ProvideRuntimeApi,
|
||||
},
|
||||
Cli,
|
||||
};
|
||||
use polkadot_node_core_candidate_validation::find_validation_data;
|
||||
use polkadot_node_primitives::{AvailableData, BlockData, PoV};
|
||||
use polkadot_primitives::v2::{CandidateDescriptor, CandidateHash};
|
||||
use polkadot_primitives::v2::CandidateDescriptor;
|
||||
|
||||
use polkadot_node_subsystem_util::request_validators;
|
||||
use sp_core::traits::SpawnNamed;
|
||||
|
||||
use rand::distributions::{Bernoulli, Distribution};
|
||||
|
||||
// Filter wrapping related types.
|
||||
use crate::{
|
||||
interceptor::*,
|
||||
@@ -49,28 +52,16 @@ use crate::{
|
||||
|
||||
// Import extra types relevant to the particular
|
||||
// subsystem.
|
||||
use polkadot_node_subsystem::{
|
||||
messages::{CandidateBackingMessage, CollatorProtocolMessage},
|
||||
SpawnGlue,
|
||||
};
|
||||
use polkadot_node_subsystem::{messages::CandidateBackingMessage, SpawnGlue};
|
||||
use polkadot_primitives::v2::CandidateReceipt;
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
struct Inner {
|
||||
/// Maps malicious candidate hash to original candidate hash.
|
||||
/// It is used to replace outgoing collator protocol seconded messages.
|
||||
map: HashMap<CandidateHash, CandidateHash>,
|
||||
}
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Replace outgoing approval messages with disputes.
|
||||
#[derive(Clone)]
|
||||
struct NoteCandidate<Spawner> {
|
||||
inner: Arc<Mutex<Inner>>,
|
||||
spawner: Spawner,
|
||||
percentage: f64,
|
||||
}
|
||||
|
||||
impl<Sender, Spawner> MessageInterceptor<Sender> for NoteCandidate<Spawner>
|
||||
@@ -80,7 +71,7 @@ where
|
||||
{
|
||||
type Message = CandidateBackingMessage;
|
||||
|
||||
/// Intercept incoming `Second` requests from the `collator-protocol` subsystem. We take
|
||||
/// Intercept incoming `Second` requests from the `collator-protocol` subsystem.
|
||||
fn intercept_incoming(
|
||||
&self,
|
||||
subsystem_sender: &mut Sender,
|
||||
@@ -88,163 +79,174 @@ where
|
||||
) -> Option<FromOrchestra<Self::Message>> {
|
||||
match msg {
|
||||
FromOrchestra::Communication {
|
||||
msg: CandidateBackingMessage::Second(relay_parent, candidate, _pov),
|
||||
msg: CandidateBackingMessage::Second(relay_parent, ref candidate, ref _pov),
|
||||
} => {
|
||||
gum::debug!(
|
||||
target: MALUS,
|
||||
candidate_hash = ?candidate.hash(),
|
||||
?relay_parent,
|
||||
"Received request to second candidate"
|
||||
"Received request to second candidate",
|
||||
);
|
||||
|
||||
let pov = PoV { block_data: BlockData(MALICIOUS_POV.into()) };
|
||||
// Need to draw value from Bernoulli distribution with given probability of success defined by the clap parameter.
|
||||
// Note that clap parameter must be f64 since this is expected by the Bernoulli::new() function.
|
||||
// It must be converted from u8, due to the lack of support for the .range() call on u64 in the clap crate.
|
||||
let distribution = Bernoulli::new(self.percentage / 100.0)
|
||||
.expect("Invalid probability! Percentage must be in range [0..=100].");
|
||||
|
||||
let (sender, receiver) = std::sync::mpsc::channel();
|
||||
let mut new_sender = subsystem_sender.clone();
|
||||
let _candidate = candidate.clone();
|
||||
self.spawner.spawn_blocking(
|
||||
"malus-get-validation-data",
|
||||
Some("malus"),
|
||||
Box::pin(async move {
|
||||
gum::trace!(target: MALUS, "Requesting validators");
|
||||
let n_validators = request_validators(relay_parent, &mut new_sender)
|
||||
.await
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.len();
|
||||
gum::trace!(target: MALUS, "Validators {}", n_validators);
|
||||
match find_validation_data(&mut new_sender, &_candidate.descriptor()).await
|
||||
{
|
||||
Ok(Some((validation_data, validation_code))) => {
|
||||
sender
|
||||
.send((validation_data, validation_code, n_validators))
|
||||
.expect("channel is still open");
|
||||
},
|
||||
_ => {
|
||||
panic!("Unable to fetch validation data");
|
||||
},
|
||||
}
|
||||
}),
|
||||
);
|
||||
// Draw a random boolean from the Bernoulli distribution with probability of true equal to `p`.
|
||||
// We use `rand::thread_rng` as the source of randomness.
|
||||
let generate_malicious_candidate = distribution.sample(&mut rand::thread_rng());
|
||||
|
||||
let (validation_data, validation_code, n_validators) = receiver.recv().unwrap();
|
||||
if generate_malicious_candidate == true {
|
||||
gum::debug!(target: MALUS, "😈 Suggesting malicious candidate.",);
|
||||
|
||||
let validation_data_hash = validation_data.hash();
|
||||
let validation_code_hash = validation_code.hash();
|
||||
let validation_data_relay_parent_number = validation_data.relay_parent_number;
|
||||
let pov = PoV { block_data: BlockData(MALICIOUS_POV.into()) };
|
||||
|
||||
gum::trace!(
|
||||
target: MALUS,
|
||||
candidate_hash = ?candidate.hash(),
|
||||
?relay_parent,
|
||||
?n_validators,
|
||||
?validation_data_hash,
|
||||
?validation_code_hash,
|
||||
?validation_data_relay_parent_number,
|
||||
"Fetched validation data."
|
||||
);
|
||||
|
||||
let malicious_available_data =
|
||||
AvailableData { pov: Arc::new(pov.clone()), validation_data };
|
||||
|
||||
let pov_hash = pov.hash();
|
||||
let erasure_root = {
|
||||
let chunks =
|
||||
erasure::obtain_chunks_v1(n_validators as usize, &malicious_available_data)
|
||||
.unwrap();
|
||||
|
||||
let branches = erasure::branches(chunks.as_ref());
|
||||
branches.root()
|
||||
};
|
||||
|
||||
let (collator_id, collator_signature) = {
|
||||
use polkadot_primitives::v2::CollatorPair;
|
||||
use sp_core::crypto::Pair;
|
||||
|
||||
let collator_pair = CollatorPair::generate().0;
|
||||
let signature_payload = polkadot_primitives::v2::collator_signature_payload(
|
||||
&relay_parent,
|
||||
&candidate.descriptor().para_id,
|
||||
&validation_data_hash,
|
||||
&pov_hash,
|
||||
&validation_code_hash,
|
||||
let (sender, receiver) = std::sync::mpsc::channel();
|
||||
let mut new_sender = subsystem_sender.clone();
|
||||
let _candidate = candidate.clone();
|
||||
self.spawner.spawn_blocking(
|
||||
"malus-get-validation-data",
|
||||
Some("malus"),
|
||||
Box::pin(async move {
|
||||
gum::trace!(target: MALUS, "Requesting validators");
|
||||
let n_validators = request_validators(relay_parent, &mut new_sender)
|
||||
.await
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.len();
|
||||
gum::trace!(target: MALUS, "Validators {}", n_validators);
|
||||
match find_validation_data(&mut new_sender, &_candidate.descriptor())
|
||||
.await
|
||||
{
|
||||
Ok(Some((validation_data, validation_code))) => {
|
||||
sender
|
||||
.send((validation_data, validation_code, n_validators))
|
||||
.expect("channel is still open");
|
||||
},
|
||||
_ => {
|
||||
panic!("Unable to fetch validation data");
|
||||
},
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
(collator_pair.public(), collator_pair.sign(&signature_payload))
|
||||
};
|
||||
let (validation_data, validation_code, n_validators) = receiver.recv().unwrap();
|
||||
|
||||
let malicious_commitments =
|
||||
create_fake_candidate_commitments(&malicious_available_data.validation_data);
|
||||
let validation_data_hash = validation_data.hash();
|
||||
let validation_code_hash = validation_code.hash();
|
||||
let validation_data_relay_parent_number = validation_data.relay_parent_number;
|
||||
|
||||
let malicious_candidate = CandidateReceipt {
|
||||
descriptor: CandidateDescriptor {
|
||||
para_id: candidate.descriptor().para_id,
|
||||
relay_parent,
|
||||
collator: collator_id,
|
||||
persisted_validation_data_hash: validation_data_hash,
|
||||
pov_hash,
|
||||
erasure_root,
|
||||
signature: collator_signature,
|
||||
para_head: malicious_commitments.head_data.hash(),
|
||||
validation_code_hash,
|
||||
},
|
||||
commitments_hash: malicious_commitments.hash(),
|
||||
};
|
||||
let malicious_candidate_hash = malicious_candidate.hash();
|
||||
gum::trace!(
|
||||
target: MALUS,
|
||||
candidate_hash = ?candidate.hash(),
|
||||
?relay_parent,
|
||||
?n_validators,
|
||||
?validation_data_hash,
|
||||
?validation_code_hash,
|
||||
?validation_data_relay_parent_number,
|
||||
"Fetched validation data."
|
||||
);
|
||||
|
||||
gum::debug!(
|
||||
target: MALUS,
|
||||
candidate_hash = ?candidate.hash(),
|
||||
?malicious_candidate_hash,
|
||||
"Created malicious candidate"
|
||||
);
|
||||
let malicious_available_data =
|
||||
AvailableData { pov: Arc::new(pov.clone()), validation_data };
|
||||
|
||||
// Map malicious candidate to the original one. We need this mapping to send back the correct seconded statement
|
||||
// to the collators.
|
||||
self.inner
|
||||
.lock()
|
||||
.expect("bad lock")
|
||||
.map
|
||||
.insert(malicious_candidate_hash, candidate.hash());
|
||||
let pov_hash = pov.hash();
|
||||
let erasure_root = {
|
||||
let chunks = erasure::obtain_chunks_v1(
|
||||
n_validators as usize,
|
||||
&malicious_available_data,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let message = FromOrchestra::Communication {
|
||||
msg: CandidateBackingMessage::Second(relay_parent, malicious_candidate, pov),
|
||||
};
|
||||
let branches = erasure::branches(chunks.as_ref());
|
||||
branches.root()
|
||||
};
|
||||
|
||||
Some(message)
|
||||
let (collator_id, collator_signature) = {
|
||||
use polkadot_primitives::v2::CollatorPair;
|
||||
use sp_core::crypto::Pair;
|
||||
|
||||
let collator_pair = CollatorPair::generate().0;
|
||||
let signature_payload = polkadot_primitives::v2::collator_signature_payload(
|
||||
&relay_parent,
|
||||
&candidate.descriptor().para_id,
|
||||
&validation_data_hash,
|
||||
&pov_hash,
|
||||
&validation_code_hash,
|
||||
);
|
||||
|
||||
(collator_pair.public(), collator_pair.sign(&signature_payload))
|
||||
};
|
||||
|
||||
let malicious_commitments = create_fake_candidate_commitments(
|
||||
&malicious_available_data.validation_data,
|
||||
);
|
||||
|
||||
let malicious_candidate = CandidateReceipt {
|
||||
descriptor: CandidateDescriptor {
|
||||
para_id: candidate.descriptor().para_id,
|
||||
relay_parent,
|
||||
collator: collator_id,
|
||||
persisted_validation_data_hash: validation_data_hash,
|
||||
pov_hash,
|
||||
erasure_root,
|
||||
signature: collator_signature,
|
||||
para_head: malicious_commitments.head_data.hash(),
|
||||
validation_code_hash,
|
||||
},
|
||||
commitments_hash: malicious_commitments.hash(),
|
||||
};
|
||||
let malicious_candidate_hash = malicious_candidate.hash();
|
||||
|
||||
let message = FromOrchestra::Communication {
|
||||
msg: CandidateBackingMessage::Second(
|
||||
relay_parent,
|
||||
malicious_candidate,
|
||||
pov,
|
||||
),
|
||||
};
|
||||
|
||||
gum::info!(
|
||||
target: MALUS,
|
||||
candidate_hash = ?candidate.hash(),
|
||||
"😈 Intercepted CandidateBackingMessage::Second and created malicious candidate with hash: {:?}",
|
||||
&malicious_candidate_hash
|
||||
);
|
||||
Some(message)
|
||||
} else {
|
||||
Some(msg)
|
||||
}
|
||||
},
|
||||
FromOrchestra::Communication { msg } => Some(FromOrchestra::Communication { msg }),
|
||||
FromOrchestra::Signal(signal) => Some(FromOrchestra::Signal(signal)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn intercept_outgoing(
|
||||
&self,
|
||||
msg: overseer::CandidateBackingOutgoingMessages,
|
||||
) -> Option<overseer::CandidateBackingOutgoingMessages> {
|
||||
let msg = match msg {
|
||||
overseer::CandidateBackingOutgoingMessages::CollatorProtocolMessage(
|
||||
CollatorProtocolMessage::Seconded(relay_parent, statement),
|
||||
) => {
|
||||
// `parachain::collator-protocol: received an unexpected `CollationSeconded`: unknown statement statement=...`
|
||||
// TODO: Fix this error. We get this on colaltors because `malicious backing` creates a candidate that gets backed/included.
|
||||
// It is harmless for test parachain collators, but it will prevent cumulus based collators to make progress
|
||||
// as they wait for the relay chain to confirm the seconding of the collation.
|
||||
overseer::CandidateBackingOutgoingMessages::CollatorProtocolMessage(
|
||||
CollatorProtocolMessage::Seconded(relay_parent, statement),
|
||||
)
|
||||
},
|
||||
msg => msg,
|
||||
};
|
||||
Some(msg)
|
||||
}
|
||||
#[derive(Debug, clap::Parser)]
|
||||
#[clap(rename_all = "kebab-case")]
|
||||
#[allow(missing_docs)]
|
||||
pub struct SuggestGarbageCandidateOptions {
|
||||
/// Determines the percentage of malicious candidates that are suggested by malus,
|
||||
/// based on the total number of intercepted CandidateBacking
|
||||
/// Must be in the range [0..=100].
|
||||
#[clap(short, long, ignore_case = true, default_value_t = 100, value_parser = clap::value_parser!(u8).range(0..=100))]
|
||||
pub percentage: u8,
|
||||
|
||||
#[clap(flatten)]
|
||||
pub cli: Cli,
|
||||
}
|
||||
|
||||
/// Garbage candidate implementation wrapper which implements `OverseerGen` glue.
|
||||
pub(crate) struct BackGarbageCandidateWrapper;
|
||||
pub(crate) struct SuggestGarbageCandidates {
|
||||
/// The probability of behaving maliciously.
|
||||
pub percentage: u8,
|
||||
}
|
||||
|
||||
impl OverseerGen for BackGarbageCandidateWrapper {
|
||||
impl OverseerGen for SuggestGarbageCandidates {
|
||||
fn generate<'a, Spawner, RuntimeClient>(
|
||||
&self,
|
||||
connector: OverseerConnector,
|
||||
@@ -255,14 +257,21 @@ impl OverseerGen for BackGarbageCandidateWrapper {
|
||||
RuntimeClient::Api: ParachainHost<Block> + BabeApi<Block> + AuthorityDiscoveryApi<Block>,
|
||||
Spawner: 'static + SpawnNamed + Clone + Unpin,
|
||||
{
|
||||
let inner = Inner { map: std::collections::HashMap::new() };
|
||||
let inner_mut = Arc::new(Mutex::new(inner));
|
||||
let note_candidate =
|
||||
NoteCandidate { inner: inner_mut.clone(), spawner: SpawnGlue(args.spawner.clone()) };
|
||||
gum::info!(
|
||||
target: MALUS,
|
||||
"😈 Started Malus node with a {:?} percent chance of behaving maliciously for a given candidate.",
|
||||
&self.percentage,
|
||||
);
|
||||
|
||||
let note_candidate = NoteCandidate {
|
||||
spawner: SpawnGlue(args.spawner.clone()),
|
||||
percentage: f64::from(self.percentage),
|
||||
};
|
||||
let fake_valid_probability = 100.0;
|
||||
let validation_filter = ReplaceValidationResult::new(
|
||||
FakeCandidateValidation::BackingAndApprovalValid,
|
||||
FakeCandidateValidationError::InvalidOutputs,
|
||||
fake_valid_probability,
|
||||
SpawnGlue(args.spawner.clone()),
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user