From 93656e24e4a5188fbee39073c3de4e537823376e Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Mon, 14 Feb 2022 14:14:26 +0000 Subject: [PATCH 01/47] Implement fake validation results Signed-off-by: Andrei Sandu --- node/malus/src/malus.rs | 23 +++- .../src/variants/dispute_valid_candidates.rs | 119 ++++++++++++++++-- 2 files changed, 132 insertions(+), 10 deletions(-) diff --git a/node/malus/src/malus.rs b/node/malus/src/malus.rs index a94c195cf56c..023297b44343 100644 --- a/node/malus/src/malus.rs +++ b/node/malus/src/malus.rs @@ -16,7 +16,7 @@ //! A malus or nemesis node launch code. -use clap::{AppSettings, Parser}; +use clap::{AppSettings, ArgEnum, Parser}; use color_eyre::eyre; use polkadot_cli::{Cli, RunCmd}; @@ -48,11 +48,26 @@ enum NemesisVariant { PvfExecuteWorker(polkadot_cli::ValidationWorkerCommand), } +#[derive(ArgEnum, Clone, Debug, PartialEq)] +#[clap( + about = "Fake candidate validation - forces all `ValidateCandidate*` calls to return a configured result.", + version +)] +#[clap(rename_all = "kebab-case")] +pub(crate) enum FakeCandidateValidation { + None, + Invalid, + // TODO: impl valid. +} + #[derive(Debug, Parser)] #[allow(missing_docs)] struct MalusCli { #[clap(subcommand)] pub variant: NemesisVariant, + + #[clap(long, arg_enum, ignore_case = true, default_value = "None")] + pub fake_validation: FakeCandidateValidation, } fn run_cmd(run: RunCmd) -> Cli { @@ -67,8 +82,10 @@ impl MalusCli { polkadot_cli::run_node(run_cmd(cmd), BackGarbageCandidate)?, NemesisVariant::SuggestGarbageCandidate(cmd) => polkadot_cli::run_node(run_cmd(cmd), SuggestGarbageCandidate)?, - NemesisVariant::DisputeAncestor(cmd) => - polkadot_cli::run_node(run_cmd(cmd), DisputeValidCandidates)?, + NemesisVariant::DisputeAncestor(cmd) => polkadot_cli::run_node( + run_cmd(cmd), + DisputeValidCandidates::new(self.fake_validation), + )?, NemesisVariant::PvfPrepareWorker(cmd) => { #[cfg(target_os = "android")] { diff --git a/node/malus/src/variants/dispute_valid_candidates.rs b/node/malus/src/variants/dispute_valid_candidates.rs index aa5626c44bef..b5e62c182dd4 100644 --- a/node/malus/src/variants/dispute_valid_candidates.rs +++ b/node/malus/src/variants/dispute_valid_candidates.rs @@ -31,13 +31,17 @@ use polkadot_cli::{ }; // Filter wrapping related types. -use crate::interceptor::*; +use crate::{interceptor::*, shared::MALUS, FakeCandidateValidation}; +use polkadot_node_primitives::{InvalidCandidate, ValidationResult}; // Import extra types relevant to the particular // subsystem. use polkadot_node_core_backing::CandidateBackingSubsystem; +use polkadot_node_core_candidate_validation::CandidateValidationSubsystem; + use polkadot_node_subsystem::messages::{ - ApprovalDistributionMessage, CandidateBackingMessage, DisputeCoordinatorMessage, + ApprovalDistributionMessage, CandidateBackingMessage, CandidateValidationMessage, + DisputeCoordinatorMessage, }; use sp_keystore::SyncCryptoStorePtr; @@ -47,6 +51,9 @@ use std::sync::Arc; #[derive(Clone, Debug)] struct ReplaceApprovalsWithDisputes; +#[derive(Clone, Debug)] +struct ReplaceValidationResult(FakeCandidateValidation); + impl MessageInterceptor for ReplaceApprovalsWithDisputes where Sender: overseer::SubsystemSender + Clone + Send + 'static, @@ -75,6 +82,12 @@ where session, .. }) => { + tracing::info!( + target = MALUS, + para_id = ?candidate_receipt.descriptor.para_id, + ?candidate_hash, + "Disputing candidate", + ); // this would also dispute candidates we were not assigned to approve Some(AllMessages::DisputeCoordinator( DisputeCoordinatorMessage::IssueLocalStatement( @@ -90,8 +103,84 @@ where } } +impl MessageInterceptor for ReplaceValidationResult +where + Sender: overseer::SubsystemSender + Clone + Send + 'static, +{ + type Message = CandidateValidationMessage; + + // Capture all candidate validation requests and fail them. + // MaybeTODO: add option to configure the failure reason. + fn intercept_incoming( + &self, + _sender: &mut Sender, + msg: FromOverseer, + ) -> Option> { + if self.0 == FakeCandidateValidation::None { + return Some(msg) + } + + match msg { + FromOverseer::Communication { + msg: + CandidateValidationMessage::ValidateFromExhaustive(_, _, descriptor, _, _, sender), + } => { + let validation_result = ValidationResult::Invalid(InvalidCandidate::InvalidOutputs); + + tracing::info!( + target = MALUS, + para_id = ?descriptor.para_id, + candidate_hash = ?descriptor.para_head, + "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 + }, + FromOverseer::Communication { + msg: CandidateValidationMessage::ValidateFromChainState(descriptor, _, _, sender), + } => { + let validation_result = ValidationResult::Invalid(InvalidCandidate::InvalidOutputs); + + tracing::info!( + target = MALUS, + para_id = ?descriptor.para_id, + candidate_hash = ?descriptor.para_head, + "ValidateFromChainState 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 + }, + msg => Some(msg), + } + } + + fn intercept_outgoing(&self, msg: AllMessages) -> Option { + Some(msg) + } +} + /// Generates an overseer that disputes instead of approving valid candidates. -pub(crate) struct DisputeValidCandidates; +pub(crate) struct DisputeValidCandidates { + fake_candidate_validation: FakeCandidateValidation, +} + +impl Default for DisputeValidCandidates { + fn default() -> Self { + Self { fake_candidate_validation: FakeCandidateValidation::None } + } +} + +impl DisputeValidCandidates { + pub fn new(fake_candidate_validation: FakeCandidateValidation) -> Self { + Self { fake_candidate_validation } + } +} impl OverseerGen for DisputeValidCandidates { fn generate<'a, Spawner, RuntimeClient>( @@ -106,13 +195,29 @@ impl OverseerGen for DisputeValidCandidates { { let spawner = args.spawner.clone(); let crypto_store_ptr = args.keystore.clone() as SyncCryptoStorePtr; - let filter = ReplaceApprovalsWithDisputes; + let backing_filter = ReplaceApprovalsWithDisputes; + let validation_filter = ReplaceValidationResult(self.fake_candidate_validation.clone()); + let candidate_validation_config = args.candidate_validation_config.clone(); prepared_overseer_builder(args)? - .replace_candidate_backing(move |cb| { + .replace_candidate_backing(move |cb_subsystem| { InterceptedSubsystem::new( - CandidateBackingSubsystem::new(spawner, crypto_store_ptr, cb.params.metrics), - filter, + CandidateBackingSubsystem::new( + spawner, + crypto_store_ptr, + cb_subsystem.params.metrics, + ), + backing_filter, + ) + }) + .replace_candidate_validation(move |cv_subsystem| { + InterceptedSubsystem::new( + CandidateValidationSubsystem::with_config( + candidate_validation_config, + cv_subsystem.metrics, + cv_subsystem.pvf_metrics, + ), + validation_filter, ) }) .build_with_connector(connector) From 2744e7556f745aee25d699b46a49e9f580b40dca Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Tue, 1 Mar 2022 11:32:58 +0000 Subject: [PATCH 02/47] refactor Signed-off-by: Andrei Sandu --- Cargo.lock | 386 ++++++++++-------- node/malus/src/malus.rs | 19 +- node/malus/src/variants/common.rs | 133 ++++++ .../src/variants/dispute_valid_candidates.rs | 94 +---- node/malus/src/variants/mod.rs | 2 + 5 files changed, 370 insertions(+), 264 deletions(-) create mode 100644 node/malus/src/variants/common.rs diff --git a/Cargo.lock b/Cargo.lock index e8ddc412c6bc..b15eac5d26b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -456,7 +456,7 @@ dependencies = [ "fnv", "futures 0.3.21", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.12.0", "sc-chain-spec", "sc-client-api", @@ -489,7 +489,7 @@ dependencies = [ "jsonrpc-derive", "jsonrpc-pubsub", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.12.0", "sc-rpc", "sc-utils", @@ -509,7 +509,7 @@ name = "beefy-primitives" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-api", "sp-application-crypto", @@ -728,7 +728,7 @@ dependencies = [ "bp-test-utils", "finality-grandpa", "frame-support", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "serde", "sp-core", @@ -743,7 +743,7 @@ version = "0.1.0" dependencies = [ "bp-runtime", "frame-support", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-std", ] @@ -757,7 +757,7 @@ dependencies = [ "frame-support", "frame-system", "impl-trait-for-tuples", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "serde", "sp-std", @@ -772,7 +772,7 @@ dependencies = [ "frame-support", "frame-system", "hex", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-api", "sp-core", @@ -789,7 +789,7 @@ dependencies = [ "bp-polkadot-core", "bp-runtime", "frame-support", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "smallvec", "sp-api", "sp-runtime", @@ -805,7 +805,7 @@ dependencies = [ "hash-db", "hex-literal", "num-traits", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-core", "sp-io", @@ -822,7 +822,7 @@ dependencies = [ "bp-header-chain", "ed25519-dalek", "finality-grandpa", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sp-application-crypto", "sp-finality-grandpa", "sp-runtime", @@ -837,7 +837,7 @@ dependencies = [ "bp-polkadot-core", "bp-rococo", "bp-runtime", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sp-api", "sp-runtime", "sp-std", @@ -857,7 +857,7 @@ dependencies = [ "pallet-bridge-grandpa", "pallet-bridge-messages", "pallet-transaction-payment", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-core", "sp-runtime", @@ -1977,7 +1977,7 @@ dependencies = [ "futures-timer", "log", "num-traits", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.11.2", "scale-info", ] @@ -2051,7 +2051,7 @@ name = "fork-tree" version = "3.0.0" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.0.0", ] [[package]] @@ -2073,7 +2073,7 @@ dependencies = [ "frame-system", "linregress", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "paste", "scale-info", "serde", @@ -2104,7 +2104,7 @@ dependencies = [ "linked-hash-map", "log", "memory-db", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "rand 0.8.5", "sc-cli", "sc-client-api", @@ -2134,7 +2134,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-arithmetic", "sp-npos-elections", @@ -2148,7 +2148,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-core", "sp-io", @@ -2164,7 +2164,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df6bb8542ef006ef0de09a5c4420787d79823c0ed7924225822362fd2bf2ff2d" dependencies = [ "cfg-if 1.0.0", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "serde", ] @@ -2180,7 +2180,7 @@ dependencies = [ "impl-trait-for-tuples", "log", "once_cell", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "paste", "scale-info", "serde", @@ -2240,7 +2240,7 @@ dependencies = [ "frame-support", "frame-support-test-pallet", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "pretty_assertions", "rustversion", "scale-info", @@ -2262,7 +2262,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", ] @@ -2273,7 +2273,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "frame-support", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "serde", "sp-core", @@ -2291,7 +2291,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-core", "sp-runtime", @@ -2303,7 +2303,7 @@ name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sp-api", ] @@ -2967,7 +2967,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.0.0", ] [[package]] @@ -3485,7 +3485,7 @@ dependencies = [ "pallet-utility", "pallet-vesting", "pallet-xcm", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-parachains", @@ -4957,7 +4957,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-runtime", "sp-std", @@ -4971,7 +4971,7 @@ dependencies = [ "frame-support", "frame-system", "pallet-session", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-application-crypto", "sp-authority-discovery", @@ -4987,7 +4987,7 @@ dependencies = [ "frame-support", "frame-system", "impl-trait-for-tuples", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-authorship", "sp-runtime", @@ -5006,7 +5006,7 @@ dependencies = [ "pallet-authorship", "pallet-session", "pallet-timestamp", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-application-crypto", "sp-consensus-babe", @@ -5029,7 +5029,7 @@ dependencies = [ "frame-system", "log", "pallet-balances", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-core", "sp-io", @@ -5067,7 +5067,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-runtime", "sp-std", @@ -5082,7 +5082,7 @@ dependencies = [ "frame-support", "frame-system", "pallet-session", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "serde", "sp-runtime", @@ -5105,7 +5105,7 @@ dependencies = [ "pallet-mmr", "pallet-mmr-primitives", "pallet-session", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "serde", "sp-core", @@ -5124,7 +5124,7 @@ dependencies = [ "frame-system", "log", "pallet-treasury", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-core", "sp-io", @@ -5141,7 +5141,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-core", "sp-io", @@ -5162,7 +5162,7 @@ dependencies = [ "frame-system", "log", "num-traits", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "serde", "sp-core", @@ -5189,7 +5189,7 @@ dependencies = [ "log", "num-traits", "pallet-balances", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "serde", "sp-core", @@ -5207,7 +5207,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-core", "sp-io", @@ -5223,7 +5223,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "serde", "sp-io", @@ -5241,7 +5241,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "rand 0.7.3", "scale-info", "sp-arithmetic", @@ -5263,7 +5263,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-core", "sp-io", @@ -5280,7 +5280,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-arithmetic", "sp-runtime", @@ -5298,7 +5298,7 @@ dependencies = [ "log", "pallet-authorship", "pallet-session", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-application-crypto", "sp-core", @@ -5319,7 +5319,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-io", "sp-runtime", @@ -5336,7 +5336,7 @@ dependencies = [ "frame-system", "log", "pallet-authorship", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-application-crypto", "sp-core", @@ -5354,7 +5354,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-core", "sp-io", @@ -5372,7 +5372,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-core", "sp-io", @@ -5390,7 +5390,7 @@ dependencies = [ "frame-support", "frame-system", "pallet-mmr-primitives", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-core", "sp-io", @@ -5406,7 +5406,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "serde", "sp-api", "sp-core", @@ -5423,7 +5423,7 @@ dependencies = [ "jsonrpc-core-client", "jsonrpc-derive", "pallet-mmr-primitives", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "serde", "sp-api", "sp-blockchain", @@ -5439,7 +5439,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-io", "sp-runtime", @@ -5453,7 +5453,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-io", "sp-runtime", @@ -5469,7 +5469,7 @@ dependencies = [ "frame-system", "log", "pallet-balances", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "serde", "sp-runtime", @@ -5493,7 +5493,7 @@ dependencies = [ "pallet-offences", "pallet-session", "pallet-staking", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-runtime", "sp-staking", @@ -5508,7 +5508,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-core", "sp-io", @@ -5524,7 +5524,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-io", "sp-runtime", @@ -5538,7 +5538,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-io", "sp-runtime", @@ -5554,7 +5554,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-io", "sp-runtime", @@ -5571,7 +5571,7 @@ dependencies = [ "impl-trait-for-tuples", "log", "pallet-timestamp", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-core", "sp-io", @@ -5605,7 +5605,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "rand_chacha 0.2.2", "scale-info", "sp-runtime", @@ -5624,7 +5624,7 @@ dependencies = [ "log", "pallet-authorship", "pallet-session", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "rand_chacha 0.2.2", "scale-info", "serde", @@ -5662,7 +5662,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-io", "sp-runtime", @@ -5678,7 +5678,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-inherents", "sp-io", @@ -5697,7 +5697,7 @@ dependencies = [ "frame-system", "log", "pallet-treasury", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "serde", "sp-core", @@ -5713,7 +5713,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "serde", "smallvec", @@ -5732,7 +5732,7 @@ dependencies = [ "jsonrpc-core-client", "jsonrpc-derive", "pallet-transaction-payment-rpc-runtime-api", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sp-api", "sp-blockchain", "sp-core", @@ -5746,7 +5746,7 @@ version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ "pallet-transaction-payment", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sp-api", "sp-runtime", ] @@ -5761,7 +5761,7 @@ dependencies = [ "frame-system", "impl-trait-for-tuples", "pallet-balances", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "serde", "sp-runtime", @@ -5776,7 +5776,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-core", "sp-io", @@ -5793,7 +5793,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-runtime", "sp-std", @@ -5807,7 +5807,7 @@ dependencies = [ "frame-system", "log", "pallet-balances", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-parachain", "polkadot-runtime-parachains", "scale-info", @@ -5832,7 +5832,7 @@ dependencies = [ "pallet-assets", "pallet-balances", "pallet-xcm", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-primitives", "polkadot-runtime-common", "scale-info", @@ -5865,6 +5865,18 @@ dependencies = [ "snap", ] +[[package]] +name = "parity-scale-codec" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" +dependencies = [ + "arrayvec 0.7.2", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive 2.3.1", +] + [[package]] name = "parity-scale-codec" version = "3.0.0" @@ -5875,10 +5887,22 @@ dependencies = [ "bitvec", "byte-slice-cast", "impl-trait-for-tuples", - "parity-scale-codec-derive", + "parity-scale-codec-derive 3.0.0", "serde", ] +[[package]] +name = "parity-scale-codec-derive" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" +dependencies = [ + "proc-macro-crate 1.1.3", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "parity-scale-codec-derive" version = "3.0.0" @@ -6269,7 +6293,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "lru 0.7.2", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-erasure-coding", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -6299,7 +6323,7 @@ dependencies = [ "futures-timer", "log", "lru 0.7.2", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-erasure-coding", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -6383,7 +6407,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -6404,7 +6428,7 @@ dependencies = [ name = "polkadot-core-primitives" version = "0.9.17" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parity-util-mem", "scale-info", "sp-core", @@ -6424,7 +6448,7 @@ dependencies = [ "futures-timer", "lazy_static", "lru 0.7.2", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-erasure-coding", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -6447,7 +6471,7 @@ dependencies = [ name = "polkadot-erasure-coding" version = "0.9.17" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-node-primitives", "polkadot-primitives", "reed-solomon-novelpoly", @@ -6490,7 +6514,7 @@ dependencies = [ "async-trait", "futures 0.3.21", "futures-timer", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.12.0", "polkadot-node-network-protocol", "polkadot-node-subsystem", @@ -6511,7 +6535,7 @@ name = "polkadot-node-collation-generation" version = "0.9.17" dependencies = [ "futures 0.3.21", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-erasure-coding", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -6538,7 +6562,7 @@ dependencies = [ "kvdb-memorydb", "lru 0.7.2", "merlin", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.12.0", "polkadot-node-jaeger", "polkadot-node-primitives", @@ -6574,7 +6598,7 @@ dependencies = [ "kvdb", "kvdb-memorydb", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.12.0", "polkadot-erasure-coding", "polkadot-node-primitives", @@ -6638,7 +6662,7 @@ dependencies = [ "assert_matches", "async-trait", "futures 0.3.21", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-node-core-pvf", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -6659,7 +6683,7 @@ version = "0.9.17" dependencies = [ "futures 0.3.21", "maplit", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -6681,7 +6705,7 @@ dependencies = [ "futures-timer", "kvdb", "kvdb-memorydb", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.12.0", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -6703,7 +6727,7 @@ dependencies = [ "kvdb", "kvdb-memorydb", "lru 0.7.2", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -6765,7 +6789,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "hex-literal", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "pin-project 1.0.10", "polkadot-core-primitives", "polkadot-node-subsystem-util", @@ -6839,7 +6863,7 @@ dependencies = [ "lazy_static", "log", "mick-jaeger", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.12.0", "polkadot-node-primitives", "polkadot-primitives", @@ -6860,7 +6884,7 @@ dependencies = [ "log", "metered-channel", "nix", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-primitives", "polkadot-test-service", "prometheus-parse", @@ -6883,7 +6907,7 @@ dependencies = [ "async-trait", "fatality", "futures 0.3.21", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-node-jaeger", "polkadot-node-primitives", "polkadot-primitives", @@ -6899,7 +6923,7 @@ version = "0.9.17" dependencies = [ "bounded-vec", "futures 0.3.21", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-erasure-coding", "polkadot-parachain", "polkadot-primitives", @@ -6975,7 +6999,7 @@ dependencies = [ "log", "lru 0.7.2", "metered-channel", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "pin-project 1.0.10", "polkadot-node-jaeger", "polkadot-node-metrics", @@ -7054,7 +7078,7 @@ version = "0.9.17" dependencies = [ "derive_more", "frame-support", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parity-util-mem", "polkadot-core-primitives", "scale-info", @@ -7085,7 +7109,7 @@ dependencies = [ "bitvec", "frame-system", "hex-literal", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parity-util-mem", "polkadot-core-primitives", "polkadot-parachain", @@ -7198,7 +7222,7 @@ dependencies = [ "pallet-utility", "pallet-vesting", "pallet-xcm", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-constants", @@ -7263,7 +7287,7 @@ dependencies = [ "pallet-transaction-payment", "pallet-treasury", "pallet-vesting", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-primitives", "polkadot-primitives-test-helpers", "polkadot-runtime-parachains", @@ -7304,7 +7328,7 @@ name = "polkadot-runtime-metrics" version = "0.9.17" dependencies = [ "bs58", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-primitives", "sp-std", "sp-tracing", @@ -7333,7 +7357,7 @@ dependencies = [ "pallet-staking", "pallet-timestamp", "pallet-vesting", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-primitives", "polkadot-primitives-test-helpers", "polkadot-runtime-metrics", @@ -7477,7 +7501,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "indexmap", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -7501,7 +7525,7 @@ dependencies = [ name = "polkadot-statement-table" version = "0.9.17" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-primitives", "sp-core", ] @@ -7511,7 +7535,7 @@ name = "polkadot-test-client" version = "0.9.17" dependencies = [ "futures 0.3.21", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-node-subsystem", "polkadot-primitives", "polkadot-test-runtime", @@ -7590,7 +7614,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "pallet-vesting", "pallet-xcm", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-parachain", "polkadot-primitives", "polkadot-runtime-common", @@ -8246,7 +8270,7 @@ dependencies = [ "env_logger 0.9.0", "jsonrpsee 0.8.0", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "serde", "serde_json", "sp-core", @@ -8385,7 +8409,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "pallet-utility", "pallet-xcm", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-parachain", "polkadot-primitives", "polkadot-runtime-common", @@ -8607,7 +8631,7 @@ dependencies = [ "ip_network", "libp2p", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "prost", "prost-build", "rand 0.7.3", @@ -8631,7 +8655,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sc-block-builder", "sc-client-api", "sc-proposer-metrics", @@ -8651,7 +8675,7 @@ name = "sc-block-builder" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sc-client-api", "sp-api", "sp-block-builder", @@ -8669,7 +8693,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "impl-trait-for-tuples", "memmap2 0.5.0", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sc-chain-spec-derive", "sc-network", "sc-telemetry", @@ -8703,7 +8727,7 @@ dependencies = [ "libp2p", "log", "names", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "rand 0.7.3", "regex", "rpassword", @@ -8737,7 +8761,7 @@ dependencies = [ "futures 0.3.21", "hash-db", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.12.0", "sc-executor", "sc-transaction-pool-api", @@ -8768,7 +8792,7 @@ dependencies = [ "linked-hash-map", "log", "parity-db", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.12.0", "sc-client-api", "sc-state-db", @@ -8818,7 +8842,7 @@ dependencies = [ "num-bigint", "num-rational 0.2.4", "num-traits", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.12.0", "rand 0.7.3", "retain_mut", @@ -8878,7 +8902,7 @@ version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ "fork-tree", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sc-client-api", "sc-consensus", "sp-blockchain", @@ -8894,7 +8918,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sc-client-api", "sc-consensus", "sc-telemetry", @@ -8928,7 +8952,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "lazy_static", "lru 0.6.6", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.12.0", "sc-executor-common", "sc-executor-wasmi", @@ -8954,7 +8978,7 @@ version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ "environmental", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sc-allocator", "sp-core", "sp-maybe-compressed-blob", @@ -8971,7 +8995,7 @@ version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sc-allocator", "sc-executor-common", "scoped-tls", @@ -8989,7 +9013,7 @@ dependencies = [ "cfg-if 1.0.0", "libc", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parity-wasm 0.42.2", "sc-allocator", "sc-executor-common", @@ -9012,7 +9036,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.12.0", "rand 0.8.5", "sc-block-builder", @@ -9050,7 +9074,7 @@ dependencies = [ "jsonrpc-derive", "jsonrpc-pubsub", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sc-client-api", "sc-finality-grandpa", "sc-rpc", @@ -9116,7 +9140,7 @@ dependencies = [ "linked_hash_set", "log", "lru 0.7.2", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.12.0", "pin-project 1.0.10", "prost", @@ -9174,7 +9198,7 @@ dependencies = [ "hyper-rustls", "num_cpus", "once_cell", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.12.0", "rand 0.7.3", "sc-client-api", @@ -9220,7 +9244,7 @@ dependencies = [ "jsonrpc-core", "jsonrpc-pubsub", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.12.0", "sc-block-builder", "sc-chain-spec", @@ -9252,7 +9276,7 @@ dependencies = [ "jsonrpc-derive", "jsonrpc-pubsub", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.12.0", "sc-chain-spec", "sc-transaction-pool-api", @@ -9297,7 +9321,7 @@ dependencies = [ "jsonrpc-core", "jsonrpc-pubsub", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parity-util-mem", "parking_lot 0.12.0", "pin-project 1.0.10", @@ -9353,7 +9377,7 @@ version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parity-util-mem", "parity-util-mem-derive", "parking_lot 0.12.0", @@ -9369,7 +9393,7 @@ dependencies = [ "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sc-chain-spec", "sc-client-api", "sc-consensus-babe", @@ -9451,7 +9475,7 @@ dependencies = [ "futures-timer", "linked-hash-map", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parity-util-mem", "parking_lot 0.12.0", "retain_mut", @@ -9503,7 +9527,7 @@ dependencies = [ "bitvec", "cfg-if 1.0.0", "derive_more", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info-derive", "serde", ] @@ -9903,7 +9927,7 @@ name = "slot-range-helper" version = "0.9.17" dependencies = [ "enumn", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "paste", "sp-runtime", "sp-std", @@ -9992,7 +10016,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "hash-db", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sp-api-proc-macro", "sp-core", "sp-runtime", @@ -10019,7 +10043,7 @@ name = "sp-application-crypto" version = "5.0.0" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "serde", "sp-core", @@ -10034,7 +10058,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "integer-sqrt", "num-traits", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "serde", "sp-debug-derive", @@ -10047,7 +10071,7 @@ name = "sp-authority-discovery" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-api", "sp-application-crypto", @@ -10061,7 +10085,7 @@ version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ "async-trait", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sp-inherents", "sp-runtime", "sp-std", @@ -10072,7 +10096,7 @@ name = "sp-block-builder" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sp-api", "sp-inherents", "sp-runtime", @@ -10087,7 +10111,7 @@ dependencies = [ "futures 0.3.21", "log", "lru 0.7.2", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.12.0", "sp-api", "sp-consensus", @@ -10106,7 +10130,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sp-core", "sp-inherents", "sp-runtime", @@ -10123,7 +10147,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "async-trait", "merlin", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "serde", "sp-api", @@ -10144,7 +10168,7 @@ name = "sp-consensus-slots" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "serde", "sp-arithmetic", @@ -10158,7 +10182,7 @@ name = "sp-consensus-vrf" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.0.0", "schnorrkel", "sp-core", "sp-runtime", @@ -10186,7 +10210,7 @@ dependencies = [ "log", "merlin", "num-traits", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parity-util-mem", "parking_lot 0.12.0", "primitive-types", @@ -10261,7 +10285,7 @@ version = "0.11.0" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ "environmental", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sp-std", "sp-storage", ] @@ -10273,7 +10297,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "finality-grandpa", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "serde", "sp-api", @@ -10291,7 +10315,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "async-trait", "impl-trait-for-tuples", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sp-core", "sp-runtime", "sp-std", @@ -10307,7 +10331,7 @@ dependencies = [ "hash-db", "libsecp256k1", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.12.0", "secp256k1", "sp-core", @@ -10342,7 +10366,7 @@ dependencies = [ "async-trait", "futures 0.3.21", "merlin", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.12.0", "schnorrkel", "serde", @@ -10365,7 +10389,7 @@ name = "sp-npos-elections" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "serde", "sp-arithmetic", @@ -10425,7 +10449,7 @@ dependencies = [ "hash256-std-hasher", "impl-trait-for-tuples", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parity-util-mem", "paste", "rand 0.7.3", @@ -10444,7 +10468,7 @@ version = "5.0.0" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ "impl-trait-for-tuples", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "primitive-types", "sp-externalities", "sp-runtime-interface-proc-macro", @@ -10481,7 +10505,7 @@ name = "sp-session" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-api", "sp-core", @@ -10495,7 +10519,7 @@ name = "sp-staking" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-runtime", "sp-std", @@ -10509,7 +10533,7 @@ dependencies = [ "hash-db", "log", "num-traits", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parking_lot 0.12.0", "rand 0.7.3", "smallvec", @@ -10535,7 +10559,7 @@ version = "5.0.0" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ "impl-serde", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "ref-cast", "serde", "sp-debug-derive", @@ -10563,7 +10587,7 @@ dependencies = [ "async-trait", "futures-timer", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sp-api", "sp-inherents", "sp-runtime", @@ -10576,7 +10600,7 @@ name = "sp-tracing" version = "4.0.0" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sp-std", "tracing", "tracing-core", @@ -10599,7 +10623,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "async-trait", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-core", "sp-inherents", @@ -10615,7 +10639,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "hash-db", "memory-db", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "sp-core", "sp-std", @@ -10629,7 +10653,7 @@ version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ "impl-serde", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "parity-wasm 0.42.2", "scale-info", "serde", @@ -10645,7 +10669,7 @@ name = "sp-version-proc-macro" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.0.0", "proc-macro2", "quote", "syn", @@ -10658,7 +10682,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "impl-trait-for-tuples", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sp-std", "wasmi", "wasmtime", @@ -10715,7 +10739,7 @@ dependencies = [ "pallet-election-provider-multi-phase", "pallet-staking", "pallet-transaction-payment", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "paste", "polkadot-core-primitives", "polkadot-runtime", @@ -10870,7 +10894,7 @@ dependencies = [ "jsonrpc-core-client", "jsonrpc-derive", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sc-client-api", "sc-rpc-api", "sc-transaction-pool-api", @@ -10902,7 +10926,7 @@ dependencies = [ "async-trait", "futures 0.3.21", "hex", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sc-client-api", "sc-client-db", "sc-consensus", @@ -11055,7 +11079,7 @@ name = "test-parachain-adder" version = "0.9.17" dependencies = [ "dlmalloc", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-parachain", "sp-io", "sp-std", @@ -11071,7 +11095,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-cli", "polkadot-node-core-pvf", "polkadot-node-primitives", @@ -11102,7 +11126,7 @@ version = "0.9.17" dependencies = [ "dlmalloc", "log", - "parity-scale-codec", + "parity-scale-codec 2.3.1", "polkadot-parachain", "sp-io", "sp-std", @@ -11118,7 +11142,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "log", - "parity-scale-codec", + "parity-scale-codec 2.3.1", "polkadot-cli", "polkadot-node-core-pvf", "polkadot-node-primitives", @@ -11140,7 +11164,7 @@ dependencies = [ name = "test-parachains" version = "0.9.17" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sp-core", "test-parachain-adder", "test-parachain-halt", @@ -11608,7 +11632,7 @@ dependencies = [ "clap", "jsonrpsee 0.4.1", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "remote-externalities", "sc-chain-spec", "sc-cli", @@ -12295,7 +12319,7 @@ dependencies = [ "pallet-vesting", "pallet-xcm", "pallet-xcm-benchmarks", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-parachain", "polkadot-primitives", "polkadot-runtime-common", @@ -12500,7 +12524,7 @@ dependencies = [ "derivative", "impl-trait-for-tuples", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "scale-info", "xcm-procedural", ] @@ -12515,7 +12539,7 @@ dependencies = [ "pallet-balances", "pallet-transaction-payment", "pallet-xcm", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-parachain", "polkadot-runtime-parachains", "scale-info", @@ -12536,7 +12560,7 @@ dependencies = [ "frame-support", "impl-trait-for-tuples", "log", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "sp-arithmetic", "sp-core", "sp-io", @@ -12580,7 +12604,7 @@ name = "xcm-simulator" version = "0.9.17" dependencies = [ "frame-support", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "paste", "polkadot-core-primitives", "polkadot-parachain", @@ -12599,7 +12623,7 @@ dependencies = [ "frame-system", "pallet-balances", "pallet-xcm", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-core-primitives", "polkadot-parachain", "polkadot-runtime-parachains", @@ -12623,7 +12647,7 @@ dependencies = [ "honggfuzz", "pallet-balances", "pallet-xcm", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "polkadot-core-primitives", "polkadot-parachain", "polkadot-runtime-parachains", @@ -12679,7 +12703,7 @@ version = "0.9.17" dependencies = [ "futures-util", "lazy_static", - "parity-scale-codec", + "parity-scale-codec 3.0.0", "reqwest", "serde", "serde_json", diff --git a/node/malus/src/malus.rs b/node/malus/src/malus.rs index ab5c839cfb53..ccd0a4c687ad 100644 --- a/node/malus/src/malus.rs +++ b/node/malus/src/malus.rs @@ -16,7 +16,7 @@ //! A malus or nemesis node launch code. -use clap::{AppSettings, ArgEnum, Parser}; +use clap::{ArgEnum, Parser}; use color_eyre::eyre; use polkadot_cli::{Cli, RunCmd}; @@ -54,10 +54,9 @@ enum NemesisVariant { version )] #[clap(rename_all = "kebab-case")] -pub(crate) enum FakeCandidateValidation { - None, +pub enum FakeCandidateValidation { Invalid, - // TODO: impl valid. + // TODO: impl Valid. } #[derive(Debug, Parser)] @@ -66,8 +65,11 @@ struct MalusCli { #[clap(subcommand)] pub variant: NemesisVariant, - #[clap(long, arg_enum, ignore_case = true, default_value = "None")] - pub fake_validation: FakeCandidateValidation, + #[clap(long, arg_enum, ignore_case = true)] + pub fake_backing_validation: Option, + + #[clap(long, arg_enum, ignore_case = true)] + pub fake_approval_validation: Option, } fn run_cmd(run: RunCmd) -> Cli { @@ -84,7 +86,10 @@ impl MalusCli { polkadot_cli::run_node(run_cmd(cmd), SuggestGarbageCandidate)?, NemesisVariant::DisputeAncestor(cmd) => polkadot_cli::run_node( run_cmd(cmd), - DisputeValidCandidates::new(self.fake_validation), + DisputeValidCandidates::new( + self.fake_backing_validation, + self.fake_approval_validation, + ), )?, NemesisVariant::PvfPrepareWorker(cmd) => { #[cfg(target_os = "android")] diff --git a/node/malus/src/variants/common.rs b/node/malus/src/variants/common.rs new file mode 100644 index 000000000000..eab1c950daaf --- /dev/null +++ b/node/malus/src/variants/common.rs @@ -0,0 +1,133 @@ +// Copyright 2021 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 . + +//! Implements common features for nemesis. Currently, only FakeValidationResult +//! interceptor is implemented. + +#![allow(missing_docs)] + +// Filter wrapping related types. +use crate::{interceptor::*, shared::MALUS, FakeCandidateValidation}; +use polkadot_node_primitives::{InvalidCandidate, ValidationResult}; +use polkadot_node_subsystem::messages::CandidateValidationMessage; + +#[derive(Clone, Debug)] +/// An interceptor which fakes validation result with a preconfigured result. +/// Replaces `CandidateValidationSubsystem`. +pub struct ReplaceValidationResult { + fake_backing_validation: Option, + fake_approval_validation: Option, +} + +impl ReplaceValidationResult { + pub fn new( + fake_backing_validation: Option, + fake_approval_validation: Option, + ) -> Self { + Self { fake_backing_validation, fake_approval_validation } + } +} + +impl MessageInterceptor for ReplaceValidationResult +where + Sender: overseer::SubsystemSender + Clone + Send + 'static, +{ + type Message = CandidateValidationMessage; + + // Capture all candidate validation requests and depending on configuration fail them. + // MaybeTODO: add option to configure the failure reason. + fn intercept_incoming( + &self, + _sender: &mut Sender, + msg: FromOverseer, + ) -> Option> { + if self.fake_backing_validation.is_none() && self.fake_approval_validation.is_none() { + return Some(msg) + } + + match msg { + FromOverseer::Communication { + msg: + CandidateValidationMessage::ValidateFromExhaustive( + validation_data, + validation_code, + descriptor, + pov, + timeout, + sender, + ), + } => { + if let Some(FakeCandidateValidation::Invalid) = self.fake_approval_validation { + let validation_result = + ValidationResult::Invalid(InvalidCandidate::InvalidOutputs); + + tracing::info!( + target = MALUS, + para_id = ?descriptor.para_id, + candidate_hash = ?descriptor.para_head, + "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 + } else { + Some(FromOverseer::Communication { + msg: CandidateValidationMessage::ValidateFromExhaustive( + validation_data, + validation_code, + descriptor, + pov, + timeout, + sender, + ), + }) + } + }, + FromOverseer::Communication { + msg: + CandidateValidationMessage::ValidateFromChainState(descriptor, pov, timeout, sender), + } => { + if let Some(FakeCandidateValidation::Invalid) = self.fake_backing_validation { + let validation_result = + ValidationResult::Invalid(InvalidCandidate::InvalidOutputs); + tracing::info!( + target = MALUS, + para_id = ?descriptor.para_id, + candidate_hash = ?descriptor.para_head, + "ValidateFromChainState 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 + } else { + Some(FromOverseer::Communication { + msg: CandidateValidationMessage::ValidateFromChainState( + descriptor, pov, timeout, sender, + ), + }) + } + }, + msg => Some(msg), + } + } + + fn intercept_outgoing(&self, msg: AllMessages) -> Option { + Some(msg) + } +} diff --git a/node/malus/src/variants/dispute_valid_candidates.rs b/node/malus/src/variants/dispute_valid_candidates.rs index b5e62c182dd4..8c3c72672c4e 100644 --- a/node/malus/src/variants/dispute_valid_candidates.rs +++ b/node/malus/src/variants/dispute_valid_candidates.rs @@ -31,8 +31,9 @@ use polkadot_cli::{ }; // Filter wrapping related types. -use crate::{interceptor::*, shared::MALUS, FakeCandidateValidation}; -use polkadot_node_primitives::{InvalidCandidate, ValidationResult}; +use crate::{ + interceptor::*, shared::MALUS, variants::ReplaceValidationResult, FakeCandidateValidation, +}; // Import extra types relevant to the particular // subsystem. @@ -40,8 +41,7 @@ use polkadot_node_core_backing::CandidateBackingSubsystem; use polkadot_node_core_candidate_validation::CandidateValidationSubsystem; use polkadot_node_subsystem::messages::{ - ApprovalDistributionMessage, CandidateBackingMessage, CandidateValidationMessage, - DisputeCoordinatorMessage, + ApprovalDistributionMessage, CandidateBackingMessage, DisputeCoordinatorMessage, }; use sp_keystore::SyncCryptoStorePtr; @@ -51,9 +51,6 @@ use std::sync::Arc; #[derive(Clone, Debug)] struct ReplaceApprovalsWithDisputes; -#[derive(Clone, Debug)] -struct ReplaceValidationResult(FakeCandidateValidation); - impl MessageInterceptor for ReplaceApprovalsWithDisputes where Sender: overseer::SubsystemSender + Clone + Send + 'static, @@ -102,83 +99,25 @@ where } } } - -impl MessageInterceptor for ReplaceValidationResult -where - Sender: overseer::SubsystemSender + Clone + Send + 'static, -{ - type Message = CandidateValidationMessage; - - // Capture all candidate validation requests and fail them. - // MaybeTODO: add option to configure the failure reason. - fn intercept_incoming( - &self, - _sender: &mut Sender, - msg: FromOverseer, - ) -> Option> { - if self.0 == FakeCandidateValidation::None { - return Some(msg) - } - - match msg { - FromOverseer::Communication { - msg: - CandidateValidationMessage::ValidateFromExhaustive(_, _, descriptor, _, _, sender), - } => { - let validation_result = ValidationResult::Invalid(InvalidCandidate::InvalidOutputs); - - tracing::info!( - target = MALUS, - para_id = ?descriptor.para_id, - candidate_hash = ?descriptor.para_head, - "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 - }, - FromOverseer::Communication { - msg: CandidateValidationMessage::ValidateFromChainState(descriptor, _, _, sender), - } => { - let validation_result = ValidationResult::Invalid(InvalidCandidate::InvalidOutputs); - - tracing::info!( - target = MALUS, - para_id = ?descriptor.para_id, - candidate_hash = ?descriptor.para_head, - "ValidateFromChainState 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 - }, - msg => Some(msg), - } - } - - fn intercept_outgoing(&self, msg: AllMessages) -> Option { - Some(msg) - } -} - -/// Generates an overseer that disputes instead of approving valid candidates. pub(crate) struct DisputeValidCandidates { - fake_candidate_validation: FakeCandidateValidation, + /// Backing configuration. + fake_backing_validation: Option, + /// Approval voting configuraiton (applies to disputes as well). + fake_approval_validation: Option, } impl Default for DisputeValidCandidates { fn default() -> Self { - Self { fake_candidate_validation: FakeCandidateValidation::None } + Self { fake_backing_validation: None, fake_approval_validation: None } } } impl DisputeValidCandidates { - pub fn new(fake_candidate_validation: FakeCandidateValidation) -> Self { - Self { fake_candidate_validation } + pub fn new( + fake_backing_validation: Option, + fake_approval_validation: Option, + ) -> Self { + Self { fake_backing_validation, fake_approval_validation } } } @@ -196,7 +135,10 @@ impl OverseerGen for DisputeValidCandidates { let spawner = args.spawner.clone(); let crypto_store_ptr = args.keystore.clone() as SyncCryptoStorePtr; let backing_filter = ReplaceApprovalsWithDisputes; - let validation_filter = ReplaceValidationResult(self.fake_candidate_validation.clone()); + let validation_filter = ReplaceValidationResult::new( + self.fake_backing_validation.clone(), + self.fake_approval_validation.clone(), + ); let candidate_validation_config = args.candidate_validation_config.clone(); prepared_overseer_builder(args)? diff --git a/node/malus/src/variants/mod.rs b/node/malus/src/variants/mod.rs index aab3203f5bf3..dada02f2787b 100644 --- a/node/malus/src/variants/mod.rs +++ b/node/malus/src/variants/mod.rs @@ -17,6 +17,7 @@ //! Collection of behavior variants. mod back_garbage_candidate; +mod common; mod dispute_valid_candidates; mod suggest_garbage_candidate; @@ -24,3 +25,4 @@ pub(crate) use self::{ back_garbage_candidate::BackGarbageCandidate, dispute_valid_candidates::DisputeValidCandidates, suggest_garbage_candidate::SuggestGarbageCandidate, }; +pub(crate) use common::ReplaceValidationResult; From a3172b0d110aa4b7ea262afb29816a28e3b85662 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Tue, 1 Mar 2022 12:14:58 +0000 Subject: [PATCH 03/47] cargo lock Signed-off-by: Andrei Sandu --- Cargo.lock | 386 +++++++++++++++++++++++++---------------------------- 1 file changed, 181 insertions(+), 205 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6a7e44d23454..809d0ce994c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -456,7 +456,7 @@ dependencies = [ "fnv", "futures 0.3.21", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.12.0", "sc-chain-spec", "sc-client-api", @@ -489,7 +489,7 @@ dependencies = [ "jsonrpc-derive", "jsonrpc-pubsub", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.12.0", "sc-rpc", "sc-utils", @@ -509,7 +509,7 @@ name = "beefy-primitives" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-api", "sp-application-crypto", @@ -728,7 +728,7 @@ dependencies = [ "bp-test-utils", "finality-grandpa", "frame-support", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "serde", "sp-core", @@ -743,7 +743,7 @@ version = "0.1.0" dependencies = [ "bp-runtime", "frame-support", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-std", ] @@ -757,7 +757,7 @@ dependencies = [ "frame-support", "frame-system", "impl-trait-for-tuples", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "serde", "sp-std", @@ -772,7 +772,7 @@ dependencies = [ "frame-support", "frame-system", "hex", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-api", "sp-core", @@ -789,7 +789,7 @@ dependencies = [ "bp-polkadot-core", "bp-runtime", "frame-support", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "smallvec", "sp-api", "sp-runtime", @@ -805,7 +805,7 @@ dependencies = [ "hash-db", "hex-literal", "num-traits", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -822,7 +822,7 @@ dependencies = [ "bp-header-chain", "ed25519-dalek", "finality-grandpa", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sp-application-crypto", "sp-finality-grandpa", "sp-runtime", @@ -837,7 +837,7 @@ dependencies = [ "bp-polkadot-core", "bp-rococo", "bp-runtime", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sp-api", "sp-runtime", "sp-std", @@ -857,7 +857,7 @@ dependencies = [ "pallet-bridge-grandpa", "pallet-bridge-messages", "pallet-transaction-payment", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-core", "sp-runtime", @@ -1977,7 +1977,7 @@ dependencies = [ "futures-timer", "log", "num-traits", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.11.2", "scale-info", ] @@ -2051,7 +2051,7 @@ name = "fork-tree" version = "3.0.0" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec 3.0.0", + "parity-scale-codec", ] [[package]] @@ -2073,7 +2073,7 @@ dependencies = [ "frame-system", "linregress", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "paste", "scale-info", "serde", @@ -2104,7 +2104,7 @@ dependencies = [ "linked-hash-map", "log", "memory-db", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "rand 0.8.5", "sc-cli", "sc-client-api", @@ -2134,7 +2134,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "frame-support", "frame-system", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-arithmetic", "sp-npos-elections", @@ -2148,7 +2148,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "frame-support", "frame-system", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -2164,7 +2164,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df6bb8542ef006ef0de09a5c4420787d79823c0ed7924225822362fd2bf2ff2d" dependencies = [ "cfg-if 1.0.0", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "serde", ] @@ -2180,7 +2180,7 @@ dependencies = [ "impl-trait-for-tuples", "log", "once_cell", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "paste", "scale-info", "serde", @@ -2240,7 +2240,7 @@ dependencies = [ "frame-support", "frame-support-test-pallet", "frame-system", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "pretty_assertions", "rustversion", "scale-info", @@ -2262,7 +2262,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "frame-support", "frame-system", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", ] @@ -2273,7 +2273,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "frame-support", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "serde", "sp-core", @@ -2291,7 +2291,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-core", "sp-runtime", @@ -2303,7 +2303,7 @@ name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sp-api", ] @@ -2967,7 +2967,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" dependencies = [ - "parity-scale-codec 3.0.0", + "parity-scale-codec", ] [[package]] @@ -3485,7 +3485,7 @@ dependencies = [ "pallet-utility", "pallet-vesting", "pallet-xcm", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-parachains", @@ -4957,7 +4957,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-runtime", "sp-std", @@ -4971,7 +4971,7 @@ dependencies = [ "frame-support", "frame-system", "pallet-session", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-application-crypto", "sp-authority-discovery", @@ -4987,7 +4987,7 @@ dependencies = [ "frame-support", "frame-system", "impl-trait-for-tuples", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-authorship", "sp-runtime", @@ -5006,7 +5006,7 @@ dependencies = [ "pallet-authorship", "pallet-session", "pallet-timestamp", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-application-crypto", "sp-consensus-babe", @@ -5029,7 +5029,7 @@ dependencies = [ "frame-system", "log", "pallet-balances", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -5067,7 +5067,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-runtime", "sp-std", @@ -5082,7 +5082,7 @@ dependencies = [ "frame-support", "frame-system", "pallet-session", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "serde", "sp-runtime", @@ -5105,7 +5105,7 @@ dependencies = [ "pallet-mmr", "pallet-mmr-primitives", "pallet-session", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "serde", "sp-core", @@ -5124,7 +5124,7 @@ dependencies = [ "frame-system", "log", "pallet-treasury", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -5141,7 +5141,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -5162,7 +5162,7 @@ dependencies = [ "frame-system", "log", "num-traits", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "serde", "sp-core", @@ -5189,7 +5189,7 @@ dependencies = [ "log", "num-traits", "pallet-balances", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "serde", "sp-core", @@ -5207,7 +5207,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -5223,7 +5223,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "serde", "sp-io", @@ -5241,7 +5241,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "rand 0.7.3", "scale-info", "sp-arithmetic", @@ -5263,7 +5263,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -5280,7 +5280,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-arithmetic", "sp-runtime", @@ -5298,7 +5298,7 @@ dependencies = [ "log", "pallet-authorship", "pallet-session", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-application-crypto", "sp-core", @@ -5319,7 +5319,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-io", "sp-runtime", @@ -5336,7 +5336,7 @@ dependencies = [ "frame-system", "log", "pallet-authorship", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-application-crypto", "sp-core", @@ -5354,7 +5354,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -5372,7 +5372,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -5390,7 +5390,7 @@ dependencies = [ "frame-support", "frame-system", "pallet-mmr-primitives", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -5406,7 +5406,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "serde", "sp-api", "sp-core", @@ -5423,7 +5423,7 @@ dependencies = [ "jsonrpc-core-client", "jsonrpc-derive", "pallet-mmr-primitives", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "serde", "sp-api", "sp-blockchain", @@ -5439,7 +5439,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-io", "sp-runtime", @@ -5453,7 +5453,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "frame-support", "frame-system", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-io", "sp-runtime", @@ -5469,7 +5469,7 @@ dependencies = [ "frame-system", "log", "pallet-balances", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "serde", "sp-runtime", @@ -5493,7 +5493,7 @@ dependencies = [ "pallet-offences", "pallet-session", "pallet-staking", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-runtime", "sp-staking", @@ -5508,7 +5508,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -5524,7 +5524,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-io", "sp-runtime", @@ -5538,7 +5538,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "frame-support", "frame-system", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-io", "sp-runtime", @@ -5554,7 +5554,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-io", "sp-runtime", @@ -5571,7 +5571,7 @@ dependencies = [ "impl-trait-for-tuples", "log", "pallet-timestamp", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -5605,7 +5605,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "frame-support", "frame-system", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "rand_chacha 0.2.2", "scale-info", "sp-runtime", @@ -5624,7 +5624,7 @@ dependencies = [ "log", "pallet-authorship", "pallet-session", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "rand_chacha 0.2.2", "scale-info", "serde", @@ -5662,7 +5662,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "frame-support", "frame-system", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-io", "sp-runtime", @@ -5678,7 +5678,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-inherents", "sp-io", @@ -5697,7 +5697,7 @@ dependencies = [ "frame-system", "log", "pallet-treasury", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "serde", "sp-core", @@ -5713,7 +5713,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "frame-support", "frame-system", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "serde", "smallvec", @@ -5732,7 +5732,7 @@ dependencies = [ "jsonrpc-core-client", "jsonrpc-derive", "pallet-transaction-payment-rpc-runtime-api", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sp-api", "sp-blockchain", "sp-core", @@ -5746,7 +5746,7 @@ version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ "pallet-transaction-payment", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sp-api", "sp-runtime", ] @@ -5761,7 +5761,7 @@ dependencies = [ "frame-system", "impl-trait-for-tuples", "pallet-balances", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "serde", "sp-runtime", @@ -5776,7 +5776,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -5793,7 +5793,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-runtime", "sp-std", @@ -5807,7 +5807,7 @@ dependencies = [ "frame-system", "log", "pallet-balances", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-parachain", "polkadot-runtime-parachains", "scale-info", @@ -5832,7 +5832,7 @@ dependencies = [ "pallet-assets", "pallet-balances", "pallet-xcm", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-primitives", "polkadot-runtime-common", "scale-info", @@ -5865,18 +5865,6 @@ dependencies = [ "snap", ] -[[package]] -name = "parity-scale-codec" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" -dependencies = [ - "arrayvec 0.7.2", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive 2.3.1", -] - [[package]] name = "parity-scale-codec" version = "3.0.0" @@ -5887,22 +5875,10 @@ dependencies = [ "bitvec", "byte-slice-cast", "impl-trait-for-tuples", - "parity-scale-codec-derive 3.0.0", + "parity-scale-codec-derive", "serde", ] -[[package]] -name = "parity-scale-codec-derive" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" -dependencies = [ - "proc-macro-crate 1.1.3", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "parity-scale-codec-derive" version = "3.0.0" @@ -6293,7 +6269,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "lru 0.7.2", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -6323,7 +6299,7 @@ dependencies = [ "futures-timer", "log", "lru 0.7.2", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -6407,7 +6383,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -6428,7 +6404,7 @@ dependencies = [ name = "polkadot-core-primitives" version = "0.9.17" dependencies = [ - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parity-util-mem", "scale-info", "sp-core", @@ -6448,7 +6424,7 @@ dependencies = [ "futures-timer", "lazy_static", "lru 0.7.2", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -6471,7 +6447,7 @@ dependencies = [ name = "polkadot-erasure-coding" version = "0.9.17" dependencies = [ - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-node-primitives", "polkadot-primitives", "reed-solomon-novelpoly", @@ -6514,7 +6490,7 @@ dependencies = [ "async-trait", "futures 0.3.21", "futures-timer", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.12.0", "polkadot-node-network-protocol", "polkadot-node-subsystem", @@ -6535,7 +6511,7 @@ name = "polkadot-node-collation-generation" version = "0.9.17" dependencies = [ "futures 0.3.21", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -6562,7 +6538,7 @@ dependencies = [ "kvdb-memorydb", "lru 0.7.2", "merlin", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.12.0", "polkadot-node-jaeger", "polkadot-node-primitives", @@ -6598,7 +6574,7 @@ dependencies = [ "kvdb", "kvdb-memorydb", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.12.0", "polkadot-erasure-coding", "polkadot-node-primitives", @@ -6662,7 +6638,7 @@ dependencies = [ "assert_matches", "async-trait", "futures 0.3.21", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-node-core-pvf", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -6683,7 +6659,7 @@ version = "0.9.17" dependencies = [ "futures 0.3.21", "maplit", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -6705,7 +6681,7 @@ dependencies = [ "futures-timer", "kvdb", "kvdb-memorydb", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.12.0", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -6727,7 +6703,7 @@ dependencies = [ "kvdb", "kvdb-memorydb", "lru 0.7.2", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -6789,7 +6765,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "hex-literal", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "pin-project 1.0.10", "polkadot-core-primitives", "polkadot-node-subsystem-util", @@ -6863,7 +6839,7 @@ dependencies = [ "lazy_static", "log", "mick-jaeger", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.12.0", "polkadot-node-primitives", "polkadot-primitives", @@ -6884,7 +6860,7 @@ dependencies = [ "log", "metered-channel", "nix", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-primitives", "polkadot-test-service", "prometheus-parse", @@ -6907,7 +6883,7 @@ dependencies = [ "async-trait", "fatality", "futures 0.3.21", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-node-jaeger", "polkadot-node-primitives", "polkadot-primitives", @@ -6923,7 +6899,7 @@ version = "0.9.17" dependencies = [ "bounded-vec", "futures 0.3.21", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-erasure-coding", "polkadot-parachain", "polkadot-primitives", @@ -6999,7 +6975,7 @@ dependencies = [ "log", "lru 0.7.2", "metered-channel", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "pin-project 1.0.10", "polkadot-node-jaeger", "polkadot-node-metrics", @@ -7078,7 +7054,7 @@ version = "0.9.17" dependencies = [ "derive_more", "frame-support", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parity-util-mem", "polkadot-core-primitives", "scale-info", @@ -7109,7 +7085,7 @@ dependencies = [ "bitvec", "frame-system", "hex-literal", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parity-util-mem", "polkadot-core-primitives", "polkadot-parachain", @@ -7222,7 +7198,7 @@ dependencies = [ "pallet-utility", "pallet-vesting", "pallet-xcm", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-constants", @@ -7287,7 +7263,7 @@ dependencies = [ "pallet-transaction-payment", "pallet-treasury", "pallet-vesting", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-primitives", "polkadot-primitives-test-helpers", "polkadot-runtime-parachains", @@ -7328,7 +7304,7 @@ name = "polkadot-runtime-metrics" version = "0.9.17" dependencies = [ "bs58", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-primitives", "sp-std", "sp-tracing", @@ -7357,7 +7333,7 @@ dependencies = [ "pallet-staking", "pallet-timestamp", "pallet-vesting", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-primitives", "polkadot-primitives-test-helpers", "polkadot-runtime-metrics", @@ -7501,7 +7477,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "indexmap", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -7525,7 +7501,7 @@ dependencies = [ name = "polkadot-statement-table" version = "0.9.17" dependencies = [ - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-primitives", "sp-core", ] @@ -7535,7 +7511,7 @@ name = "polkadot-test-client" version = "0.9.17" dependencies = [ "futures 0.3.21", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-node-subsystem", "polkadot-primitives", "polkadot-test-runtime", @@ -7614,7 +7590,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "pallet-vesting", "pallet-xcm", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-parachain", "polkadot-primitives", "polkadot-runtime-common", @@ -8270,7 +8246,7 @@ dependencies = [ "env_logger 0.9.0", "jsonrpsee 0.8.0", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "serde", "serde_json", "sp-core", @@ -8409,7 +8385,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "pallet-utility", "pallet-xcm", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-parachain", "polkadot-primitives", "polkadot-runtime-common", @@ -8631,7 +8607,7 @@ dependencies = [ "ip_network", "libp2p", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "prost", "prost-build", "rand 0.7.3", @@ -8655,7 +8631,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sc-block-builder", "sc-client-api", "sc-proposer-metrics", @@ -8675,7 +8651,7 @@ name = "sc-block-builder" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sc-client-api", "sp-api", "sp-block-builder", @@ -8693,7 +8669,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "impl-trait-for-tuples", "memmap2 0.5.0", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sc-chain-spec-derive", "sc-network", "sc-telemetry", @@ -8727,7 +8703,7 @@ dependencies = [ "libp2p", "log", "names", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "rand 0.7.3", "regex", "rpassword", @@ -8761,7 +8737,7 @@ dependencies = [ "futures 0.3.21", "hash-db", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.12.0", "sc-executor", "sc-transaction-pool-api", @@ -8792,7 +8768,7 @@ dependencies = [ "linked-hash-map", "log", "parity-db", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.12.0", "sc-client-api", "sc-state-db", @@ -8842,7 +8818,7 @@ dependencies = [ "num-bigint", "num-rational 0.2.4", "num-traits", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.12.0", "rand 0.7.3", "retain_mut", @@ -8902,7 +8878,7 @@ version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ "fork-tree", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sc-client-api", "sc-consensus", "sp-blockchain", @@ -8918,7 +8894,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sc-client-api", "sc-consensus", "sc-telemetry", @@ -8952,7 +8928,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "lazy_static", "lru 0.6.6", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.12.0", "sc-executor-common", "sc-executor-wasmi", @@ -8978,7 +8954,7 @@ version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ "environmental", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sc-allocator", "sp-core", "sp-maybe-compressed-blob", @@ -8995,7 +8971,7 @@ version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sc-allocator", "sc-executor-common", "scoped-tls", @@ -9013,7 +8989,7 @@ dependencies = [ "cfg-if 1.0.0", "libc", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parity-wasm 0.42.2", "sc-allocator", "sc-executor-common", @@ -9036,7 +9012,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.12.0", "rand 0.8.5", "sc-block-builder", @@ -9074,7 +9050,7 @@ dependencies = [ "jsonrpc-derive", "jsonrpc-pubsub", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sc-client-api", "sc-finality-grandpa", "sc-rpc", @@ -9140,7 +9116,7 @@ dependencies = [ "linked_hash_set", "log", "lru 0.7.2", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.12.0", "pin-project 1.0.10", "prost", @@ -9198,7 +9174,7 @@ dependencies = [ "hyper-rustls", "num_cpus", "once_cell", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.12.0", "rand 0.7.3", "sc-client-api", @@ -9244,7 +9220,7 @@ dependencies = [ "jsonrpc-core", "jsonrpc-pubsub", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.12.0", "sc-block-builder", "sc-chain-spec", @@ -9276,7 +9252,7 @@ dependencies = [ "jsonrpc-derive", "jsonrpc-pubsub", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.12.0", "sc-chain-spec", "sc-transaction-pool-api", @@ -9321,7 +9297,7 @@ dependencies = [ "jsonrpc-core", "jsonrpc-pubsub", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parity-util-mem", "parking_lot 0.12.0", "pin-project 1.0.10", @@ -9377,7 +9353,7 @@ version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parity-util-mem", "parity-util-mem-derive", "parking_lot 0.12.0", @@ -9393,7 +9369,7 @@ dependencies = [ "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sc-chain-spec", "sc-client-api", "sc-consensus-babe", @@ -9475,7 +9451,7 @@ dependencies = [ "futures-timer", "linked-hash-map", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parity-util-mem", "parking_lot 0.12.0", "retain_mut", @@ -9527,7 +9503,7 @@ dependencies = [ "bitvec", "cfg-if 1.0.0", "derive_more", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info-derive", "serde", ] @@ -9927,7 +9903,7 @@ name = "slot-range-helper" version = "0.9.17" dependencies = [ "enumn", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "paste", "sp-runtime", "sp-std", @@ -10016,7 +9992,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "hash-db", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sp-api-proc-macro", "sp-core", "sp-runtime", @@ -10043,7 +10019,7 @@ name = "sp-application-crypto" version = "5.0.0" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "serde", "sp-core", @@ -10058,7 +10034,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "integer-sqrt", "num-traits", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "serde", "sp-debug-derive", @@ -10071,7 +10047,7 @@ name = "sp-authority-discovery" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-api", "sp-application-crypto", @@ -10085,7 +10061,7 @@ version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ "async-trait", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sp-inherents", "sp-runtime", "sp-std", @@ -10096,7 +10072,7 @@ name = "sp-block-builder" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sp-api", "sp-inherents", "sp-runtime", @@ -10111,7 +10087,7 @@ dependencies = [ "futures 0.3.21", "log", "lru 0.7.2", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.12.0", "sp-api", "sp-consensus", @@ -10130,7 +10106,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sp-core", "sp-inherents", "sp-runtime", @@ -10147,7 +10123,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "async-trait", "merlin", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "serde", "sp-api", @@ -10168,7 +10144,7 @@ name = "sp-consensus-slots" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "serde", "sp-arithmetic", @@ -10182,7 +10158,7 @@ name = "sp-consensus-vrf" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec 3.0.0", + "parity-scale-codec", "schnorrkel", "sp-core", "sp-runtime", @@ -10210,7 +10186,7 @@ dependencies = [ "log", "merlin", "num-traits", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parity-util-mem", "parking_lot 0.12.0", "primitive-types", @@ -10285,7 +10261,7 @@ version = "0.11.0" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ "environmental", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sp-std", "sp-storage", ] @@ -10297,7 +10273,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "finality-grandpa", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "serde", "sp-api", @@ -10315,7 +10291,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "async-trait", "impl-trait-for-tuples", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sp-core", "sp-runtime", "sp-std", @@ -10331,7 +10307,7 @@ dependencies = [ "hash-db", "libsecp256k1", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.12.0", "secp256k1", "sp-core", @@ -10366,7 +10342,7 @@ dependencies = [ "async-trait", "futures 0.3.21", "merlin", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.12.0", "schnorrkel", "serde", @@ -10389,7 +10365,7 @@ name = "sp-npos-elections" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "serde", "sp-arithmetic", @@ -10449,7 +10425,7 @@ dependencies = [ "hash256-std-hasher", "impl-trait-for-tuples", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parity-util-mem", "paste", "rand 0.7.3", @@ -10468,7 +10444,7 @@ version = "5.0.0" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ "impl-trait-for-tuples", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "primitive-types", "sp-externalities", "sp-runtime-interface-proc-macro", @@ -10505,7 +10481,7 @@ name = "sp-session" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-api", "sp-core", @@ -10519,7 +10495,7 @@ name = "sp-staking" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-runtime", "sp-std", @@ -10533,7 +10509,7 @@ dependencies = [ "hash-db", "log", "num-traits", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parking_lot 0.12.0", "rand 0.7.3", "smallvec", @@ -10559,7 +10535,7 @@ version = "5.0.0" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ "impl-serde", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "ref-cast", "serde", "sp-debug-derive", @@ -10587,7 +10563,7 @@ dependencies = [ "async-trait", "futures-timer", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sp-api", "sp-inherents", "sp-runtime", @@ -10600,7 +10576,7 @@ name = "sp-tracing" version = "4.0.0" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sp-std", "tracing", "tracing-core", @@ -10623,7 +10599,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "async-trait", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-core", "sp-inherents", @@ -10639,7 +10615,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "hash-db", "memory-db", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "sp-core", "sp-std", @@ -10653,7 +10629,7 @@ version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ "impl-serde", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "parity-wasm 0.42.2", "scale-info", "serde", @@ -10669,7 +10645,7 @@ name = "sp-version-proc-macro" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95adccf96dadbe5e5e6bb8605d5a2c01" dependencies = [ - "parity-scale-codec 3.0.0", + "parity-scale-codec", "proc-macro2", "quote", "syn", @@ -10682,7 +10658,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bfc6fb4a95ad dependencies = [ "impl-trait-for-tuples", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sp-std", "wasmi", "wasmtime", @@ -10739,7 +10715,7 @@ dependencies = [ "pallet-election-provider-multi-phase", "pallet-staking", "pallet-transaction-payment", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "paste", "polkadot-core-primitives", "polkadot-runtime", @@ -10894,7 +10870,7 @@ dependencies = [ "jsonrpc-core-client", "jsonrpc-derive", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sc-client-api", "sc-rpc-api", "sc-transaction-pool-api", @@ -10926,7 +10902,7 @@ dependencies = [ "async-trait", "futures 0.3.21", "hex", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sc-client-api", "sc-client-db", "sc-consensus", @@ -11079,7 +11055,7 @@ name = "test-parachain-adder" version = "0.9.17" dependencies = [ "dlmalloc", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-parachain", "sp-io", "sp-std", @@ -11095,7 +11071,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-cli", "polkadot-node-core-pvf", "polkadot-node-primitives", @@ -11126,7 +11102,7 @@ version = "0.9.17" dependencies = [ "dlmalloc", "log", - "parity-scale-codec 2.3.1", + "parity-scale-codec", "polkadot-parachain", "sp-io", "sp-std", @@ -11142,7 +11118,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "log", - "parity-scale-codec 2.3.1", + "parity-scale-codec", "polkadot-cli", "polkadot-node-core-pvf", "polkadot-node-primitives", @@ -11164,7 +11140,7 @@ dependencies = [ name = "test-parachains" version = "0.9.17" dependencies = [ - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sp-core", "test-parachain-adder", "test-parachain-halt", @@ -11632,7 +11608,7 @@ dependencies = [ "clap", "jsonrpsee 0.4.1", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "remote-externalities", "sc-chain-spec", "sc-cli", @@ -12319,7 +12295,7 @@ dependencies = [ "pallet-vesting", "pallet-xcm", "pallet-xcm-benchmarks", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-parachain", "polkadot-primitives", "polkadot-runtime-common", @@ -12524,7 +12500,7 @@ dependencies = [ "derivative", "impl-trait-for-tuples", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "scale-info", "xcm-procedural", ] @@ -12539,7 +12515,7 @@ dependencies = [ "pallet-balances", "pallet-transaction-payment", "pallet-xcm", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-parachain", "polkadot-runtime-parachains", "scale-info", @@ -12560,7 +12536,7 @@ dependencies = [ "frame-support", "impl-trait-for-tuples", "log", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "sp-arithmetic", "sp-core", "sp-io", @@ -12604,7 +12580,7 @@ name = "xcm-simulator" version = "0.9.17" dependencies = [ "frame-support", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "paste", "polkadot-core-primitives", "polkadot-parachain", @@ -12623,7 +12599,7 @@ dependencies = [ "frame-system", "pallet-balances", "pallet-xcm", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain", "polkadot-runtime-parachains", @@ -12647,7 +12623,7 @@ dependencies = [ "honggfuzz", "pallet-balances", "pallet-xcm", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain", "polkadot-runtime-parachains", @@ -12703,7 +12679,7 @@ version = "0.9.17" dependencies = [ "futures-util", "lazy_static", - "parity-scale-codec 3.0.0", + "parity-scale-codec", "reqwest", "serde", "serde_json", From 91008662929f1fc327fcd1560c04e8f0ad98ef38 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Tue, 1 Mar 2022 12:19:29 +0000 Subject: [PATCH 04/47] spell check Signed-off-by: Andrei Sandu --- node/malus/src/variants/dispute_valid_candidates.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/malus/src/variants/dispute_valid_candidates.rs b/node/malus/src/variants/dispute_valid_candidates.rs index 8c3c72672c4e..d337d4428829 100644 --- a/node/malus/src/variants/dispute_valid_candidates.rs +++ b/node/malus/src/variants/dispute_valid_candidates.rs @@ -102,7 +102,7 @@ where pub(crate) struct DisputeValidCandidates { /// Backing configuration. fake_backing_validation: Option, - /// Approval voting configuraiton (applies to disputes as well). + /// Approval voting configuration (applies to disputes as well). fake_approval_validation: Option, } From cf1880dd8393e43ac7ca6de253b1758297310c22 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Wed, 2 Mar 2022 14:32:18 +0000 Subject: [PATCH 05/47] Malus tests are duplicated in the zombienet test suite Signed-off-by: Andrei Sandu --- .../0001-dispute-valid-block.feature | 29 -------------- .../0001-dispute-valid-block.toml | 39 ------------------- 2 files changed, 68 deletions(-) delete mode 100644 node/malus/integrationtests/0001-dispute-valid-block.feature delete mode 100644 node/malus/integrationtests/0001-dispute-valid-block.toml diff --git a/node/malus/integrationtests/0001-dispute-valid-block.feature b/node/malus/integrationtests/0001-dispute-valid-block.feature deleted file mode 100644 index fe0c14c791e4..000000000000 --- a/node/malus/integrationtests/0001-dispute-valid-block.feature +++ /dev/null @@ -1,29 +0,0 @@ -Description: Disputes -Network: ./0001-dispute-valid-block.toml -Creds: config - - -alice: is up -bob: is up -charlie: is up -david is up -alice: reports node_roles is 4 -bob: reports node_roles is 4 -alice: reports sub_libp2p_is_major_syncing is 0 -alice: reports block height is at least 2 within 15 seconds -alice: reports peers count is at least 2 -bob: reports block height is at least 2 -bob: reports peers count is at least 2 -charlie: reports block height is at least 2 -charlie: reports peers count is at least 2 -alice: reports parachain_candidate_disputes_total is at least 1 within 250 seconds -bob: reports parachain_candidate_disputes_total is at least 1 within 90 seconds -charlie: reports parachain_candidate_disputes_total is at least 1 within 90 seconds -alice: reports parachain_candidate_dispute_votes{validity="valid"} is at least 1 within 90 seconds -bob: reports parachain_candidate_dispute_votes{validity="valid"} is at least 2 within 90 seconds -charlie: reports parachain_candidate_dispute_votes{validity="valid"} is at least 2 within 90 seconds -alice: reports parachain_candidate_dispute_concluded{validity="valid"} is at least 1 within 90 seconds -alice: reports parachain_candidate_dispute_concluded{validity="invalid"} is 0 within 90 seconds -bob: reports parachain_candidate_dispute_concluded{validity="valid"} is at least 1 within 90 seconds -charlie: reports parachain_candidate_dispute_concluded{validity="valid"} is at least 1 within 90 seconds -charlie: reports parachain_candidate_dispute_concluded{validity="valid"} is at least 1 within 90 seconds diff --git a/node/malus/integrationtests/0001-dispute-valid-block.toml b/node/malus/integrationtests/0001-dispute-valid-block.toml deleted file mode 100644 index 9a4917841d30..000000000000 --- a/node/malus/integrationtests/0001-dispute-valid-block.toml +++ /dev/null @@ -1,39 +0,0 @@ -[settings] -timeout = 1000 - -[relaychain] -default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" -chain = "wococo-local" -command = "polkadot" - - [[relaychain.nodes]] - name = "alice" - validator = true - extra_args = [ "--alice", "-lparachain=debug" ] - - [[relaychain.nodes]] - name = "bob" - validator = true - extra_args = [ "--bob", "-lparachain=debug" ] - - [[relaychain.nodes]] - name = "charlie" - validator = true - extra_args = [ "--charlie", "-lparachain=debug" ] - - [[relaychain.nodes]] - name = "dave" - validator = true - command = "/usr/local/bin/malus dispute-ancestor" - extra_args = ["--dave", "-lparachain=debug"] - image = "{{MALUS_IMAGE}}" - autoConnectApi = false - -[[parachains]] -id = 100 - - [parachains.collator] - name = "collator01" - image = "{{COL_IMAGE}}" - command = "/usr/local/bin/adder-collator" - args = ["-lparachain=debug"] From 187d54930585654780aa27cfa90856148f643ff5 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Wed, 2 Mar 2022 14:33:12 +0000 Subject: [PATCH 06/47] Add new test Signed-off-by: Andrei Sandu --- .gitlab-ci.yml | 15 +++-- .../0003-parachains-bft-disputes.feature | 57 +++++++++++++++++++ .../0003-parachains-bft-disputes.toml | 41 +++++++++++++ 3 files changed, 105 insertions(+), 8 deletions(-) create mode 100644 zombienet_tests/functional/0003-parachains-bft-disputes.feature create mode 100644 zombienet_tests/functional/0003-parachains-bft-disputes.toml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 31c66b541b17..3a9660648038 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -698,32 +698,31 @@ zombienet-tests-parachains-disputes: tags: - zombienet-polkadot-integration-test -zombienet-tests-malus-dispute-valid: +zombienet-tests-bft-disputes-lag: stage: deploy image: "${ZOMBIENET_IMAGE}" <<: *kubernetes-env <<: *zombienet-refs needs: - job: publish-polkadot-image - - job: publish-malus-image - job: publish-test-collators-image variables: - GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/node/malus/integrationtests" + GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/functional" before_script: - echo "Zombie-net Tests Config" - - echo "${ZOMBIENET_IMAGE_NAME}" + - echo "${ZOMBIENET_IMAGE}" - echo "${PARACHAINS_IMAGE_NAME} ${PARACHAINS_IMAGE_TAG}" - - echo "${MALUS_IMAGE_NAME} ${MALUS_IMAGE_TAG}" + - echo "COL_IMAGE=${COLLATOR_IMAGE_NAME}:${COLLATOR_IMAGE_TAG}" - echo "${GH_DIR}" - - export DEBUG=zombie* + - export DEBUG=zombie,zombie::network-node - export ZOMBIENET_INTEGRATION_TEST_IMAGE=${PARACHAINS_IMAGE_NAME}:${PARACHAINS_IMAGE_TAG} - export MALUS_IMAGE=${MALUS_IMAGE_NAME}:${MALUS_IMAGE_TAG} - export COL_IMAGE=${COLLATOR_IMAGE_NAME}:${COLLATOR_IMAGE_TAG} script: - /home/nonroot/zombie-net/scripts/run-test-env-manager.sh --github-remote-dir="${GH_DIR}" - --test="0001-dispute-valid-block.feature" - allow_failure: false + --test="0003-parachains-bft-disputes.feature" + allow_failure: true retry: 2 tags: - zombienet-polkadot-integration-test diff --git a/zombienet_tests/functional/0003-parachains-bft-disputes.feature b/zombienet_tests/functional/0003-parachains-bft-disputes.feature new file mode 100644 index 000000000000..7e7c9b346681 --- /dev/null +++ b/zombienet_tests/functional/0003-parachains-bft-disputes.feature @@ -0,0 +1,57 @@ +Description: Test dispute finality lag at BFT threshold. Malus nodes are configured to dispute all candidates +and fake candidate validation (except during backing). +Network: ./0003-parachains-bft-disputes.toml +Creds: config + +honest-validator-0: is up +honest-validator-1: is up +honest-validator-2: is up +honest-validator-3: is up +honest-validator-4: is up +honest-validator-5: is up +honest-validator-6: is up +honest-validator-7: is up +honest-validator-8: is up +honest-validator-9: is up +honest-validator-10: is up +malus-validator-0: is up +malus-validator-1: is up +malus-validator-2: is up +malus-validator-3: is up +malus-validator-4: is up + +# Check authority status. +honest-validator-0: reports node_roles is 4 +honest-validator-1: reports node_roles is 4 +honest-validator-2: reports node_roles is 4 +honest-validator-3: reports node_roles is 4 +honest-validator-4: reports node_roles is 4 +honest-validator-5: reports node_roles is 4 +honest-validator-6: reports node_roles is 4 +honest-validator-7: reports node_roles is 4 +honest-validator-8: reports node_roles is 4 +honest-validator-9: reports node_roles is 4 +malus-validator-0: reports node_roles is 4 +malus-validator-1: reports node_roles is 4 +malus-validator-2: reports node_roles is 4 +malus-validator-3: reports node_roles is 4 +malus-validator-4: reports node_roles is 4 + + +honest-validator-0: parachain 2000 block height is at least 4 within 120 seconds +honest-validator-1: parachain 2001 block height is at least 4 within 120 seconds +honest-validator-2: parachain 2002 block height is at least 4 within 120 seconds +honest-validator-3: parachain 2003 block height is at least 4 within 120 seconds + +# Allow the the chains to make some more progress. +sleep 120 seconds + +honest-validator-0: reports parachain_disputes_finality_lag is lower than 4 +honest-validator-1: reports parachain_disputes_finality_lag is lower than 4 +honest-validator-2: reports parachain_disputes_finality_lag is lower than 4 +honest-validator-3: reports parachain_disputes_finality_lag is lower than 4 +honest-validator-6: reports parachain_disputes_finality_lag is lower than 4 +honest-validator-7: reports parachain_disputes_finality_lag is lower than 4 +honest-validator-8: reports parachain_disputes_finality_lag is lower than 4 +honest-validator-9: reports parachain_disputes_finality_lag is lower than 4 +honest-validator-10: reports parachain_disputes_finality_lag is lower than 4 diff --git a/zombienet_tests/functional/0003-parachains-bft-disputes.toml b/zombienet_tests/functional/0003-parachains-bft-disputes.toml new file mode 100644 index 000000000000..879b54d7338e --- /dev/null +++ b/zombienet_tests/functional/0003-parachains-bft-disputes.toml @@ -0,0 +1,41 @@ +[settings] +timeout = 1000 + +[relaychain.genesis.runtime.runtime_genesis_config.configuration.config] + max_validators_per_core = 3 + needed_approvals = 10 + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +chain = "rococo-local" +chain_spec_command = "../polkadot/target/testnet/polkadot build-spec --chain rococo-local --disable-default-bootnode" + + [[relaychain.node_groups]] + name = "malus-validator" + args = [ "-lparachain=debug" ] + command = "malus --fake-approval-validation=invalid dispute-ancestor" + count = 5 + + [[relaychain.node_groups]] + name = "honest-validator" + args = [ "-lparachain=debug" ] + count = 11 + +{% for id in range(2000,2004) %} +[[parachains]] +id = {{id}} +addToGenesis = true +genesis_state_generator = "../polkadot/target/testnet/undying-collator export-genesis-state --pov-size={{(id - 1999)*1000}} --pvf-complexity={{(id - 1999)*10}}" + + [parachains.collator] + name = "collator" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["--pov-size={{(id - 1999)*1000}}", "--pvf-complexity={{(id - 1999)*10}}", "-lparachain=debug", "--parachain-id {{id}}"] + count = 1 +{% endfor %} + +[types.Header] +number = "u64" +parent_hash = "Hash" +post_state = "Hash" \ No newline at end of file From 9212aec0d6eda3e5d690ce60be9350bb0ba8af83 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Wed, 2 Mar 2022 14:42:02 +0000 Subject: [PATCH 07/47] fix path Signed-off-by: Andrei Sandu --- zombienet_tests/functional/0003-parachains-bft-disputes.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zombienet_tests/functional/0003-parachains-bft-disputes.toml b/zombienet_tests/functional/0003-parachains-bft-disputes.toml index 879b54d7338e..efb18e338e94 100644 --- a/zombienet_tests/functional/0003-parachains-bft-disputes.toml +++ b/zombienet_tests/functional/0003-parachains-bft-disputes.toml @@ -8,7 +8,7 @@ timeout = 1000 [relaychain] default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" chain = "rococo-local" -chain_spec_command = "../polkadot/target/testnet/polkadot build-spec --chain rococo-local --disable-default-bootnode" +chain_spec_command = "polkadot build-spec --chain rococo-local --disable-default-bootnode" [[relaychain.node_groups]] name = "malus-validator" @@ -25,7 +25,7 @@ chain_spec_command = "../polkadot/target/testnet/polkadot build-spec --chain roc [[parachains]] id = {{id}} addToGenesis = true -genesis_state_generator = "../polkadot/target/testnet/undying-collator export-genesis-state --pov-size={{(id - 1999)*1000}} --pvf-complexity={{(id - 1999)*10}}" +genesis_state_generator = "undying-collator export-genesis-state --pov-size={{(id - 1999)*1000}} --pvf-complexity={{(id - 1999)*10}}" [parachains.collator] name = "collator" From efd37ad77360a56b15c5b760bb48f0469e65f464 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Wed, 2 Mar 2022 14:47:26 +0000 Subject: [PATCH 08/47] spellcheck Signed-off-by: Andrei Sandu --- node/malus/src/malus.rs | 4 ---- node/malus/src/variants/common.rs | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/node/malus/src/malus.rs b/node/malus/src/malus.rs index ccd0a4c687ad..ae7214ccfe4f 100644 --- a/node/malus/src/malus.rs +++ b/node/malus/src/malus.rs @@ -49,10 +49,6 @@ enum NemesisVariant { } #[derive(ArgEnum, Clone, Debug, PartialEq)] -#[clap( - about = "Fake candidate validation - forces all `ValidateCandidate*` calls to return a configured result.", - version -)] #[clap(rename_all = "kebab-case")] pub enum FakeCandidateValidation { Invalid, diff --git a/node/malus/src/variants/common.rs b/node/malus/src/variants/common.rs index eab1c950daaf..f613535d1f1d 100644 --- a/node/malus/src/variants/common.rs +++ b/node/malus/src/variants/common.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Implements common features for nemesis. Currently, only FakeValidationResult +//! Implements common features for nemesis. Currently, only `FakeValidationResult` //! interceptor is implemented. #![allow(missing_docs)] From d4da58d1b01cfcfd6ab8b06f2d544019e60f3a47 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Wed, 2 Mar 2022 14:49:31 +0000 Subject: [PATCH 09/47] typos Signed-off-by: Andrei Sandu --- node/malus/src/variants/common.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/malus/src/variants/common.rs b/node/malus/src/variants/common.rs index f613535d1f1d..f1ec7b5cb281 100644 --- a/node/malus/src/variants/common.rs +++ b/node/malus/src/variants/common.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright 2022 Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Implements common features for nemesis. Currently, only `FakeValidationResult` +//! Implements common code for nemesis. Currently, only `FakeValidationResult` //! interceptor is implemented. #![allow(missing_docs)] From 3b7025d64f3acf441d712c6d75374074b354d89e Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Thu, 3 Mar 2022 11:30:42 +0000 Subject: [PATCH 10/47] Add malus image param Signed-off-by: Andrei Sandu --- zombienet_tests/functional/0003-parachains-bft-disputes.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/zombienet_tests/functional/0003-parachains-bft-disputes.toml b/zombienet_tests/functional/0003-parachains-bft-disputes.toml index efb18e338e94..42760b8e9b36 100644 --- a/zombienet_tests/functional/0003-parachains-bft-disputes.toml +++ b/zombienet_tests/functional/0003-parachains-bft-disputes.toml @@ -11,6 +11,7 @@ chain = "rococo-local" chain_spec_command = "polkadot build-spec --chain rococo-local --disable-default-bootnode" [[relaychain.node_groups]] + image = "{{MALUS_IMAGE}}" name = "malus-validator" args = [ "-lparachain=debug" ] command = "malus --fake-approval-validation=invalid dispute-ancestor" From 628de45747291388d575c74340ad73e6e76b90fb Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Fri, 4 Mar 2022 20:05:20 +0000 Subject: [PATCH 11/47] Bump zombienet and CPU/mem limits Signed-off-by: Andrei Sandu --- .gitlab-ci.yml | 2 +- zombienet_tests/functional/0003-parachains-bft-disputes.toml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3a9660648038..5db9a30f0ee6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -27,7 +27,7 @@ variables: CI_IMAGE: "paritytech/ci-linux:production" DOCKER_OS: "debian:stretch" ARCH: "x86_64" - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.2.14" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.2.15" VAULT_SERVER_URL: "https://vault.parity-mgmt-vault.parity.io" VAULT_AUTH_PATH: "gitlab-parity-io-jwt" VAULT_AUTH_ROLE: "cicd_gitlab_parity_${CI_PROJECT_NAME}" diff --git a/zombienet_tests/functional/0003-parachains-bft-disputes.toml b/zombienet_tests/functional/0003-parachains-bft-disputes.toml index 42760b8e9b36..1f4ce3c8aee4 100644 --- a/zombienet_tests/functional/0003-parachains-bft-disputes.toml +++ b/zombienet_tests/functional/0003-parachains-bft-disputes.toml @@ -10,6 +10,10 @@ default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" chain = "rococo-local" chain_spec_command = "polkadot build-spec --chain rococo-local --disable-default-bootnode" +[relaychain.default_resources] +limits = { memory = "8G", cpu = "2" } +requests = { memory = "2G", cpu = "1" } + [[relaychain.node_groups]] image = "{{MALUS_IMAGE}}" name = "malus-validator" From b70512b867ece3e2ffc80c9b169ab9f825e2ae9e Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Thu, 10 Mar 2022 16:07:40 +0000 Subject: [PATCH 12/47] Review feedback Signed-off-by: Andrei Sandu --- cli/src/cli.rs | 1 + node/malus/src/malus.rs | 88 ++++++++++++++++--- node/malus/src/variants/common.rs | 82 +++++++++-------- .../src/variants/dispute_valid_candidates.rs | 26 ++---- 4 files changed, 128 insertions(+), 69 deletions(-) diff --git a/cli/src/cli.rs b/cli/src/cli.rs index e69259568ca5..96ce1d6d0ae7 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -83,6 +83,7 @@ pub struct ValidationWorkerCommand { #[allow(missing_docs)] #[derive(Debug, Parser)] +#[cfg_attr(feature = "malus", derive(Clone))] pub struct RunCmd { #[allow(missing_docs)] #[clap(flatten)] diff --git a/node/malus/src/malus.rs b/node/malus/src/malus.rs index ae7214ccfe4f..40403c0e64dd 100644 --- a/node/malus/src/malus.rs +++ b/node/malus/src/malus.rs @@ -19,6 +19,7 @@ use clap::{ArgEnum, Parser}; use color_eyre::eyre; use polkadot_cli::{Cli, RunCmd}; +use polkadot_node_primitives::InvalidCandidate; pub(crate) mod interceptor; pub(crate) mod shared; @@ -37,7 +38,7 @@ enum NemesisVariant { /// Back a candidate with a specifically crafted proof of validity. BackGarbageCandidate(RunCmd), /// Delayed disputing of ancestors that are perfectly fine. - DisputeAncestor(RunCmd), + DisputeAncestor(DisputeAncestorOptions), #[allow(missing_docs)] #[clap(name = "prepare-worker", hide = true)] @@ -51,21 +52,87 @@ enum NemesisVariant { #[derive(ArgEnum, Clone, Debug, PartialEq)] #[clap(rename_all = "kebab-case")] pub enum FakeCandidateValidation { - Invalid, + Disabled, + BackingInvalid, + ApprovalInvalid, + BackingAndApprovalInvalid, // TODO: impl Valid. } +/// Candidate invalidity details +#[derive(ArgEnum, Clone, Debug, PartialEq)] +#[clap(rename_all = "kebab-case")] +pub enum FakeCandidateValidationError { + /// Validation outputs check doesn't pass. + InvalidOutputs, + /// Failed to execute.`validate_block`. This includes function panicking. + ExecutionError, + /// Execution timeout. + Timeout, + /// Validation input is over the limit. + ParamsTooLarge, + /// Code size is over the limit. + CodeTooLarge, + /// Code does not decompress correctly. + CodeDecompressionFailure, + /// PoV does not decompress correctly. + PoVDecompressionFailure, + /// Validation function returned invalid data. + BadReturn, + /// Invalid relay chain parent. + BadParent, + /// POV hash does not match. + PoVHashMismatch, + /// Bad collator signature. + BadSignature, + /// Para head hash does not match. + ParaHeadHashMismatch, + /// Validation code hash does not match. + CodeHashMismatch, +} + +impl Into for FakeCandidateValidationError { + fn into(self) -> InvalidCandidate { + match self { + FakeCandidateValidationError::ExecutionError => + InvalidCandidate::ExecutionError("Malus".into()), + FakeCandidateValidationError::InvalidOutputs => InvalidCandidate::InvalidOutputs, + FakeCandidateValidationError::Timeout => InvalidCandidate::Timeout, + FakeCandidateValidationError::ParamsTooLarge => InvalidCandidate::ParamsTooLarge(666), + FakeCandidateValidationError::CodeTooLarge => InvalidCandidate::CodeTooLarge(666), + FakeCandidateValidationError::CodeDecompressionFailure => + InvalidCandidate::CodeDecompressionFailure, + FakeCandidateValidationError::PoVDecompressionFailure => + InvalidCandidate::PoVDecompressionFailure, + FakeCandidateValidationError::BadReturn => InvalidCandidate::BadReturn, + FakeCandidateValidationError::BadParent => InvalidCandidate::BadParent, + FakeCandidateValidationError::PoVHashMismatch => InvalidCandidate::PoVHashMismatch, + FakeCandidateValidationError::BadSignature => InvalidCandidate::BadSignature, + FakeCandidateValidationError::ParaHeadHashMismatch => + InvalidCandidate::ParaHeadHashMismatch, + FakeCandidateValidationError::CodeHashMismatch => InvalidCandidate::CodeHashMismatch, + } + } +} + #[derive(Debug, Parser)] #[allow(missing_docs)] struct MalusCli { #[clap(subcommand)] pub variant: NemesisVariant, +} +#[derive(Clone, Debug, Parser)] +#[clap(rename_all = "kebab-case")] +#[allow(missing_docs)] +struct DisputeAncestorOptions { + #[clap(long, arg_enum, ignore_case = true, default_value_t = FakeCandidateValidation::Disabled)] + pub fake_validation: FakeCandidateValidation, - #[clap(long, arg_enum, ignore_case = true)] - pub fake_backing_validation: Option, + #[clap(long, arg_enum, ignore_case = true, default_value_t = FakeCandidateValidationError::InvalidOutputs)] + pub fake_validation_error: FakeCandidateValidationError, - #[clap(long, arg_enum, ignore_case = true)] - pub fake_approval_validation: Option, + #[clap(flatten)] + cmd: RunCmd, } fn run_cmd(run: RunCmd) -> Cli { @@ -80,12 +147,9 @@ impl MalusCli { polkadot_cli::run_node(run_cmd(cmd), BackGarbageCandidate)?, NemesisVariant::SuggestGarbageCandidate(cmd) => polkadot_cli::run_node(run_cmd(cmd), SuggestGarbageCandidate)?, - NemesisVariant::DisputeAncestor(cmd) => polkadot_cli::run_node( - run_cmd(cmd), - DisputeValidCandidates::new( - self.fake_backing_validation, - self.fake_approval_validation, - ), + NemesisVariant::DisputeAncestor(opts) => polkadot_cli::run_node( + run_cmd(opts.clone().cmd), + DisputeValidCandidates::new(opts), )?, NemesisVariant::PvfPrepareWorker(cmd) => { #[cfg(target_os = "android")] diff --git a/node/malus/src/variants/common.rs b/node/malus/src/variants/common.rs index f1ec7b5cb281..5569f44364a6 100644 --- a/node/malus/src/variants/common.rs +++ b/node/malus/src/variants/common.rs @@ -20,7 +20,7 @@ #![allow(missing_docs)] // Filter wrapping related types. -use crate::{interceptor::*, shared::MALUS, FakeCandidateValidation}; +use crate::{interceptor::*, shared::MALUS, FakeCandidateValidation, FakeCandidateValidationError}; use polkadot_node_primitives::{InvalidCandidate, ValidationResult}; use polkadot_node_subsystem::messages::CandidateValidationMessage; @@ -28,16 +28,16 @@ use polkadot_node_subsystem::messages::CandidateValidationMessage; /// An interceptor which fakes validation result with a preconfigured result. /// Replaces `CandidateValidationSubsystem`. pub struct ReplaceValidationResult { - fake_backing_validation: Option, - fake_approval_validation: Option, + fake_validation: FakeCandidateValidation, + fake_validation_error: FakeCandidateValidationError, } impl ReplaceValidationResult { pub fn new( - fake_backing_validation: Option, - fake_approval_validation: Option, + fake_validation: FakeCandidateValidation, + fake_validation_error: FakeCandidateValidationError, ) -> Self { - Self { fake_backing_validation, fake_approval_validation } + Self { fake_validation, fake_validation_error } } } @@ -54,7 +54,7 @@ where _sender: &mut Sender, msg: FromOverseer, ) -> Option> { - if self.fake_backing_validation.is_none() && self.fake_approval_validation.is_none() { + if self.fake_validation == FakeCandidateValidation::Disabled { return Some(msg) } @@ -70,22 +70,24 @@ where sender, ), } => { - if let Some(FakeCandidateValidation::Invalid) = self.fake_approval_validation { - let validation_result = - ValidationResult::Invalid(InvalidCandidate::InvalidOutputs); + match self.fake_validation { + FakeCandidateValidation::ApprovalInvalid | + FakeCandidateValidation::BackingAndApprovalInvalid => { + let validation_result = + ValidationResult::Invalid(InvalidCandidate::InvalidOutputs); - tracing::info!( - target = MALUS, - para_id = ?descriptor.para_id, - candidate_hash = ?descriptor.para_head, - "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 - } else { - Some(FromOverseer::Communication { + tracing::info!( + target = MALUS, + para_id = ?descriptor.para_id, + candidate_hash = ?descriptor.para_head, + "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 + }, + _ => Some(FromOverseer::Communication { msg: CandidateValidationMessage::ValidateFromExhaustive( validation_data, validation_code, @@ -94,33 +96,35 @@ where timeout, sender, ), - }) + }), } }, FromOverseer::Communication { msg: CandidateValidationMessage::ValidateFromChainState(descriptor, pov, timeout, sender), } => { - if let Some(FakeCandidateValidation::Invalid) = self.fake_backing_validation { - let validation_result = - ValidationResult::Invalid(InvalidCandidate::InvalidOutputs); - tracing::info!( - target = MALUS, - para_id = ?descriptor.para_id, - candidate_hash = ?descriptor.para_head, - "ValidateFromChainState result: {:?}", - &validation_result - ); + match self.fake_validation { + FakeCandidateValidation::BackingInvalid | + FakeCandidateValidation::BackingAndApprovalInvalid => { + let validation_result = + ValidationResult::Invalid(self.fake_validation_error.clone().into()); + tracing::info!( + target = MALUS, + para_id = ?descriptor.para_id, + candidate_hash = ?descriptor.para_head, + "ValidateFromChainState 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 - } else { - Some(FromOverseer::Communication { + // We're not even checking the candidate, this makes us appear faster than honest validators. + sender.send(Ok(validation_result)).unwrap(); + None + }, + _ => Some(FromOverseer::Communication { msg: CandidateValidationMessage::ValidateFromChainState( descriptor, pov, timeout, sender, ), - }) + }), } }, msg => Some(msg), diff --git a/node/malus/src/variants/dispute_valid_candidates.rs b/node/malus/src/variants/dispute_valid_candidates.rs index d337d4428829..9f2f4f662f0c 100644 --- a/node/malus/src/variants/dispute_valid_candidates.rs +++ b/node/malus/src/variants/dispute_valid_candidates.rs @@ -32,7 +32,7 @@ use polkadot_cli::{ // Filter wrapping related types. use crate::{ - interceptor::*, shared::MALUS, variants::ReplaceValidationResult, FakeCandidateValidation, + interceptor::*, shared::MALUS, variants::ReplaceValidationResult, DisputeAncestorOptions, }; // Import extra types relevant to the particular @@ -99,25 +99,15 @@ where } } } -pub(crate) struct DisputeValidCandidates { - /// Backing configuration. - fake_backing_validation: Option, - /// Approval voting configuration (applies to disputes as well). - fake_approval_validation: Option, -} -impl Default for DisputeValidCandidates { - fn default() -> Self { - Self { fake_backing_validation: None, fake_approval_validation: None } - } +pub(crate) struct DisputeValidCandidates { + /// Fake validation config (applies to disputes as well). + opts: DisputeAncestorOptions, } impl DisputeValidCandidates { - pub fn new( - fake_backing_validation: Option, - fake_approval_validation: Option, - ) -> Self { - Self { fake_backing_validation, fake_approval_validation } + pub fn new(opts: DisputeAncestorOptions) -> Self { + Self { opts } } } @@ -136,8 +126,8 @@ impl OverseerGen for DisputeValidCandidates { let crypto_store_ptr = args.keystore.clone() as SyncCryptoStorePtr; let backing_filter = ReplaceApprovalsWithDisputes; let validation_filter = ReplaceValidationResult::new( - self.fake_backing_validation.clone(), - self.fake_approval_validation.clone(), + self.opts.fake_validation.clone(), + self.opts.fake_validation_error.clone(), ); let candidate_validation_config = args.candidate_validation_config.clone(); From f78686688444d4dcc790ae1be616bf55ff8313b8 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Thu, 10 Mar 2022 16:21:52 +0000 Subject: [PATCH 13/47] move stuff around Signed-off-by: Andrei Sandu --- node/malus/src/malus.rs | 82 +---------------- node/malus/src/variants/common.rs | 3 +- .../src/variants/dispute_valid_candidates.rs | 87 ++++++++++++++++++- node/malus/src/variants/mod.rs | 3 +- 4 files changed, 89 insertions(+), 86 deletions(-) diff --git a/node/malus/src/malus.rs b/node/malus/src/malus.rs index 40403c0e64dd..de051dec841a 100644 --- a/node/malus/src/malus.rs +++ b/node/malus/src/malus.rs @@ -16,10 +16,9 @@ //! A malus or nemesis node launch code. -use clap::{ArgEnum, Parser}; +use clap::Parser; use color_eyre::eyre; use polkadot_cli::{Cli, RunCmd}; -use polkadot_node_primitives::InvalidCandidate; pub(crate) mod interceptor; pub(crate) mod shared; @@ -49,91 +48,12 @@ enum NemesisVariant { PvfExecuteWorker(polkadot_cli::ValidationWorkerCommand), } -#[derive(ArgEnum, Clone, Debug, PartialEq)] -#[clap(rename_all = "kebab-case")] -pub enum FakeCandidateValidation { - Disabled, - BackingInvalid, - ApprovalInvalid, - BackingAndApprovalInvalid, - // TODO: impl Valid. -} - -/// Candidate invalidity details -#[derive(ArgEnum, Clone, Debug, PartialEq)] -#[clap(rename_all = "kebab-case")] -pub enum FakeCandidateValidationError { - /// Validation outputs check doesn't pass. - InvalidOutputs, - /// Failed to execute.`validate_block`. This includes function panicking. - ExecutionError, - /// Execution timeout. - Timeout, - /// Validation input is over the limit. - ParamsTooLarge, - /// Code size is over the limit. - CodeTooLarge, - /// Code does not decompress correctly. - CodeDecompressionFailure, - /// PoV does not decompress correctly. - PoVDecompressionFailure, - /// Validation function returned invalid data. - BadReturn, - /// Invalid relay chain parent. - BadParent, - /// POV hash does not match. - PoVHashMismatch, - /// Bad collator signature. - BadSignature, - /// Para head hash does not match. - ParaHeadHashMismatch, - /// Validation code hash does not match. - CodeHashMismatch, -} - -impl Into for FakeCandidateValidationError { - fn into(self) -> InvalidCandidate { - match self { - FakeCandidateValidationError::ExecutionError => - InvalidCandidate::ExecutionError("Malus".into()), - FakeCandidateValidationError::InvalidOutputs => InvalidCandidate::InvalidOutputs, - FakeCandidateValidationError::Timeout => InvalidCandidate::Timeout, - FakeCandidateValidationError::ParamsTooLarge => InvalidCandidate::ParamsTooLarge(666), - FakeCandidateValidationError::CodeTooLarge => InvalidCandidate::CodeTooLarge(666), - FakeCandidateValidationError::CodeDecompressionFailure => - InvalidCandidate::CodeDecompressionFailure, - FakeCandidateValidationError::PoVDecompressionFailure => - InvalidCandidate::PoVDecompressionFailure, - FakeCandidateValidationError::BadReturn => InvalidCandidate::BadReturn, - FakeCandidateValidationError::BadParent => InvalidCandidate::BadParent, - FakeCandidateValidationError::PoVHashMismatch => InvalidCandidate::PoVHashMismatch, - FakeCandidateValidationError::BadSignature => InvalidCandidate::BadSignature, - FakeCandidateValidationError::ParaHeadHashMismatch => - InvalidCandidate::ParaHeadHashMismatch, - FakeCandidateValidationError::CodeHashMismatch => InvalidCandidate::CodeHashMismatch, - } - } -} - #[derive(Debug, Parser)] #[allow(missing_docs)] struct MalusCli { #[clap(subcommand)] pub variant: NemesisVariant, } -#[derive(Clone, Debug, Parser)] -#[clap(rename_all = "kebab-case")] -#[allow(missing_docs)] -struct DisputeAncestorOptions { - #[clap(long, arg_enum, ignore_case = true, default_value_t = FakeCandidateValidation::Disabled)] - pub fake_validation: FakeCandidateValidation, - - #[clap(long, arg_enum, ignore_case = true, default_value_t = FakeCandidateValidationError::InvalidOutputs)] - pub fake_validation_error: FakeCandidateValidationError, - - #[clap(flatten)] - cmd: RunCmd, -} fn run_cmd(run: RunCmd) -> Cli { Cli { subcommand: None, run } diff --git a/node/malus/src/variants/common.rs b/node/malus/src/variants/common.rs index 5569f44364a6..d3feca183654 100644 --- a/node/malus/src/variants/common.rs +++ b/node/malus/src/variants/common.rs @@ -20,7 +20,8 @@ #![allow(missing_docs)] // Filter wrapping related types. -use crate::{interceptor::*, shared::MALUS, FakeCandidateValidation, FakeCandidateValidationError}; +use super::dispute_valid_candidates::{FakeCandidateValidation, FakeCandidateValidationError}; +use crate::{interceptor::*, shared::MALUS}; use polkadot_node_primitives::{InvalidCandidate, ValidationResult}; use polkadot_node_subsystem::messages::CandidateValidationMessage; diff --git a/node/malus/src/variants/dispute_valid_candidates.rs b/node/malus/src/variants/dispute_valid_candidates.rs index 9f2f4f662f0c..37b305d4eaed 100644 --- a/node/malus/src/variants/dispute_valid_candidates.rs +++ b/node/malus/src/variants/dispute_valid_candidates.rs @@ -21,6 +21,7 @@ #![allow(missing_docs)] +use clap::{ArgEnum, Parser}; use polkadot_cli::{ prepared_overseer_builder, service::{ @@ -28,12 +29,12 @@ use polkadot_cli::{ OverseerConnector, OverseerGen, OverseerGenArgs, OverseerHandle, ParachainHost, ProvideRuntimeApi, SpawnNamed, }, + RunCmd, }; // Filter wrapping related types. -use crate::{ - interceptor::*, shared::MALUS, variants::ReplaceValidationResult, DisputeAncestorOptions, -}; +use crate::{interceptor::*, shared::MALUS, variants::ReplaceValidationResult}; +use polkadot_node_primitives::InvalidCandidate; // Import extra types relevant to the particular // subsystem. @@ -47,6 +48,86 @@ use sp_keystore::SyncCryptoStorePtr; use std::sync::Arc; +#[derive(ArgEnum, Clone, Debug, PartialEq)] +#[clap(rename_all = "kebab-case")] +pub enum FakeCandidateValidation { + Disabled, + BackingInvalid, + ApprovalInvalid, + BackingAndApprovalInvalid, + // TODO: impl Valid. +} + +/// Candidate invalidity details +#[derive(ArgEnum, Clone, Debug, PartialEq)] +#[clap(rename_all = "kebab-case")] +pub enum FakeCandidateValidationError { + /// Validation outputs check doesn't pass. + InvalidOutputs, + /// Failed to execute.`validate_block`. This includes function panicking. + ExecutionError, + /// Execution timeout. + Timeout, + /// Validation input is over the limit. + ParamsTooLarge, + /// Code size is over the limit. + CodeTooLarge, + /// Code does not decompress correctly. + CodeDecompressionFailure, + /// PoV does not decompress correctly. + POVDecompressionFailure, + /// Validation function returned invalid data. + BadReturn, + /// Invalid relay chain parent. + BadParent, + /// POV hash does not match. + POVHashMismatch, + /// Bad collator signature. + BadSignature, + /// Para head hash does not match. + ParaHeadHashMismatch, + /// Validation code hash does not match. + CodeHashMismatch, +} + +impl Into for FakeCandidateValidationError { + fn into(self) -> InvalidCandidate { + match self { + FakeCandidateValidationError::ExecutionError => + InvalidCandidate::ExecutionError("Malus".into()), + FakeCandidateValidationError::InvalidOutputs => InvalidCandidate::InvalidOutputs, + FakeCandidateValidationError::Timeout => InvalidCandidate::Timeout, + FakeCandidateValidationError::ParamsTooLarge => InvalidCandidate::ParamsTooLarge(666), + FakeCandidateValidationError::CodeTooLarge => InvalidCandidate::CodeTooLarge(666), + FakeCandidateValidationError::CodeDecompressionFailure => + InvalidCandidate::CodeDecompressionFailure, + FakeCandidateValidationError::POVDecompressionFailure => + InvalidCandidate::PoVDecompressionFailure, + FakeCandidateValidationError::BadReturn => InvalidCandidate::BadReturn, + FakeCandidateValidationError::BadParent => InvalidCandidate::BadParent, + FakeCandidateValidationError::POVHashMismatch => InvalidCandidate::PoVHashMismatch, + FakeCandidateValidationError::BadSignature => InvalidCandidate::BadSignature, + FakeCandidateValidationError::ParaHeadHashMismatch => + InvalidCandidate::ParaHeadHashMismatch, + FakeCandidateValidationError::CodeHashMismatch => InvalidCandidate::CodeHashMismatch, + } + } +} + +#[derive(Clone, Debug, Parser)] +#[clap(rename_all = "kebab-case")] +#[allow(missing_docs)] +pub struct DisputeAncestorOptions { + #[clap(long, arg_enum, ignore_case = true, default_value_t = FakeCandidateValidation::Disabled)] + pub fake_validation: FakeCandidateValidation, + + #[clap(long, arg_enum, ignore_case = true, default_value_t = FakeCandidateValidationError::InvalidOutputs)] + pub fake_validation_error: FakeCandidateValidationError, + + #[clap(flatten)] + pub cmd: RunCmd, +} + /// Replace outgoing approval messages with disputes. #[derive(Clone, Debug)] struct ReplaceApprovalsWithDisputes; diff --git a/node/malus/src/variants/mod.rs b/node/malus/src/variants/mod.rs index dada02f2787b..fa014afaa050 100644 --- a/node/malus/src/variants/mod.rs +++ b/node/malus/src/variants/mod.rs @@ -22,7 +22,8 @@ mod dispute_valid_candidates; mod suggest_garbage_candidate; pub(crate) use self::{ - back_garbage_candidate::BackGarbageCandidate, dispute_valid_candidates::DisputeValidCandidates, + back_garbage_candidate::BackGarbageCandidate, + dispute_valid_candidates::{DisputeAncestorOptions, DisputeValidCandidates}, suggest_garbage_candidate::SuggestGarbageCandidate, }; pub(crate) use common::ReplaceValidationResult; From c4a4560ac966811933444043b096fbba37d23949 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Wed, 23 Mar 2022 19:49:51 +0000 Subject: [PATCH 14/47] chores Signed-off-by: Andrei Sandu --- node/malus/src/variants/common.rs | 8 ++++---- node/malus/src/variants/dispute_valid_candidates.rs | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/node/malus/src/variants/common.rs b/node/malus/src/variants/common.rs index d3feca183654..f261cfdd99a2 100644 --- a/node/malus/src/variants/common.rs +++ b/node/malus/src/variants/common.rs @@ -77,8 +77,8 @@ where let validation_result = ValidationResult::Invalid(InvalidCandidate::InvalidOutputs); - tracing::info!( - target = MALUS, + gum::info!( + target: MALUS, para_id = ?descriptor.para_id, candidate_hash = ?descriptor.para_head, "ValidateFromExhaustive result: {:?}", @@ -109,8 +109,8 @@ where FakeCandidateValidation::BackingAndApprovalInvalid => { let validation_result = ValidationResult::Invalid(self.fake_validation_error.clone().into()); - tracing::info!( - target = MALUS, + gum::info!( + target: MALUS, para_id = ?descriptor.para_id, candidate_hash = ?descriptor.para_head, "ValidateFromChainState result: {:?}", diff --git a/node/malus/src/variants/dispute_valid_candidates.rs b/node/malus/src/variants/dispute_valid_candidates.rs index 37b305d4eaed..95a02b7ab2f3 100644 --- a/node/malus/src/variants/dispute_valid_candidates.rs +++ b/node/malus/src/variants/dispute_valid_candidates.rs @@ -48,7 +48,7 @@ use sp_keystore::SyncCryptoStorePtr; use std::sync::Arc; -#[derive(ArgEnum, Clone, Debug, PartialEq)] +#[derive(ArgEnum, Clone, Copy, Debug, PartialEq)] #[clap(rename_all = "kebab-case")] pub enum FakeCandidateValidation { Disabled, @@ -59,7 +59,7 @@ pub enum FakeCandidateValidation { } /// Candidate invalidity details -#[derive(ArgEnum, Clone, Debug, PartialEq)] +#[derive(ArgEnum, Clone, Copy, Debug, PartialEq)] #[clap(rename_all = "kebab-case")] pub enum FakeCandidateValidationError { /// Validation outputs check doesn't pass. @@ -160,8 +160,8 @@ where session, .. }) => { - tracing::info!( - target = MALUS, + gum::info!( + target: MALUS, para_id = ?candidate_receipt.descriptor.para_id, ?candidate_hash, "Disputing candidate", @@ -207,8 +207,8 @@ impl OverseerGen for DisputeValidCandidates { let crypto_store_ptr = args.keystore.clone() as SyncCryptoStorePtr; let backing_filter = ReplaceApprovalsWithDisputes; let validation_filter = ReplaceValidationResult::new( - self.opts.fake_validation.clone(), - self.opts.fake_validation_error.clone(), + self.opts.fake_validation, + self.opts.fake_validation_error, ); let candidate_validation_config = args.candidate_validation_config.clone(); From e90ab096514034b7af1682e277f3ae7d19dc02b3 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Thu, 24 Mar 2022 19:47:23 +0000 Subject: [PATCH 15/47] Impl valid - still wip Signed-off-by: Andrei Sandu --- node/malus/src/variants/common.rs | 225 ++++++++++++++++-- .../src/variants/dispute_valid_candidates.rs | 71 +----- 2 files changed, 214 insertions(+), 82 deletions(-) diff --git a/node/malus/src/variants/common.rs b/node/malus/src/variants/common.rs index f261cfdd99a2..ca1f2c124b0d 100644 --- a/node/malus/src/variants/common.rs +++ b/node/malus/src/variants/common.rs @@ -19,40 +19,208 @@ #![allow(missing_docs)] -// Filter wrapping related types. -use super::dispute_valid_candidates::{FakeCandidateValidation, FakeCandidateValidationError}; use crate::{interceptor::*, shared::MALUS}; -use polkadot_node_primitives::{InvalidCandidate, ValidationResult}; -use polkadot_node_subsystem::messages::CandidateValidationMessage; +use polkadot_node_primitives::{InvalidCandidate, PoV, ValidationResult}; +use polkadot_node_subsystem::messages::{ + AvailabilityRecoveryMessage, CandidateValidationMessage, ValidationFailed, +}; +use polkadot_node_subsystem_util as util; + +use polkadot_primitives::v2::{ + CandidateCommitments, CandidateDescriptor, CandidateReceipt, Hash, PersistedValidationData, + ValidationCode, +}; + +use polkadot_cli::service::SpawnNamed; + +use futures::channel::oneshot; +use std::sync::Arc; +use clap::ArgEnum; + + +#[derive(ArgEnum, Clone, Copy, Debug, PartialEq)] +#[clap(rename_all = "kebab-case")] +pub enum FakeCandidateValidation { + Disabled, + BackingInvalid, + ApprovalInvalid, + BackingAndApprovalInvalid, + BackingValid, + ApprovalValid, + BackingAndApprovalValid, + // TODO: later. + // BackingValidAndApprovalInvalid, + // BackingInvalidAndApprovalValid, +} + +/// Candidate invalidity details +#[derive(ArgEnum, Clone, Copy, Debug, PartialEq)] +#[clap(rename_all = "kebab-case")] +pub enum FakeCandidateValidationError { + /// Validation outputs check doesn't pass. + InvalidOutputs, + /// Failed to execute.`validate_block`. This includes function panicking. + ExecutionError, + /// Execution timeout. + Timeout, + /// Validation input is over the limit. + ParamsTooLarge, + /// Code size is over the limit. + CodeTooLarge, + /// Code does not decompress correctly. + CodeDecompressionFailure, + /// PoV does not decompress correctly. + POVDecompressionFailure, + /// Validation function returned invalid data. + BadReturn, + /// Invalid relay chain parent. + BadParent, + /// POV hash does not match. + POVHashMismatch, + /// Bad collator signature. + BadSignature, + /// Para head hash does not match. + ParaHeadHashMismatch, + /// Validation code hash does not match. + CodeHashMismatch, +} + +impl Into for FakeCandidateValidationError { + fn into(self) -> InvalidCandidate { + match self { + FakeCandidateValidationError::ExecutionError => + InvalidCandidate::ExecutionError("Malus".into()), + FakeCandidateValidationError::InvalidOutputs => InvalidCandidate::InvalidOutputs, + FakeCandidateValidationError::Timeout => InvalidCandidate::Timeout, + FakeCandidateValidationError::ParamsTooLarge => InvalidCandidate::ParamsTooLarge(666), + FakeCandidateValidationError::CodeTooLarge => InvalidCandidate::CodeTooLarge(666), + FakeCandidateValidationError::CodeDecompressionFailure => + InvalidCandidate::CodeDecompressionFailure, + FakeCandidateValidationError::POVDecompressionFailure => + InvalidCandidate::PoVDecompressionFailure, + FakeCandidateValidationError::BadReturn => InvalidCandidate::BadReturn, + FakeCandidateValidationError::BadParent => InvalidCandidate::BadParent, + FakeCandidateValidationError::POVHashMismatch => InvalidCandidate::PoVHashMismatch, + FakeCandidateValidationError::BadSignature => InvalidCandidate::BadSignature, + FakeCandidateValidationError::ParaHeadHashMismatch => + InvalidCandidate::ParaHeadHashMismatch, + FakeCandidateValidationError::CodeHashMismatch => InvalidCandidate::CodeHashMismatch, + } + } +} #[derive(Clone, Debug)] /// An interceptor which fakes validation result with a preconfigured result. /// Replaces `CandidateValidationSubsystem`. -pub struct ReplaceValidationResult { +pub struct ReplaceValidationResult { fake_validation: FakeCandidateValidation, fake_validation_error: FakeCandidateValidationError, + spawner: Spawner, } -impl ReplaceValidationResult { +impl ReplaceValidationResult +where + Spawner: SpawnNamed, +{ pub fn new( fake_validation: FakeCandidateValidation, fake_validation_error: FakeCandidateValidationError, + spawner: Spawner, ) -> Self { - Self { fake_validation, fake_validation_error } + Self { fake_validation, fake_validation_error, spawner } + } + + pub fn send_validation_response( + &self, + candidate_descriptor: CandidateDescriptor, + pov: Arc, + sender: Sender, + response_sender: oneshot::Sender>, + ) where + Sender: overseer::SubsystemSender + + overseer::SubsystemSender + + Clone + + Send + + 'static, + { + let candidate_receipt = create_candidate_receipt(candidate_descriptor.clone()); + let mut subsystem_sender = sender.clone(); + self.spawner.spawn( + "malus-send-fake-validation", + Some("malus"), + Box::pin(async move { + let relay_parent = candidate_descriptor.relay_parent; + let session_index = + util::request_session_index_for_child(relay_parent, &mut subsystem_sender) + .await; + let session_index = session_index.await.unwrap().unwrap(); + + let (a_tx, a_rx) = oneshot::channel(); + + subsystem_sender + .send_message(AllMessages::from( + AvailabilityRecoveryMessage::RecoverAvailableData( + candidate_receipt, + session_index, + None, + a_tx, + ), + )) + .await; + + if let Ok(Ok(availability_data)) = a_rx.await { + create_validation_response( + availability_data.validation_data, + None, + candidate_descriptor, + pov, + response_sender, + ); + } else { + gum::info!(target: MALUS, "Could not get availability data, can't back"); + } + }), + ); } } -impl MessageInterceptor for ReplaceValidationResult +fn create_validation_response( + persisted_validation_data: PersistedValidationData, + validation_code: Option, + _candidate_descriptor: CandidateDescriptor, + _pov: Arc, + response_sender: oneshot::Sender>, +) { + let candidate_commitmentments = CandidateCommitments { + head_data: persisted_validation_data.parent_head.clone(), + new_validation_code: validation_code, + ..Default::default() + }; + + response_sender + .send(Ok(ValidationResult::Valid(candidate_commitmentments, persisted_validation_data))) + .unwrap(); +} + +fn create_candidate_receipt(descriptor: CandidateDescriptor) -> CandidateReceipt { + CandidateReceipt { descriptor, commitments_hash: Hash::zero() } +} + +impl MessageInterceptor for ReplaceValidationResult where - Sender: overseer::SubsystemSender + Clone + Send + 'static, + Sender: overseer::SubsystemSender + + overseer::SubsystemSender + + Clone + + Send + + 'static, + Spawner: SpawnNamed + Clone + 'static, { type Message = CandidateValidationMessage; // Capture all candidate validation requests and depending on configuration fail them. - // MaybeTODO: add option to configure the failure reason. fn intercept_incoming( &self, - _sender: &mut Sender, + subsystem_sender: &mut Sender, msg: FromOverseer, ) -> Option> { if self.fake_validation == FakeCandidateValidation::Disabled { @@ -72,6 +240,17 @@ where ), } => { match self.fake_validation { + FakeCandidateValidation::ApprovalValid | + FakeCandidateValidation::BackingAndApprovalValid => { + create_validation_response( + validation_data, + Some(validation_code), + descriptor, + pov, + sender, + ); + None + }, FakeCandidateValidation::ApprovalInvalid | FakeCandidateValidation::BackingAndApprovalInvalid => { let validation_result = @@ -102,9 +281,24 @@ where }, FromOverseer::Communication { msg: - CandidateValidationMessage::ValidateFromChainState(descriptor, pov, timeout, sender), + CandidateValidationMessage::ValidateFromChainState( + descriptor, + pov, + timeout, + response_sender, + ), } => { match self.fake_validation { + FakeCandidateValidation::BackingValid | + FakeCandidateValidation::BackingAndApprovalValid => { + self.send_validation_response( + descriptor, + pov, + subsystem_sender.clone(), + response_sender, + ); + None + }, FakeCandidateValidation::BackingInvalid | FakeCandidateValidation::BackingAndApprovalInvalid => { let validation_result = @@ -118,12 +312,15 @@ where ); // We're not even checking the candidate, this makes us appear faster than honest validators. - sender.send(Ok(validation_result)).unwrap(); + response_sender.send(Ok(validation_result)).unwrap(); None }, _ => Some(FromOverseer::Communication { msg: CandidateValidationMessage::ValidateFromChainState( - descriptor, pov, timeout, sender, + descriptor, + pov, + timeout, + response_sender, ), }), } diff --git a/node/malus/src/variants/dispute_valid_candidates.rs b/node/malus/src/variants/dispute_valid_candidates.rs index 95a02b7ab2f3..16f776d8d9f2 100644 --- a/node/malus/src/variants/dispute_valid_candidates.rs +++ b/node/malus/src/variants/dispute_valid_candidates.rs @@ -21,7 +21,7 @@ #![allow(missing_docs)] -use clap::{ArgEnum, Parser}; +use clap::{Parser}; use polkadot_cli::{ prepared_overseer_builder, service::{ @@ -34,7 +34,7 @@ use polkadot_cli::{ // Filter wrapping related types. use crate::{interceptor::*, shared::MALUS, variants::ReplaceValidationResult}; -use polkadot_node_primitives::InvalidCandidate; +use super::common::{FakeCandidateValidation, FakeCandidateValidationError}; // Import extra types relevant to the particular // subsystem. @@ -48,72 +48,6 @@ use sp_keystore::SyncCryptoStorePtr; use std::sync::Arc; -#[derive(ArgEnum, Clone, Copy, Debug, PartialEq)] -#[clap(rename_all = "kebab-case")] -pub enum FakeCandidateValidation { - Disabled, - BackingInvalid, - ApprovalInvalid, - BackingAndApprovalInvalid, - // TODO: impl Valid. -} - -/// Candidate invalidity details -#[derive(ArgEnum, Clone, Copy, Debug, PartialEq)] -#[clap(rename_all = "kebab-case")] -pub enum FakeCandidateValidationError { - /// Validation outputs check doesn't pass. - InvalidOutputs, - /// Failed to execute.`validate_block`. This includes function panicking. - ExecutionError, - /// Execution timeout. - Timeout, - /// Validation input is over the limit. - ParamsTooLarge, - /// Code size is over the limit. - CodeTooLarge, - /// Code does not decompress correctly. - CodeDecompressionFailure, - /// PoV does not decompress correctly. - POVDecompressionFailure, - /// Validation function returned invalid data. - BadReturn, - /// Invalid relay chain parent. - BadParent, - /// POV hash does not match. - POVHashMismatch, - /// Bad collator signature. - BadSignature, - /// Para head hash does not match. - ParaHeadHashMismatch, - /// Validation code hash does not match. - CodeHashMismatch, -} - -impl Into for FakeCandidateValidationError { - fn into(self) -> InvalidCandidate { - match self { - FakeCandidateValidationError::ExecutionError => - InvalidCandidate::ExecutionError("Malus".into()), - FakeCandidateValidationError::InvalidOutputs => InvalidCandidate::InvalidOutputs, - FakeCandidateValidationError::Timeout => InvalidCandidate::Timeout, - FakeCandidateValidationError::ParamsTooLarge => InvalidCandidate::ParamsTooLarge(666), - FakeCandidateValidationError::CodeTooLarge => InvalidCandidate::CodeTooLarge(666), - FakeCandidateValidationError::CodeDecompressionFailure => - InvalidCandidate::CodeDecompressionFailure, - FakeCandidateValidationError::POVDecompressionFailure => - InvalidCandidate::PoVDecompressionFailure, - FakeCandidateValidationError::BadReturn => InvalidCandidate::BadReturn, - FakeCandidateValidationError::BadParent => InvalidCandidate::BadParent, - FakeCandidateValidationError::POVHashMismatch => InvalidCandidate::PoVHashMismatch, - FakeCandidateValidationError::BadSignature => InvalidCandidate::BadSignature, - FakeCandidateValidationError::ParaHeadHashMismatch => - InvalidCandidate::ParaHeadHashMismatch, - FakeCandidateValidationError::CodeHashMismatch => InvalidCandidate::CodeHashMismatch, - } - } -} - #[derive(Clone, Debug, Parser)] #[clap(rename_all = "kebab-case")] #[allow(missing_docs)] @@ -209,6 +143,7 @@ impl OverseerGen for DisputeValidCandidates { let validation_filter = ReplaceValidationResult::new( self.opts.fake_validation, self.opts.fake_validation_error, + spawner.clone(), ); let candidate_validation_config = args.candidate_validation_config.clone(); From 8226f4ef8d6f529581f9cfeedb7f7c6f10f72069 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Sat, 26 Mar 2022 15:25:24 +0000 Subject: [PATCH 16/47] fixes Signed-off-by: Andrei Sandu --- .../src/variants/dispute_valid_candidates.rs | 34 +++---------------- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/node/malus/src/variants/dispute_valid_candidates.rs b/node/malus/src/variants/dispute_valid_candidates.rs index 16f776d8d9f2..e1db160b0deb 100644 --- a/node/malus/src/variants/dispute_valid_candidates.rs +++ b/node/malus/src/variants/dispute_valid_candidates.rs @@ -15,7 +15,8 @@ // along with Polkadot. If not, see . //! A malicious node that replaces approvals with invalid disputes -//! against valid candidates. +//! against valid candidates. Additionally, the malus node can be configured to +//! fake candidate validation and return a static result for candidate checking. //! //! Attention: For usage with `zombienet` only! @@ -36,15 +37,10 @@ use polkadot_cli::{ use crate::{interceptor::*, shared::MALUS, variants::ReplaceValidationResult}; use super::common::{FakeCandidateValidation, FakeCandidateValidationError}; -// Import extra types relevant to the particular -// subsystem. -use polkadot_node_core_backing::CandidateBackingSubsystem; -use polkadot_node_core_candidate_validation::CandidateValidationSubsystem; - +// Import extra types relevant to the particular subsystem. use polkadot_node_subsystem::messages::{ ApprovalDistributionMessage, CandidateBackingMessage, DisputeCoordinatorMessage, }; -use sp_keystore::SyncCryptoStorePtr; use std::sync::Arc; @@ -138,36 +134,16 @@ impl OverseerGen for DisputeValidCandidates { Spawner: 'static + SpawnNamed + Clone + Unpin, { let spawner = args.spawner.clone(); - let crypto_store_ptr = args.keystore.clone() as SyncCryptoStorePtr; let backing_filter = ReplaceApprovalsWithDisputes; let validation_filter = ReplaceValidationResult::new( self.opts.fake_validation, self.opts.fake_validation_error, spawner.clone(), ); - let candidate_validation_config = args.candidate_validation_config.clone(); prepared_overseer_builder(args)? - .replace_candidate_backing(move |cb_subsystem| { - InterceptedSubsystem::new( - CandidateBackingSubsystem::new( - spawner, - crypto_store_ptr, - cb_subsystem.params.metrics, - ), - backing_filter, - ) - }) - .replace_candidate_validation(move |cv_subsystem| { - InterceptedSubsystem::new( - CandidateValidationSubsystem::with_config( - candidate_validation_config, - cv_subsystem.metrics, - cv_subsystem.pvf_metrics, - ), - validation_filter, - ) - }) + .replace_candidate_backing(move |cb| InterceptedSubsystem::new(cb, backing_filter)) + .replace_candidate_validation(move |cv_subsystem| InterceptedSubsystem::new(cv_subsystem, validation_filter)) .build_with_connector(connector) .map_err(|e| e.into()) } From 35c8c8e036eeefde7d04817d8369173d069f3f2b Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Sat, 26 Mar 2022 15:26:26 +0000 Subject: [PATCH 17/47] fmt Signed-off-by: Andrei Sandu --- node/malus/src/variants/common.rs | 5 ++--- node/malus/src/variants/dispute_valid_candidates.rs | 8 +++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/node/malus/src/variants/common.rs b/node/malus/src/variants/common.rs index ca1f2c124b0d..87f0d0688238 100644 --- a/node/malus/src/variants/common.rs +++ b/node/malus/src/variants/common.rs @@ -33,10 +33,9 @@ use polkadot_primitives::v2::{ use polkadot_cli::service::SpawnNamed; +use clap::ArgEnum; use futures::channel::oneshot; use std::sync::Arc; -use clap::ArgEnum; - #[derive(ArgEnum, Clone, Copy, Debug, PartialEq)] #[clap(rename_all = "kebab-case")] @@ -146,7 +145,7 @@ where let candidate_receipt = create_candidate_receipt(candidate_descriptor.clone()); let mut subsystem_sender = sender.clone(); self.spawner.spawn( - "malus-send-fake-validation", + "malus-fake-validation", Some("malus"), Box::pin(async move { let relay_parent = candidate_descriptor.relay_parent; diff --git a/node/malus/src/variants/dispute_valid_candidates.rs b/node/malus/src/variants/dispute_valid_candidates.rs index e1db160b0deb..2c4be798c683 100644 --- a/node/malus/src/variants/dispute_valid_candidates.rs +++ b/node/malus/src/variants/dispute_valid_candidates.rs @@ -22,7 +22,7 @@ #![allow(missing_docs)] -use clap::{Parser}; +use clap::Parser; use polkadot_cli::{ prepared_overseer_builder, service::{ @@ -34,8 +34,8 @@ use polkadot_cli::{ }; // Filter wrapping related types. -use crate::{interceptor::*, shared::MALUS, variants::ReplaceValidationResult}; use super::common::{FakeCandidateValidation, FakeCandidateValidationError}; +use crate::{interceptor::*, shared::MALUS, variants::ReplaceValidationResult}; // Import extra types relevant to the particular subsystem. use polkadot_node_subsystem::messages::{ @@ -143,7 +143,9 @@ impl OverseerGen for DisputeValidCandidates { prepared_overseer_builder(args)? .replace_candidate_backing(move |cb| InterceptedSubsystem::new(cb, backing_filter)) - .replace_candidate_validation(move |cv_subsystem| InterceptedSubsystem::new(cv_subsystem, validation_filter)) + .replace_candidate_validation(move |cv_subsystem| { + InterceptedSubsystem::new(cv_subsystem, validation_filter) + }) .build_with_connector(connector) .map_err(|e| e.into()) } From 1c279dc12f7cfcb70f04d146b2d4b0121f7ffc8f Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Mon, 28 Mar 2022 08:58:17 +0000 Subject: [PATCH 18/47] Pull Ladi's implementation: https://github.com/paritytech/polkadot/pull/4711 Co-authored-by: Lldenaurois Co-authored-by: Andrei Sandu Signed-off-by: Andrei Sandu --- .../src/variants/suggest_garbage_candidate.rs | 250 +++++++++++------- 1 file changed, 152 insertions(+), 98 deletions(-) diff --git a/node/malus/src/variants/suggest_garbage_candidate.rs b/node/malus/src/variants/suggest_garbage_candidate.rs index 64e8629edc50..4ca1fc2f0267 100644 --- a/node/malus/src/variants/suggest_garbage_candidate.rs +++ b/node/malus/src/variants/suggest_garbage_candidate.rs @@ -14,11 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! A malicious overseer proposing a garbage block. +//! A malicious node that replaces approvals with invalid disputes +//! against valid candidates. //! -//! Supposed to be used with regular nodes or in conjunction -//! with [`malus-back-garbage-candidate.rs`](./malus-back-garbage-candidate.rs) -//! to simulate a coordinated attack. +//! Attention: For usage with `zombienet` only! #![allow(missing_docs)] @@ -30,40 +29,42 @@ use polkadot_cli::{ ProvideRuntimeApi, SpawnNamed, }, }; +use polkadot_node_primitives::{AvailableData, BlockData, PoV}; +use polkadot_primitives::v2::{CandidateCommitments, CandidateDescriptor, CandidateHash, Hash}; -// Import extra types relevant to the particular -// subsystem. -use polkadot_node_core_backing::CandidateBackingSubsystem; -use polkadot_node_primitives::Statement; -use polkadot_node_subsystem::{ - messages::{CandidateBackingMessage, StatementDistributionMessage}, - overseer::{self, SubsystemSender}, -}; -use polkadot_node_subsystem_util as util; // Filter wrapping related types. use crate::interceptor::*; -use polkadot_primitives::v2::{ - CandidateCommitments, CandidateReceipt, CommittedCandidateReceipt, CompactStatement, Hash, - Signed, -}; -use sp_keystore::SyncCryptoStorePtr; -use util::metered; -use std::sync::Arc; +// Import extra types relevant to the particular +// subsystem. +use polkadot_node_subsystem::messages::{AvailabilityStoreMessage, CandidateBackingMessage}; +use polkadot_primitives::v2::{CandidateReceipt, CommittedCandidateReceipt}; -use crate::shared::*; +use std::sync::{Arc, Mutex}; -/// Replaces the seconded PoV data -/// of outgoing messages by some garbage data. +struct NotedCandidate { + candidate: CandidateReceipt, + relay_parent: Hash, +} + +#[derive(Default)] +struct Inner { + map: std::collections::HashMap, +} + +/// Replace outgoing approval messages with disputes. #[derive(Clone)] -struct ReplacePoVBytes -where - Sender: Send, -{ - queue: metered::UnboundedMeteredSender<(Sender, Hash, CandidateReceipt)>, +struct NoteCandidate { + inner: Arc>, } -impl MessageInterceptor for ReplacePoVBytes +/// Replace outgoing approval messages with disputes. +#[derive(Clone)] +struct BackGarbageCandidate { + inner: Arc>, +} + +impl MessageInterceptor for NoteCandidate where Sender: overseer::SubsystemSender + Clone + Send + 'static, { @@ -71,20 +72,27 @@ where fn intercept_incoming( &self, - sender: &mut Sender, + _sender: &mut Sender, msg: FromOverseer, ) -> Option> { match msg { FromOverseer::Communication { - msg: CandidateBackingMessage::Second(hash, candidate_receipt, _pov), + msg: CandidateBackingMessage::Second(relay_parent, candidate, pov), } => { - self.queue - .unbounded_send((sender.clone(), hash, candidate_receipt.clone())) - .unwrap(); - - None + let mut candidate_cache = self.inner.lock().unwrap(); + candidate_cache.map.insert( + candidate.hash(), + NotedCandidate { + candidate: candidate.clone(), + relay_parent: relay_parent.clone(), + }, + ); + Some(FromOverseer::Communication { + msg: CandidateBackingMessage::Second(relay_parent, candidate, pov), + }) }, - other => Some(other), + FromOverseer::Communication { msg } => Some(FromOverseer::Communication { msg }), + FromOverseer::Signal(signal) => Some(FromOverseer::Signal(signal)), } } @@ -93,10 +101,104 @@ where } } -/// Generates an overseer that exposes bad behavior. -pub(crate) struct SuggestGarbageCandidate; +impl MessageInterceptor for BackGarbageCandidate +where + Sender: overseer::SubsystemSender + Clone + Send + 'static, +{ + type Message = AvailabilityStoreMessage; + + fn intercept_incoming( + &self, + _sender: &mut Sender, + msg: FromOverseer, + ) -> Option> { + Some(msg) + } + + fn intercept_outgoing(&self, msg: AllMessages) -> Option { + match msg { + AllMessages::AvailabilityStore(AvailabilityStoreMessage::StoreAvailableData { + candidate_hash, + n_validators, + available_data, + tx, + }) => { + let pov = Arc::new(PoV { block_data: BlockData(vec![0; 256]) }); + let malicious_available_data = AvailableData { + pov: pov.clone(), + validation_data: available_data.validation_data.clone(), + }; + + let pov_hash = pov.hash(); + let validation_data_hash = malicious_available_data.validation_data.hash(); + + let inner = self.inner.lock().unwrap(); + let cache = inner.map.get(&candidate_hash).unwrap(); + let relay_parent = cache.relay_parent.clone(); + let candidate_cache = cache.candidate.clone(); + let validation_code_hash = candidate_cache.descriptor().validation_code_hash; + + let erasure_root = { + let chunks = + erasure::obtain_chunks_v1(n_validators as usize, &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_cache.descriptor().para_id, + &validation_data_hash, + &pov_hash, + &validation_code_hash, + ); + + (collator_pair.public(), collator_pair.sign(&signature_payload)) + }; + let malicious_commitments = CandidateCommitments { + upward_messages: Vec::new(), + horizontal_messages: Vec::new(), + new_validation_code: None, + head_data: vec![1, 2, 3, 4, 5].into(), + processed_downward_messages: 0, + hrmp_watermark: available_data.validation_data.relay_parent_number, + }; + let malicious_candidate = CommittedCandidateReceipt { + descriptor: CandidateDescriptor { + para_id: candidate_cache.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: malicious_commitments.clone(), + }; + let malicious_candidate_hash = malicious_candidate.hash(); + Some(AllMessages::AvailabilityStore(AvailabilityStoreMessage::StoreAvailableData { + candidate_hash: malicious_candidate_hash, + n_validators, + available_data: malicious_available_data, + tx, + })) + }, + msg => Some(msg), + } + } +} + +/// Generates an overseer that disputes instead of approving valid candidates. +pub(crate) struct BackGarbageCandidateWrapper; -impl OverseerGen for SuggestGarbageCandidate { +impl OverseerGen for BackGarbageCandidateWrapper { fn generate<'a, Spawner, RuntimeClient>( &self, connector: OverseerConnector, @@ -107,65 +209,17 @@ impl OverseerGen for SuggestGarbageCandidate { RuntimeClient::Api: ParachainHost + BabeApi + AuthorityDiscoveryApi, Spawner: 'static + SpawnNamed + Clone + Unpin, { - let spawner = args.spawner.clone(); - let (sink, source) = metered::unbounded(); - let keystore = args.keystore.clone() as SyncCryptoStorePtr; - - let filter = ReplacePoVBytes { queue: sink }; - - let keystore2 = keystore.clone(); - let spawner2 = spawner.clone(); - - let result = prepared_overseer_builder(args)? - .replace_candidate_backing(move |cb| { - InterceptedSubsystem::new( - CandidateBackingSubsystem::new(spawner2, keystore2, cb.params.metrics), - filter, - ) + let inner = Inner { map: std::collections::HashMap::new() }; + let inner_mut = Arc::new(Mutex::new(inner)); + let note_candidate = NoteCandidate { inner: inner_mut.clone() }; + let back_garbage_candidate = BackGarbageCandidate { inner: inner_mut.clone() }; + + prepared_overseer_builder(args)? + .replace_candidate_backing(move |cb| InterceptedSubsystem::new(cb, note_candidate)) + .replace_availability_store(move |av| { + InterceptedSubsystem::new(av, back_garbage_candidate) }) .build_with_connector(connector) - .map_err(|e| e.into()); - - launch_processing_task( - &spawner, - source, - move |(mut subsystem_sender, hash, candidate_receipt): (_, Hash, CandidateReceipt)| { - let keystore = keystore.clone(); - async move { - gum::info!( - target: MALUS, - "Replacing seconded candidate pov with something else" - ); - - let committed_candidate_receipt = CommittedCandidateReceipt { - descriptor: candidate_receipt.descriptor.clone(), - commitments: CandidateCommitments::default(), - }; - - let statement = Statement::Seconded(committed_candidate_receipt); - - if let Ok(validator) = - util::Validator::new(hash, keystore.clone(), &mut subsystem_sender).await - { - let signed_statement: Signed = validator - .sign(keystore, statement) - .await - .expect("Signing works. qed") - .expect("Something must come out of this. qed"); - - subsystem_sender - .send_message(StatementDistributionMessage::Share( - hash, - signed_statement, - )) - .await; - } else { - gum::info!("We are not a validator. Not siging anything."); - } - } - }, - ); - - result + .map_err(|e| e.into()) } } From 8932494d1d809df97123a8b11492e962f02eda7a Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Mon, 28 Mar 2022 09:00:07 +0000 Subject: [PATCH 19/47] Fix build Signed-off-by: Andrei Sandu --- Cargo.lock | 1 + node/malus/Cargo.toml | 2 ++ node/malus/src/malus.rs | 2 +- node/malus/src/variants/mod.rs | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 12f3ba7a24d9..5f0cae2bdc91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7659,6 +7659,7 @@ dependencies = [ "futures-timer", "parity-util-mem", "polkadot-cli", + "polkadot-erasure-coding", "polkadot-node-core-backing", "polkadot-node-core-candidate-validation", "polkadot-node-core-dispute-coordinator", diff --git a/node/malus/Cargo.toml b/node/malus/Cargo.toml index 042573b6f0e4..15762e06dae1 100644 --- a/node/malus/Cargo.toml +++ b/node/malus/Cargo.toml @@ -28,10 +28,12 @@ color-eyre = { version = "0.6.1", default-features = false } assert_matches = "1.5" async-trait = "0.1.52" 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"] } futures = "0.3.21" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../gum/" } +erasure = { package = "polkadot-erasure-coding", path = "../../erasure-coding" } [features] default = [] diff --git a/node/malus/src/malus.rs b/node/malus/src/malus.rs index de051dec841a..38a5f0afbef8 100644 --- a/node/malus/src/malus.rs +++ b/node/malus/src/malus.rs @@ -66,7 +66,7 @@ impl MalusCli { NemesisVariant::BackGarbageCandidate(cmd) => polkadot_cli::run_node(run_cmd(cmd), BackGarbageCandidate)?, NemesisVariant::SuggestGarbageCandidate(cmd) => - polkadot_cli::run_node(run_cmd(cmd), SuggestGarbageCandidate)?, + polkadot_cli::run_node(run_cmd(cmd), BackGarbageCandidateWrapper)?, NemesisVariant::DisputeAncestor(opts) => polkadot_cli::run_node( run_cmd(opts.clone().cmd), DisputeValidCandidates::new(opts), diff --git a/node/malus/src/variants/mod.rs b/node/malus/src/variants/mod.rs index fa014afaa050..1b03ad395347 100644 --- a/node/malus/src/variants/mod.rs +++ b/node/malus/src/variants/mod.rs @@ -24,6 +24,6 @@ mod suggest_garbage_candidate; pub(crate) use self::{ back_garbage_candidate::BackGarbageCandidate, dispute_valid_candidates::{DisputeAncestorOptions, DisputeValidCandidates}, - suggest_garbage_candidate::SuggestGarbageCandidate, + suggest_garbage_candidate::BackGarbageCandidateWrapper, }; pub(crate) use common::ReplaceValidationResult; From fb75de4b8e444efe05ab84ccbc7119b2be803e3e Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Mon, 28 Mar 2022 12:55:38 +0000 Subject: [PATCH 20/47] Logs and comments Signed-off-by: Andrei Sandu --- .../src/variants/suggest_garbage_candidate.rs | 55 ++++++++----------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/node/malus/src/variants/suggest_garbage_candidate.rs b/node/malus/src/variants/suggest_garbage_candidate.rs index 4ca1fc2f0267..4d83d83e786a 100644 --- a/node/malus/src/variants/suggest_garbage_candidate.rs +++ b/node/malus/src/variants/suggest_garbage_candidate.rs @@ -33,7 +33,7 @@ use polkadot_node_primitives::{AvailableData, BlockData, PoV}; use polkadot_primitives::v2::{CandidateCommitments, CandidateDescriptor, CandidateHash, Hash}; // Filter wrapping related types. -use crate::interceptor::*; +use crate::{interceptor::*, shared::{MALUS ,MALICIOUS_POV}}; // Import extra types relevant to the particular // subsystem. @@ -58,11 +58,6 @@ struct NoteCandidate { inner: Arc>, } -/// Replace outgoing approval messages with disputes. -#[derive(Clone)] -struct BackGarbageCandidate { - inner: Arc>, -} impl MessageInterceptor for NoteCandidate where @@ -70,6 +65,7 @@ where { type Message = CandidateBackingMessage; + /// Cache and forward `CandidateBackingMessage::Second`. This is called by collator protocol (validator side). fn intercept_incoming( &self, _sender: &mut Sender, @@ -87,6 +83,11 @@ where relay_parent: relay_parent.clone(), }, ); + gum::info!( + target: MALUS, + candidate_hash = ?candidate.hash(), + "Cached candidate" + ); Some(FromOverseer::Communication { msg: CandidateBackingMessage::Second(relay_parent, candidate, pov), }) @@ -96,25 +97,13 @@ where } } - fn intercept_outgoing(&self, msg: AllMessages) -> Option { - Some(msg) - } -} - -impl MessageInterceptor for BackGarbageCandidate -where - Sender: overseer::SubsystemSender + Clone + Send + 'static, -{ - type Message = AvailabilityStoreMessage; - - fn intercept_incoming( - &self, - _sender: &mut Sender, - msg: FromOverseer, - ) -> Option> { - Some(msg) - } - + /// The goal of this is to make the malicious candidate available to other honest validators. The backing + /// subsystem sends `AvailabilityStore::StoreAvailableData` via `make_pov_available()` once a candidate is + /// backed. + /// This implementation intercepts the outgoing `AvailabilityStore::StoreAvailableData` message and mangles + /// it before forwarding it to the overseer(then `av-store`). More specifically, it replaces the candidate + /// (pov, persistent validation data and collator signagure) while computing the correct erasure root hash + /// from original candidate. fn intercept_outgoing(&self, msg: AllMessages) -> Option { match msg { AllMessages::AvailabilityStore(AvailabilityStoreMessage::StoreAvailableData { @@ -123,7 +112,7 @@ where available_data, tx, }) => { - let pov = Arc::new(PoV { block_data: BlockData(vec![0; 256]) }); + let pov = Arc::new(PoV { block_data: BlockData(MALICIOUS_POV.into()) }); let malicious_available_data = AvailableData { pov: pov.clone(), validation_data: available_data.validation_data.clone(), @@ -183,6 +172,14 @@ where commitments: malicious_commitments.clone(), }; let malicious_candidate_hash = malicious_candidate.hash(); + + gum::info!( + target: MALUS, + ?candidate_hash, + new_candidate_hash = ?malicious_candidate_hash, + "Replacing candidate" + ); + Some(AllMessages::AvailabilityStore(AvailabilityStoreMessage::StoreAvailableData { candidate_hash: malicious_candidate_hash, n_validators, @@ -195,7 +192,7 @@ where } } -/// Generates an overseer that disputes instead of approving valid candidates. +/// Garbage candidate implementation wrapper which implements `OverseerGen` glue. pub(crate) struct BackGarbageCandidateWrapper; impl OverseerGen for BackGarbageCandidateWrapper { @@ -212,13 +209,9 @@ impl OverseerGen for BackGarbageCandidateWrapper { let inner = Inner { map: std::collections::HashMap::new() }; let inner_mut = Arc::new(Mutex::new(inner)); let note_candidate = NoteCandidate { inner: inner_mut.clone() }; - let back_garbage_candidate = BackGarbageCandidate { inner: inner_mut.clone() }; prepared_overseer_builder(args)? .replace_candidate_backing(move |cb| InterceptedSubsystem::new(cb, note_candidate)) - .replace_availability_store(move |av| { - InterceptedSubsystem::new(av, back_garbage_candidate) - }) .build_with_connector(connector) .map_err(|e| e.into()) } From 9408f45acc5a62e5b254e026d3660166e68357e8 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Mon, 28 Mar 2022 16:09:42 +0000 Subject: [PATCH 21/47] WIP: suggest garbage candidate + implement validation result caching Signed-off-by: Andrei Sandu --- node/malus/src/variants/common.rs | 55 +++++++++++++++++-- .../src/variants/suggest_garbage_candidate.rs | 43 ++++++++------- 2 files changed, 74 insertions(+), 24 deletions(-) diff --git a/node/malus/src/variants/common.rs b/node/malus/src/variants/common.rs index 87f0d0688238..2d79ea6a30db 100644 --- a/node/malus/src/variants/common.rs +++ b/node/malus/src/variants/common.rs @@ -19,7 +19,12 @@ #![allow(missing_docs)] -use crate::{interceptor::*, shared::MALUS}; +use crate::{ + interceptor::*, + shared::{MALICIOUS_POV, MALUS}, +}; +use std::collections::HashMap; + use polkadot_node_primitives::{InvalidCandidate, PoV, ValidationResult}; use polkadot_node_subsystem::messages::{ AvailabilityRecoveryMessage, CandidateValidationMessage, ValidationFailed, @@ -27,8 +32,8 @@ use polkadot_node_subsystem::messages::{ use polkadot_node_subsystem_util as util; use polkadot_primitives::v2::{ - CandidateCommitments, CandidateDescriptor, CandidateReceipt, Hash, PersistedValidationData, - ValidationCode, + CandidateCommitments, CandidateDescriptor, CandidateHash, CandidateReceipt, Hash, + PersistedValidationData, ValidationCode, }; use polkadot_cli::service::SpawnNamed; @@ -115,6 +120,7 @@ pub struct ReplaceValidationResult { fake_validation: FakeCandidateValidation, fake_validation_error: FakeCandidateValidationError, spawner: Spawner, + candidate_commitments: HashMap, } impl ReplaceValidationResult @@ -126,7 +132,12 @@ where fake_validation_error: FakeCandidateValidationError, spawner: Spawner, ) -> Self { - Self { fake_validation, fake_validation_error, spawner } + Self { + fake_validation, + fake_validation_error, + spawner, + candidate_commitments: HashMap::new(), + } } pub fn send_validation_response( @@ -223,7 +234,41 @@ where msg: FromOverseer, ) -> Option> { if self.fake_validation == FakeCandidateValidation::Disabled { - return Some(msg) + // Proxy messages and cache validation results. + match msg { + FromOverseer::Communication { + msg: + CandidateValidationMessage::ValidateFromChainState( + descriptor, + pov, + timeout, + response_sender, + ), + } => { + let (tx, rx) = oneshot::channel(); + let mut subsystem_sender = subsystem_sender.clone(); + // this should go to the original candidate validation subsystem. + + gum::info!(target: MALUS, "Proxying validation request",); + + self.spawner.spawn( + "malus-validation-proxy", + Some("malus"), + Box::pin(async move { + subsystem_sender + .send_message(CandidateValidationMessage::ValidateFromChainState( + descriptor, pov, timeout, tx, + )) + .await; + let result = rx.await.unwrap(); + gum::info!(target: MALUS, "Proxied validation result {:?}", &result); + response_sender.send(result); + }), + ); + return None + }, + _ => return Some(msg), + } } match msg { diff --git a/node/malus/src/variants/suggest_garbage_candidate.rs b/node/malus/src/variants/suggest_garbage_candidate.rs index 4d83d83e786a..e4e46b76dd42 100644 --- a/node/malus/src/variants/suggest_garbage_candidate.rs +++ b/node/malus/src/variants/suggest_garbage_candidate.rs @@ -14,8 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! A malicious node that replaces approvals with invalid disputes -//! against valid candidates. +//! A malicious node that stores bogus availability chunks, preventing others from +//! doing approval voting. This should lead to disputes depending if the validator +//! has fetched a malicious chunk. //! //! Attention: For usage with `zombienet` only! @@ -33,7 +34,10 @@ use polkadot_node_primitives::{AvailableData, BlockData, PoV}; use polkadot_primitives::v2::{CandidateCommitments, CandidateDescriptor, CandidateHash, Hash}; // Filter wrapping related types. -use crate::{interceptor::*, shared::{MALUS ,MALICIOUS_POV}}; +use crate::{ + interceptor::*, + shared::{MALICIOUS_POV, MALUS}, +}; // Import extra types relevant to the particular // subsystem. @@ -58,7 +62,6 @@ struct NoteCandidate { inner: Arc>, } - impl MessageInterceptor for NoteCandidate where Sender: overseer::SubsystemSender + Clone + Send + 'static, @@ -87,22 +90,24 @@ where target: MALUS, candidate_hash = ?candidate.hash(), "Cached candidate" - ); - Some(FromOverseer::Communication { + ); + let message = FromOverseer::Communication { msg: CandidateBackingMessage::Second(relay_parent, candidate, pov), - }) + }; + + Some(message) }, FromOverseer::Communication { msg } => Some(FromOverseer::Communication { msg }), FromOverseer::Signal(signal) => Some(FromOverseer::Signal(signal)), } } - /// The goal of this is to make the malicious candidate available to other honest validators. The backing - /// subsystem sends `AvailabilityStore::StoreAvailableData` via `make_pov_available()` once a candidate is + /// The goal of this is to make the malicious candidate available to other honest validators. The backing + /// subsystem sends `AvailabilityStore::StoreAvailableData` via `make_pov_available()` once a candidate is /// backed. - /// This implementation intercepts the outgoing `AvailabilityStore::StoreAvailableData` message and mangles - /// it before forwarding it to the overseer(then `av-store`). More specifically, it replaces the candidate - /// (pov, persistent validation data and collator signagure) while computing the correct erasure root hash + /// This implementation intercepts the outgoing `AvailabilityStore::StoreAvailableData` message and mangles + /// it before forwarding it to the overseer(then `av-store`). More specifically, it replaces the candidate + /// (pov, persistent validation data and collator signagure) while computing the correct erasure root hash /// from original candidate. fn intercept_outgoing(&self, msg: AllMessages) -> Option { match msg { @@ -125,6 +130,7 @@ where let cache = inner.map.get(&candidate_hash).unwrap(); let relay_parent = cache.relay_parent.clone(); let candidate_cache = cache.candidate.clone(); + let candidate_descriptor = candidate_cache.descriptor(); let validation_code_hash = candidate_cache.descriptor().validation_code_hash; let erasure_root = { @@ -134,6 +140,7 @@ where let branches = erasure::branches(chunks.as_ref()); branches.root() }; + let (collator_id, collator_signature) = { use polkadot_primitives::v2::CollatorPair; use sp_core::crypto::Pair; @@ -149,6 +156,7 @@ where (collator_pair.public(), collator_pair.sign(&signature_payload)) }; + // Use fake candidate validation to get commitments. let malicious_commitments = CandidateCommitments { upward_messages: Vec::new(), horizontal_messages: Vec::new(), @@ -173,15 +181,12 @@ where }; let malicious_candidate_hash = malicious_candidate.hash(); - gum::info!( - target: MALUS, - ?candidate_hash, - new_candidate_hash = ?malicious_candidate_hash, - "Replacing candidate" - ); + gum::info!(target: MALUS, ?candidate_hash, "Replacing candidate availability data"); + // We need to use the same candidate hash for storing the availability data, such that + // other's can fetch it. Some(AllMessages::AvailabilityStore(AvailabilityStoreMessage::StoreAvailableData { - candidate_hash: malicious_candidate_hash, + candidate_hash, n_validators, available_data: malicious_available_data, tx, From 78ed1193bfa0458ab3471d1b0dfe8d5a7653f288 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Mon, 28 Mar 2022 18:06:13 +0000 Subject: [PATCH 22/47] fix Signed-off-by: Andrei Sandu --- node/malus/src/variants/common.rs | 34 +++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/node/malus/src/variants/common.rs b/node/malus/src/variants/common.rs index 2d79ea6a30db..04ef9af57d91 100644 --- a/node/malus/src/variants/common.rs +++ b/node/malus/src/variants/common.rs @@ -40,7 +40,7 @@ use polkadot_cli::service::SpawnNamed; use clap::ArgEnum; use futures::channel::oneshot; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; #[derive(ArgEnum, Clone, Copy, Debug, PartialEq)] #[clap(rename_all = "kebab-case")] @@ -120,7 +120,8 @@ pub struct ReplaceValidationResult { fake_validation: FakeCandidateValidation, fake_validation_error: FakeCandidateValidationError, spawner: Spawner, - candidate_commitments: HashMap, + // We use the para head hash as key. + validation_result: Arc>>, } impl ReplaceValidationResult @@ -136,7 +137,7 @@ where fake_validation, fake_validation_error, spawner, - candidate_commitments: HashMap::new(), + validation_result: Arc::new(Mutex::new(HashMap::new())), } } @@ -245,30 +246,51 @@ where response_sender, ), } => { + + // This is our request, let it pass to original subsystem. + if timeout == std::time::Duration::from_secs(13) { + return Some(FromOverseer::Communication { + msg: CandidateValidationMessage::ValidateFromChainState( + descriptor, + pov, + timeout, + response_sender, + ), + }) + } + let (tx, rx) = oneshot::channel(); let mut subsystem_sender = subsystem_sender.clone(); - // this should go to the original candidate validation subsystem. gum::info!(target: MALUS, "Proxying validation request",); + let validation_result = self.validation_result.clone(); self.spawner.spawn( "malus-validation-proxy", Some("malus"), Box::pin(async move { subsystem_sender .send_message(CandidateValidationMessage::ValidateFromChainState( - descriptor, pov, timeout, tx, + descriptor.clone(), pov, std::time::Duration::from_secs(13), tx, )) .await; let result = rx.await.unwrap(); gum::info!(target: MALUS, "Proxied validation result {:?}", &result); - response_sender.send(result); + match result.unwrap() { + ValidationResult::Valid(commitments, validation_data) => { + validation_result.lock().expect("bad lock").insert(descriptor.para_head, (commitments.clone(), validation_data.clone())); + response_sender.send(Ok(ValidationResult::Valid(commitments, validation_data))); + } + _ => panic!("Bad things can happen.") + } + }), ); return None }, _ => return Some(msg), } + } match msg { From efe4e5074254ae1bad357c902c86c7cf0ddbf424 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Wed, 30 Mar 2022 15:02:07 +0000 Subject: [PATCH 23/47] Do commitment hash checks in candidate validation Signed-off-by: Andrei Sandu --- node/core/candidate-validation/src/lib.rs | 56 ++++++++++++++++++----- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/node/core/candidate-validation/src/lib.rs b/node/core/candidate-validation/src/lib.rs index 8256690bac47..4604f29a59e3 100644 --- a/node/core/candidate-validation/src/lib.rs +++ b/node/core/candidate-validation/src/lib.rs @@ -138,6 +138,7 @@ where pov, timeout, response_sender, + commitments_hash, ) => { let bg = { let mut sender = ctx.sender().clone(); @@ -153,6 +154,7 @@ where pov, timeout, &metrics, + commitments_hash, ) .await; @@ -170,6 +172,7 @@ where pov, timeout, response_sender, + commitments_hash, ) => { let bg = { let metrics = metrics.clone(); @@ -185,6 +188,7 @@ where pov, timeout, &metrics, + commitments_hash, ) .await; @@ -413,6 +417,28 @@ where AssumptionCheckOutcome::DoesNotMatch } +/// Returns validation data for a given candidate. +pub async fn find_validation_data( + sender: &mut Sender, + descriptor: &CandidateDescriptor, +) -> Result, ValidationFailed> +where + Sender: SubsystemSender, +{ + match find_assumed_validation_data(sender, &descriptor).await { + AssumptionCheckOutcome::Matches(validation_data, validation_code) => + Ok(Some((validation_data, validation_code))), + AssumptionCheckOutcome::DoesNotMatch => { + // If neither the assumption of the occupied core having the para included or the assumption + // of the occupied core timing out are valid, then the persisted_validation_data_hash in the descriptor + // is not based on the relay parent and is thus invalid. + Ok(None) + }, + AssumptionCheckOutcome::BadRequest => + Err(ValidationFailed("Assumption Check: Bad request".into())), + } +} + async fn validate_from_chain_state( sender: &mut Sender, validation_host: ValidationHost, @@ -420,22 +446,16 @@ async fn validate_from_chain_state( pov: Arc, timeout: Duration, metrics: &Metrics, + commitments_hash: Hash, ) -> Result where Sender: SubsystemSender, { + let mut new_sender = sender.clone(); let (validation_data, validation_code) = - match find_assumed_validation_data(sender, &descriptor).await { - AssumptionCheckOutcome::Matches(validation_data, validation_code) => - (validation_data, validation_code), - AssumptionCheckOutcome::DoesNotMatch => { - // If neither the assumption of the occupied core having the para included or the assumption - // of the occupied core timing out are valid, then the persisted_validation_data_hash in the descriptor - // is not based on the relay parent and is thus invalid. - return Ok(ValidationResult::Invalid(InvalidCandidate::BadParent)) - }, - AssumptionCheckOutcome::BadRequest => - return Err(ValidationFailed("Assumption Check: Bad request".into())), + match find_validation_data(&mut new_sender, &descriptor).await? { + Some((validation_data, validation_code)) => (validation_data, validation_code), + None => return Ok(ValidationResult::Invalid(InvalidCandidate::BadParent)), }; let validation_result = validate_candidate_exhaustive( @@ -446,10 +466,16 @@ where pov, timeout, metrics, + commitments_hash, ) .await; if let Ok(ValidationResult::Valid(ref outputs, _)) = validation_result { + // If validation produces new commitments we consider the candidate invalid. + if commitments_hash != outputs.hash() { + return Ok(ValidationResult::Invalid(InvalidCandidate::ComittmentsHashMismatch)) + } + let (tx, rx) = oneshot::channel(); match runtime_api_request( sender, @@ -477,6 +503,7 @@ async fn validate_candidate_exhaustive( pov: Arc, timeout: Duration, metrics: &Metrics, + commitments_hash: Hash, ) -> Result { let _timer = metrics.time_validate_candidate_exhaustive(); @@ -566,7 +593,12 @@ async fn validate_candidate_exhaustive( processed_downward_messages: res.processed_downward_messages, hrmp_watermark: res.hrmp_watermark, }; - Ok(ValidationResult::Valid(outputs, persisted_validation_data)) + if commitments_hash != outputs.hash() { + // If validation produced a new set of commitments, we treat the candidate as invalid. + Ok(ValidationResult::Invalid(InvalidCandidate::ComittmentsHashMismatch)) + } else { + Ok(ValidationResult::Valid(outputs, persisted_validation_data)) + } }, } } From 1d02b2a68534c7ebfb0d82b47da44bf4046dd4f5 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Wed, 30 Mar 2022 15:03:07 +0000 Subject: [PATCH 24/47] Minor refactor in approval, backing, dispute-coord Signed-off-by: Andrei Sandu --- node/core/approval-voting/src/lib.rs | 1 + node/core/backing/src/lib.rs | 80 ++++++++++--------- .../src/real/participation/mod.rs | 17 +--- node/primitives/src/lib.rs | 2 + node/subsystem-types/src/messages.rs | 8 +- 5 files changed, 56 insertions(+), 52 deletions(-) diff --git a/node/core/approval-voting/src/lib.rs b/node/core/approval-voting/src/lib.rs index 6037abd2a66a..577befc6cae7 100644 --- a/node/core/approval-voting/src/lib.rs +++ b/node/core/approval-voting/src/lib.rs @@ -2277,6 +2277,7 @@ async fn launch_approval( available_data.pov, APPROVAL_EXECUTION_TIMEOUT, val_tx, + candidate.commitments_hash, ) .into(), ) diff --git a/node/core/backing/src/lib.rs b/node/core/backing/src/lib.rs index 2f85b5ed43aa..56655bfe0795 100644 --- a/node/core/backing/src/lib.rs +++ b/node/core/backing/src/lib.rs @@ -31,8 +31,8 @@ use futures::{ }; use polkadot_node_primitives::{ - AvailableData, PoV, SignedDisputeStatement, SignedFullStatement, Statement, ValidationResult, - BACKING_EXECUTION_TIMEOUT, + AvailableData, InvalidCandidate, PoV, SignedDisputeStatement, SignedFullStatement, Statement, + ValidationResult, BACKING_EXECUTION_TIMEOUT, }; use polkadot_node_subsystem_util::{ self as util, @@ -380,6 +380,7 @@ async fn request_candidate_validation( sender: &mut JobSender, candidate: CandidateDescriptor, pov: Arc, + commitments_hash: Hash, ) -> Result { let (tx, rx) = oneshot::channel(); @@ -389,6 +390,7 @@ async fn request_candidate_validation( pov, BACKING_EXECUTION_TIMEOUT, tx, + commitments_hash, )) .await; @@ -450,17 +452,23 @@ async fn validate_and_make_available( }, }; + let expected_commitments_hash = candidate.commitments_hash; + let v = { let _span = span.as_ref().map(|s| { s.child("request-validation") .with_pov(&pov) .with_para_id(candidate.descriptor().para_id) }); - request_candidate_validation(&mut sender, candidate.descriptor.clone(), pov.clone()).await? + request_candidate_validation( + &mut sender, + candidate.descriptor.clone(), + pov.clone(), + expected_commitments_hash, + ) + .await? }; - let expected_commitments_hash = candidate.commitments_hash; - let res = match v { ValidationResult::Valid(commitments, validation_data) => { gum::debug!( @@ -469,41 +477,39 @@ async fn validate_and_make_available( "Validation successful", ); - // If validation produces a new set of commitments, we vote the candidate as invalid. - if commitments.hash() != expected_commitments_hash { - gum::debug!( - target: LOG_TARGET, - candidate_hash = ?candidate.hash(), - actual_commitments = ?commitments, - "Commitments obtained with validation don't match the announced by the candidate receipt", - ); - Err(candidate) - } else { - let erasure_valid = make_pov_available( - &mut sender, - n_validators, - pov.clone(), - candidate.hash(), - validation_data, - candidate.descriptor.erasure_root, - span.as_ref(), - ) - .await?; + let erasure_valid = make_pov_available( + &mut sender, + n_validators, + pov.clone(), + candidate.hash(), + validation_data, + candidate.descriptor.erasure_root, + span.as_ref(), + ) + .await?; - match erasure_valid { - Ok(()) => Ok((candidate, commitments, pov.clone())), - Err(InvalidErasureRoot) => { - gum::debug!( - target: LOG_TARGET, - candidate_hash = ?candidate.hash(), - actual_commitments = ?commitments, - "Erasure root doesn't match the announced by the candidate receipt", - ); - Err(candidate) - }, - } + match erasure_valid { + Ok(()) => Ok((candidate, commitments, pov.clone())), + Err(InvalidErasureRoot) => { + gum::debug!( + target: LOG_TARGET, + candidate_hash = ?candidate.hash(), + actual_commitments = ?commitments, + "Erasure root doesn't match the announced by the candidate receipt", + ); + Err(candidate) + }, } }, + ValidationResult::Invalid(InvalidCandidate::ComittmentsHashMismatch) => { + // If validation produces a new set of commitments, we vote the candidate as invalid. + gum::warn!( + target: LOG_TARGET, + candidate_hash = ?candidate.hash(), + "Validation yielded different commitments", + ); + Err(candidate) + }, ValidationResult::Invalid(reason) => { gum::debug!( target: LOG_TARGET, diff --git a/node/core/dispute-coordinator/src/real/participation/mod.rs b/node/core/dispute-coordinator/src/real/participation/mod.rs index 4ed4015cd6db..fd1ccf06ed19 100644 --- a/node/core/dispute-coordinator/src/real/participation/mod.rs +++ b/node/core/dispute-coordinator/src/real/participation/mod.rs @@ -366,6 +366,7 @@ async fn participate( available_data.pov, APPROVAL_EXECUTION_TIMEOUT, validation_tx, + req.candidate_receipt().commitments_hash, ) .into(), ) @@ -393,6 +394,7 @@ async fn participate( send_result(&mut result_sender, req, ParticipationOutcome::Invalid).await; }, + Ok(Ok(ValidationResult::Invalid(invalid))) => { gum::warn!( target: LOG_TARGET, @@ -403,19 +405,8 @@ async fn participate( send_result(&mut result_sender, req, ParticipationOutcome::Invalid).await; }, - Ok(Ok(ValidationResult::Valid(commitments, _))) => { - if commitments.hash() != req.candidate_receipt().commitments_hash { - gum::warn!( - target: LOG_TARGET, - expected = ?req.candidate_receipt().commitments_hash, - got = ?commitments.hash(), - "Candidate is valid but commitments hash doesn't match", - ); - - send_result(&mut result_sender, req, ParticipationOutcome::Invalid).await; - } else { - send_result(&mut result_sender, req, ParticipationOutcome::Valid).await; - } + Ok(Ok(ValidationResult::Valid(_, _))) => { + send_result(&mut result_sender, req, ParticipationOutcome::Valid).await; }, } } diff --git a/node/primitives/src/lib.rs b/node/primitives/src/lib.rs index 2d09d9c96357..2d2b4ea4f3cd 100644 --- a/node/primitives/src/lib.rs +++ b/node/primitives/src/lib.rs @@ -231,6 +231,8 @@ pub enum InvalidCandidate { ParaHeadHashMismatch, /// Validation code hash does not match. CodeHashMismatch, + /// Validation has generated different candidate commitments. + ComittmentsHashMismatch, } /// Result of the validation of the candidate. diff --git a/node/subsystem-types/src/messages.rs b/node/subsystem-types/src/messages.rs index 8657ec16283b..f801daba791e 100644 --- a/node/subsystem-types/src/messages.rs +++ b/node/subsystem-types/src/messages.rs @@ -138,6 +138,8 @@ pub enum CandidateValidationMessage { /// Execution timeout Duration, oneshot::Sender>, + /// Original commitments hash + Hash, ), /// Validate a candidate with provided, exhaustive parameters for validation. /// @@ -156,6 +158,8 @@ pub enum CandidateValidationMessage { /// Execution timeout Duration, oneshot::Sender>, + /// Comittments hash + Hash, ), /// Try to compile the given validation code and send back /// the outcome. @@ -174,8 +178,8 @@ impl CandidateValidationMessage { /// If the current variant contains the relay parent hash, return it. pub fn relay_parent(&self) -> Option { match self { - Self::ValidateFromChainState(_, _, _, _) => None, - Self::ValidateFromExhaustive(_, _, _, _, _, _) => None, + Self::ValidateFromChainState(_, _, _, _, _) => None, + Self::ValidateFromExhaustive(_, _, _, _, _, _, _) => None, Self::PreCheck(relay_parent, _, _) => Some(*relay_parent), } } From 4719ad3d53c8511eccc673d5255cc8ae3910e589 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Wed, 30 Mar 2022 15:03:45 +0000 Subject: [PATCH 25/47] Working version of suggest garbage candidate Signed-off-by: Andrei Sandu --- .../src/variants/back_garbage_candidate.rs | 2 + node/malus/src/variants/common.rs | 154 ++++++++----- node/malus/src/variants/mod.rs | 2 +- .../src/variants/suggest_garbage_candidate.rs | 217 +++++++++++------- 4 files changed, 234 insertions(+), 141 deletions(-) diff --git a/node/malus/src/variants/back_garbage_candidate.rs b/node/malus/src/variants/back_garbage_candidate.rs index 5cca3144a8a1..0b57cd827cef 100644 --- a/node/malus/src/variants/back_garbage_candidate.rs +++ b/node/malus/src/variants/back_garbage_candidate.rs @@ -111,6 +111,7 @@ where pov, _duration, response_sender, + candidate_commitments, ), } if pov.block_data.0.as_slice() == MALICIOUS_POV => { Self::let_pass( @@ -129,6 +130,7 @@ where pov, _duration, response_sender, + commitments_hash, ), } if pov.block_data.0.as_slice() == MALICIOUS_POV => { if let Some(candidate_receipt) = diff --git a/node/malus/src/variants/common.rs b/node/malus/src/variants/common.rs index 04ef9af57d91..b11e68714d78 100644 --- a/node/malus/src/variants/common.rs +++ b/node/malus/src/variants/common.rs @@ -25,15 +25,13 @@ use crate::{ }; use std::collections::HashMap; +use polkadot_node_core_candidate_validation::find_validation_data; use polkadot_node_primitives::{InvalidCandidate, PoV, ValidationResult}; -use polkadot_node_subsystem::messages::{ - AvailabilityRecoveryMessage, CandidateValidationMessage, ValidationFailed, -}; -use polkadot_node_subsystem_util as util; +use polkadot_node_subsystem::messages::{CandidateValidationMessage, ValidationFailed}; use polkadot_primitives::v2::{ - CandidateCommitments, CandidateDescriptor, CandidateHash, CandidateReceipt, Hash, - PersistedValidationData, ValidationCode, + BlockNumber, CandidateCommitments, CandidateDescriptor, Hash, PersistedValidationData, + ValidationCode, }; use polkadot_cli::service::SpawnNamed; @@ -141,11 +139,13 @@ where } } + /// Creates and sends the validation response for a given candidate. Queries the runtime to obtain the validation data for the + /// given candidate. pub fn send_validation_response( &self, candidate_descriptor: CandidateDescriptor, pov: Arc, - sender: Sender, + subsystem_sender: Sender, response_sender: oneshot::Sender>, ) where Sender: overseer::SubsystemSender @@ -154,47 +154,48 @@ where + Send + 'static, { - let candidate_receipt = create_candidate_receipt(candidate_descriptor.clone()); - let mut subsystem_sender = sender.clone(); - self.spawner.spawn( - "malus-fake-validation", + let _candidate_descriptor = candidate_descriptor.clone(); + let mut subsystem_sender = subsystem_sender.clone(); + let (sender, receiver) = std::sync::mpsc::channel(); + self.spawner.spawn_blocking( + "malus-get-validation-data", Some("malus"), Box::pin(async move { - let relay_parent = candidate_descriptor.relay_parent; - let session_index = - util::request_session_index_for_child(relay_parent, &mut subsystem_sender) - .await; - let session_index = session_index.await.unwrap().unwrap(); - - let (a_tx, a_rx) = oneshot::channel(); - - subsystem_sender - .send_message(AllMessages::from( - AvailabilityRecoveryMessage::RecoverAvailableData( - candidate_receipt, - session_index, - None, - a_tx, - ), - )) - .await; - - if let Ok(Ok(availability_data)) = a_rx.await { - create_validation_response( - availability_data.validation_data, - None, - candidate_descriptor, - pov, - response_sender, - ); - } else { - gum::info!(target: MALUS, "Could not get availability data, can't back"); + match find_validation_data(&mut subsystem_sender, &_candidate_descriptor).await { + Ok(Some((validation_data, validation_code))) => { + sender.send((validation_data, validation_code)); + }, + _ => { + panic!("Unable to fetch validation data"); + }, } }), ); + let (validation_data, validation_code) = receiver.recv().unwrap(); + create_validation_response( + validation_data, + Some(validation_code), + candidate_descriptor, + pov, + response_sender, + ); + } +} + +pub fn create_fake_candidate_commitments( + persisted_validation_data: &PersistedValidationData, +) -> CandidateCommitments { + CandidateCommitments { + upward_messages: Vec::new(), + horizontal_messages: Vec::new(), + new_validation_code: None, + head_data: persisted_validation_data.parent_head.clone(), + processed_downward_messages: 0, + hrmp_watermark: persisted_validation_data.relay_parent_number, } } +// Create and send validation response. This function needs the persistent validation data. fn create_validation_response( persisted_validation_data: PersistedValidationData, validation_code: Option, @@ -202,21 +203,15 @@ fn create_validation_response( _pov: Arc, response_sender: oneshot::Sender>, ) { - let candidate_commitmentments = CandidateCommitments { - head_data: persisted_validation_data.parent_head.clone(), - new_validation_code: validation_code, - ..Default::default() - }; - response_sender - .send(Ok(ValidationResult::Valid(candidate_commitmentments, persisted_validation_data))) + .send(Ok(ValidationResult::Valid( + create_fake_candidate_commitments(&persisted_validation_data), + persisted_validation_data, + ))) .unwrap(); } -fn create_candidate_receipt(descriptor: CandidateDescriptor) -> CandidateReceipt { - CandidateReceipt { descriptor, commitments_hash: Hash::zero() } -} - +// TODO: Only fake validation for `MALICIOUS_POV`, otherwise behave normally. impl MessageInterceptor for ReplaceValidationResult where Sender: overseer::SubsystemSender @@ -244,9 +239,9 @@ where pov, timeout, response_sender, + commitments_hash, ), } => { - // This is our request, let it pass to original subsystem. if timeout == std::time::Duration::from_secs(13) { return Some(FromOverseer::Communication { @@ -255,6 +250,7 @@ where pov, timeout, response_sender, + commitments_hash, ), }) } @@ -271,26 +267,34 @@ where Box::pin(async move { subsystem_sender .send_message(CandidateValidationMessage::ValidateFromChainState( - descriptor.clone(), pov, std::time::Duration::from_secs(13), tx, + descriptor.clone(), + pov, + std::time::Duration::from_secs(13), + tx, + commitments_hash, )) .await; let result = rx.await.unwrap(); gum::info!(target: MALUS, "Proxied validation result {:?}", &result); match result.unwrap() { ValidationResult::Valid(commitments, validation_data) => { - validation_result.lock().expect("bad lock").insert(descriptor.para_head, (commitments.clone(), validation_data.clone())); - response_sender.send(Ok(ValidationResult::Valid(commitments, validation_data))); - } - _ => panic!("Bad things can happen.") + validation_result.lock().expect("bad lock").insert( + descriptor.para_head, + (commitments.clone(), validation_data.clone()), + ); + response_sender.send(Ok(ValidationResult::Valid( + commitments, + validation_data, + ))); + }, + _ => panic!("Bad things can happen."), } - }), ); return None }, _ => return Some(msg), } - } match msg { @@ -303,8 +307,24 @@ where pov, timeout, sender, + commitments_hash, ), } => { + // Behave normally if the `PoV` is not known to be malicious. + if pov.block_data.0.as_slice() != MALICIOUS_POV { + return Some(FromOverseer::Communication { + msg: CandidateValidationMessage::ValidateFromExhaustive( + validation_data, + validation_code, + descriptor, + pov, + timeout, + sender, + commitments_hash, + ), + }) + } + match self.fake_validation { FakeCandidateValidation::ApprovalValid | FakeCandidateValidation::BackingAndApprovalValid => { @@ -341,6 +361,7 @@ where pov, timeout, sender, + commitments_hash, ), }), } @@ -352,8 +373,22 @@ where pov, timeout, response_sender, + commitments_hash, ), } => { + // Behave normally if the `PoV` is not known to be malicious. + if pov.block_data.0.as_slice() != MALICIOUS_POV { + return Some(FromOverseer::Communication { + msg: CandidateValidationMessage::ValidateFromChainState( + descriptor, + pov, + timeout, + response_sender, + commitments_hash, + ), + }) + } + match self.fake_validation { FakeCandidateValidation::BackingValid | FakeCandidateValidation::BackingAndApprovalValid => { @@ -387,6 +422,7 @@ where pov, timeout, response_sender, + commitments_hash, ), }), } diff --git a/node/malus/src/variants/mod.rs b/node/malus/src/variants/mod.rs index 1b03ad395347..d57580fdf8d3 100644 --- a/node/malus/src/variants/mod.rs +++ b/node/malus/src/variants/mod.rs @@ -26,4 +26,4 @@ pub(crate) use self::{ dispute_valid_candidates::{DisputeAncestorOptions, DisputeValidCandidates}, suggest_garbage_candidate::BackGarbageCandidateWrapper, }; -pub(crate) use common::ReplaceValidationResult; +pub(crate) use common::*; diff --git a/node/malus/src/variants/suggest_garbage_candidate.rs b/node/malus/src/variants/suggest_garbage_candidate.rs index e4e46b76dd42..5f2f5191b8ec 100644 --- a/node/malus/src/variants/suggest_garbage_candidate.rs +++ b/node/malus/src/variants/suggest_garbage_candidate.rs @@ -30,112 +30,124 @@ use polkadot_cli::{ ProvideRuntimeApi, SpawnNamed, }, }; +use polkadot_node_core_candidate_validation::find_validation_data; use polkadot_node_primitives::{AvailableData, BlockData, PoV}; -use polkadot_primitives::v2::{CandidateCommitments, CandidateDescriptor, CandidateHash, Hash}; +use polkadot_primitives::v2::{CandidateCommitments, CandidateDescriptor, CandidateHash}; + +use polkadot_node_subsystem_util::request_validators; // Filter wrapping related types. use crate::{ interceptor::*, shared::{MALICIOUS_POV, MALUS}, + variants::{FakeCandidateValidation, FakeCandidateValidationError, ReplaceValidationResult}, }; // Import extra types relevant to the particular // subsystem. -use polkadot_node_subsystem::messages::{AvailabilityStoreMessage, CandidateBackingMessage}; -use polkadot_primitives::v2::{CandidateReceipt, CommittedCandidateReceipt}; - -use std::sync::{Arc, Mutex}; +use polkadot_node_subsystem::messages::{CandidateBackingMessage, CollatorProtocolMessage}; +use polkadot_primitives::v2::CandidateReceipt; -struct NotedCandidate { - candidate: CandidateReceipt, - relay_parent: Hash, -} +use std::{ + collections::HashMap, + sync::{Arc, Mutex}, +}; -#[derive(Default)] struct Inner { - map: std::collections::HashMap, + /// Maps malicious candidate hash to original candidate hash. + /// It is used to replace outgoing collator protocol seconded messages. + map: HashMap, } /// Replace outgoing approval messages with disputes. #[derive(Clone)] -struct NoteCandidate { +struct NoteCandidate { inner: Arc>, + spawner: Spawner, } -impl MessageInterceptor for NoteCandidate +impl MessageInterceptor for NoteCandidate where - Sender: overseer::SubsystemSender + Clone + Send + 'static, + Sender: overseer::SubsystemSender + + overseer::SubsystemSender + + Clone + + Send + + 'static, + Spawner: SpawnNamed + Clone + 'static, { type Message = CandidateBackingMessage; /// Cache and forward `CandidateBackingMessage::Second`. This is called by collator protocol (validator side). fn intercept_incoming( &self, - _sender: &mut Sender, + subsystem_sender: &mut Sender, msg: FromOverseer, ) -> Option> { match msg { FromOverseer::Communication { - msg: CandidateBackingMessage::Second(relay_parent, candidate, pov), + msg: CandidateBackingMessage::Second(relay_parent, candidate, _pov), } => { - let mut candidate_cache = self.inner.lock().unwrap(); - candidate_cache.map.insert( - candidate.hash(), - NotedCandidate { - candidate: candidate.clone(), - relay_parent: relay_parent.clone(), - }, - ); gum::info!( target: MALUS, candidate_hash = ?candidate.hash(), - "Cached candidate" + ?relay_parent, + "Received request to second candidate" ); - let message = FromOverseer::Communication { - msg: CandidateBackingMessage::Second(relay_parent, candidate, pov), - }; - Some(message) - }, - FromOverseer::Communication { msg } => Some(FromOverseer::Communication { msg }), - FromOverseer::Signal(signal) => Some(FromOverseer::Signal(signal)), - } - } + let pov = PoV { block_data: BlockData(MALICIOUS_POV.into()) }; - /// The goal of this is to make the malicious candidate available to other honest validators. The backing - /// subsystem sends `AvailabilityStore::StoreAvailableData` via `make_pov_available()` once a candidate is - /// backed. - /// This implementation intercepts the outgoing `AvailabilityStore::StoreAvailableData` message and mangles - /// it before forwarding it to the overseer(then `av-store`). More specifically, it replaces the candidate - /// (pov, persistent validation data and collator signagure) while computing the correct erasure root hash - /// from original candidate. - fn intercept_outgoing(&self, msg: AllMessages) -> Option { - match msg { - AllMessages::AvailabilityStore(AvailabilityStoreMessage::StoreAvailableData { - candidate_hash, - n_validators, - available_data, - tx, - }) => { - let pov = Arc::new(PoV { block_data: BlockData(MALICIOUS_POV.into()) }); - let malicious_available_data = AvailableData { - pov: pov.clone(), - validation_data: available_data.validation_data.clone(), - }; + 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::info!(target: MALUS, "Requesting validators"); + let n_validators = request_validators(relay_parent, &mut new_sender) + .await + .await + .unwrap() + .unwrap() + .len(); + gum::info!(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)); + }, + _ => { + panic!("Unable to fetch validation data"); + }, + } + }), + ); - let pov_hash = pov.hash(); - let validation_data_hash = malicious_available_data.validation_data.hash(); + let (validation_data, validation_code, n_validators) = receiver.recv().unwrap(); + + 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; + + gum::info!( + 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 inner = self.inner.lock().unwrap(); - let cache = inner.map.get(&candidate_hash).unwrap(); - let relay_parent = cache.relay_parent.clone(); - let candidate_cache = cache.candidate.clone(); - let candidate_descriptor = candidate_cache.descriptor(); - let validation_code_hash = candidate_cache.descriptor().validation_code_hash; + 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, &available_data).unwrap(); + erasure::obtain_chunks_v1(n_validators as usize, &malicious_available_data) + .unwrap(); let branches = erasure::branches(chunks.as_ref()); branches.root() @@ -148,7 +160,7 @@ where let collator_pair = CollatorPair::generate().0; let signature_payload = polkadot_primitives::v2::collator_signature_payload( &relay_parent, - &candidate_cache.descriptor().para_id, + &candidate.descriptor().para_id, &validation_data_hash, &pov_hash, &validation_code_hash, @@ -156,18 +168,19 @@ where (collator_pair.public(), collator_pair.sign(&signature_payload)) }; - // Use fake candidate validation to get commitments. + let malicious_commitments = CandidateCommitments { upward_messages: Vec::new(), horizontal_messages: Vec::new(), new_validation_code: None, - head_data: vec![1, 2, 3, 4, 5].into(), + head_data: malicious_available_data.validation_data.parent_head.clone(), processed_downward_messages: 0, - hrmp_watermark: available_data.validation_data.relay_parent_number, + hrmp_watermark: validation_data_relay_parent_number, }; - let malicious_candidate = CommittedCandidateReceipt { + + let malicious_candidate = CandidateReceipt { descriptor: CandidateDescriptor { - para_id: candidate_cache.descriptor().para_id, + para_id: candidate.descriptor().para_id, relay_parent, collator: collator_id, persisted_validation_data_hash: validation_data_hash, @@ -177,24 +190,56 @@ where para_head: malicious_commitments.head_data.hash(), validation_code_hash, }, - commitments: malicious_commitments.clone(), + commitments_hash: malicious_commitments.hash(), }; let malicious_candidate_hash = malicious_candidate.hash(); - gum::info!(target: MALUS, ?candidate_hash, "Replacing candidate availability data"); + gum::info!( + target: MALUS, + candidate_hash = ?candidate.hash(), + ?malicious_candidate_hash, + "Created malicious candidate" + ); + + self.inner + .lock() + .expect("bad lock") + .map + .insert(malicious_candidate_hash, candidate.hash()); + let message = FromOverseer::Communication { + msg: CandidateBackingMessage::Second(relay_parent, malicious_candidate, pov), + }; - // We need to use the same candidate hash for storing the availability data, such that - // other's can fetch it. - Some(AllMessages::AvailabilityStore(AvailabilityStoreMessage::StoreAvailableData { - candidate_hash, - n_validators, - available_data: malicious_available_data, - tx, - })) + Some(message) }, - msg => Some(msg), + FromOverseer::Communication { msg } => Some(FromOverseer::Communication { msg }), + FromOverseer::Signal(signal) => Some(FromOverseer::Signal(signal)), } } + + fn intercept_outgoing(&self, msg: AllMessages) -> Option { + let msg = match msg { + // TODO: Send the Seconded statement for the original candidate. + AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded( + relay_parent, + statement, + )) => { + // match self.inner.lock().expect("bad lock").map.entry(statement.payload().candidate_hash()) { + // Entry::Occupied(original_candidate) => { + // // Create new statement + // statement.payload_ut(). + + // } + // } + AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded( + relay_parent, + statement, + )) + }, + msg => msg, + }; + Some(msg) + } } /// Garbage candidate implementation wrapper which implements `OverseerGen` glue. @@ -213,10 +258,20 @@ impl OverseerGen for BackGarbageCandidateWrapper { { let inner = Inner { map: std::collections::HashMap::new() }; let inner_mut = Arc::new(Mutex::new(inner)); - let note_candidate = NoteCandidate { inner: inner_mut.clone() }; + let note_candidate = + NoteCandidate { inner: inner_mut.clone(), spawner: args.spawner.clone() }; + + let validation_filter = ReplaceValidationResult::new( + FakeCandidateValidation::BackingAndApprovalValid, + FakeCandidateValidationError::InvalidOutputs, + args.spawner.clone(), + ); prepared_overseer_builder(args)? .replace_candidate_backing(move |cb| InterceptedSubsystem::new(cb, note_candidate)) + .replace_candidate_validation(move |cb| { + InterceptedSubsystem::new(cb, validation_filter) + }) .build_with_connector(connector) .map_err(|e| e.into()) } From 519d693493a709cd6be40ffd7f414a5fff746e96 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Wed, 30 Mar 2022 15:35:33 +0000 Subject: [PATCH 26/47] Dedup Signed-off-by: Andrei Sandu --- .../src/variants/suggest_garbage_candidate.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/node/malus/src/variants/suggest_garbage_candidate.rs b/node/malus/src/variants/suggest_garbage_candidate.rs index 5f2f5191b8ec..0922d22ff7ca 100644 --- a/node/malus/src/variants/suggest_garbage_candidate.rs +++ b/node/malus/src/variants/suggest_garbage_candidate.rs @@ -40,7 +40,10 @@ use polkadot_node_subsystem_util::request_validators; use crate::{ interceptor::*, shared::{MALICIOUS_POV, MALUS}, - variants::{FakeCandidateValidation, FakeCandidateValidationError, ReplaceValidationResult}, + variants::{ + create_fake_candidate_commitments, FakeCandidateValidation, FakeCandidateValidationError, + ReplaceValidationResult, + }, }; // Import extra types relevant to the particular @@ -169,14 +172,8 @@ where (collator_pair.public(), collator_pair.sign(&signature_payload)) }; - let malicious_commitments = CandidateCommitments { - upward_messages: Vec::new(), - horizontal_messages: Vec::new(), - new_validation_code: None, - head_data: malicious_available_data.validation_data.parent_head.clone(), - processed_downward_messages: 0, - hrmp_watermark: validation_data_relay_parent_number, - }; + let malicious_commitments = + create_fake_candidate_commitments(&malicious_available_data.validation_data); let malicious_candidate = CandidateReceipt { descriptor: CandidateDescriptor { From 6724b4a9cd6ccd076b9df6c8020cfbbc332017c9 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Thu, 31 Mar 2022 08:40:50 +0000 Subject: [PATCH 27/47] cleanup #1 Signed-off-by: Andrei Sandu --- .../src/variants/back_garbage_candidate.rs | 4 +- node/malus/src/variants/common.rs | 108 ++---------------- .../src/variants/suggest_garbage_candidate.rs | 23 ++-- 3 files changed, 23 insertions(+), 112 deletions(-) diff --git a/node/malus/src/variants/back_garbage_candidate.rs b/node/malus/src/variants/back_garbage_candidate.rs index 0b57cd827cef..2ca98576eda0 100644 --- a/node/malus/src/variants/back_garbage_candidate.rs +++ b/node/malus/src/variants/back_garbage_candidate.rs @@ -111,7 +111,7 @@ where pov, _duration, response_sender, - candidate_commitments, + _candidate_commitments, ), } if pov.block_data.0.as_slice() == MALICIOUS_POV => { Self::let_pass( @@ -130,7 +130,7 @@ where pov, _duration, response_sender, - commitments_hash, + _commitments_hash, ), } if pov.block_data.0.as_slice() == MALICIOUS_POV => { if let Some(candidate_receipt) = diff --git a/node/malus/src/variants/common.rs b/node/malus/src/variants/common.rs index b11e68714d78..71bc28633106 100644 --- a/node/malus/src/variants/common.rs +++ b/node/malus/src/variants/common.rs @@ -23,22 +23,18 @@ use crate::{ interceptor::*, shared::{MALICIOUS_POV, MALUS}, }; -use std::collections::HashMap; use polkadot_node_core_candidate_validation::find_validation_data; use polkadot_node_primitives::{InvalidCandidate, PoV, ValidationResult}; use polkadot_node_subsystem::messages::{CandidateValidationMessage, ValidationFailed}; -use polkadot_primitives::v2::{ - BlockNumber, CandidateCommitments, CandidateDescriptor, Hash, PersistedValidationData, - ValidationCode, -}; +use polkadot_primitives::v2::{CandidateCommitments, CandidateDescriptor, PersistedValidationData}; use polkadot_cli::service::SpawnNamed; use clap::ArgEnum; use futures::channel::oneshot; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; #[derive(ArgEnum, Clone, Copy, Debug, PartialEq)] #[clap(rename_all = "kebab-case")] @@ -118,8 +114,6 @@ pub struct ReplaceValidationResult { fake_validation: FakeCandidateValidation, fake_validation_error: FakeCandidateValidationError, spawner: Spawner, - // We use the para head hash as key. - validation_result: Arc>>, } impl ReplaceValidationResult @@ -131,12 +125,7 @@ where fake_validation_error: FakeCandidateValidationError, spawner: Spawner, ) -> Self { - Self { - fake_validation, - fake_validation_error, - spawner, - validation_result: Arc::new(Mutex::new(HashMap::new())), - } + Self { fake_validation, fake_validation_error, spawner } } /// Creates and sends the validation response for a given candidate. Queries the runtime to obtain the validation data for the @@ -163,7 +152,9 @@ where Box::pin(async move { match find_validation_data(&mut subsystem_sender, &_candidate_descriptor).await { Ok(Some((validation_data, validation_code))) => { - sender.send((validation_data, validation_code)); + sender + .send((validation_data, validation_code)) + .expect("channel is still open"); }, _ => { panic!("Unable to fetch validation data"); @@ -171,14 +162,8 @@ where } }), ); - let (validation_data, validation_code) = receiver.recv().unwrap(); - create_validation_response( - validation_data, - Some(validation_code), - candidate_descriptor, - pov, - response_sender, - ); + let (validation_data, _) = receiver.recv().unwrap(); + create_validation_response(validation_data, candidate_descriptor, pov, response_sender); } } @@ -198,7 +183,6 @@ pub fn create_fake_candidate_commitments( // Create and send validation response. This function needs the persistent validation data. fn create_validation_response( persisted_validation_data: PersistedValidationData, - validation_code: Option, _candidate_descriptor: CandidateDescriptor, _pov: Arc, response_sender: oneshot::Sender>, @@ -229,74 +213,6 @@ where subsystem_sender: &mut Sender, msg: FromOverseer, ) -> Option> { - if self.fake_validation == FakeCandidateValidation::Disabled { - // Proxy messages and cache validation results. - match msg { - FromOverseer::Communication { - msg: - CandidateValidationMessage::ValidateFromChainState( - descriptor, - pov, - timeout, - response_sender, - commitments_hash, - ), - } => { - // This is our request, let it pass to original subsystem. - if timeout == std::time::Duration::from_secs(13) { - return Some(FromOverseer::Communication { - msg: CandidateValidationMessage::ValidateFromChainState( - descriptor, - pov, - timeout, - response_sender, - commitments_hash, - ), - }) - } - - let (tx, rx) = oneshot::channel(); - let mut subsystem_sender = subsystem_sender.clone(); - - gum::info!(target: MALUS, "Proxying validation request",); - - let validation_result = self.validation_result.clone(); - self.spawner.spawn( - "malus-validation-proxy", - Some("malus"), - Box::pin(async move { - subsystem_sender - .send_message(CandidateValidationMessage::ValidateFromChainState( - descriptor.clone(), - pov, - std::time::Duration::from_secs(13), - tx, - commitments_hash, - )) - .await; - let result = rx.await.unwrap(); - gum::info!(target: MALUS, "Proxied validation result {:?}", &result); - match result.unwrap() { - ValidationResult::Valid(commitments, validation_data) => { - validation_result.lock().expect("bad lock").insert( - descriptor.para_head, - (commitments.clone(), validation_data.clone()), - ); - response_sender.send(Ok(ValidationResult::Valid( - commitments, - validation_data, - ))); - }, - _ => panic!("Bad things can happen."), - } - }), - ); - return None - }, - _ => return Some(msg), - } - } - match msg { FromOverseer::Communication { msg: @@ -328,13 +244,7 @@ where match self.fake_validation { FakeCandidateValidation::ApprovalValid | FakeCandidateValidation::BackingAndApprovalValid => { - create_validation_response( - validation_data, - Some(validation_code), - descriptor, - pov, - sender, - ); + create_validation_response(validation_data, descriptor, pov, sender); None }, FakeCandidateValidation::ApprovalInvalid | diff --git a/node/malus/src/variants/suggest_garbage_candidate.rs b/node/malus/src/variants/suggest_garbage_candidate.rs index 0922d22ff7ca..1f893621c1ee 100644 --- a/node/malus/src/variants/suggest_garbage_candidate.rs +++ b/node/malus/src/variants/suggest_garbage_candidate.rs @@ -32,7 +32,7 @@ use polkadot_cli::{ }; use polkadot_node_core_candidate_validation::find_validation_data; use polkadot_node_primitives::{AvailableData, BlockData, PoV}; -use polkadot_primitives::v2::{CandidateCommitments, CandidateDescriptor, CandidateHash}; +use polkadot_primitives::v2::{CandidateDescriptor, CandidateHash}; use polkadot_node_subsystem_util::request_validators; @@ -80,7 +80,7 @@ where { type Message = CandidateBackingMessage; - /// Cache and forward `CandidateBackingMessage::Second`. This is called by collator protocol (validator side). + /// Intercept incoming `Second` requests from the `collator-protocol` subsystem. We take fn intercept_incoming( &self, subsystem_sender: &mut Sender, @@ -117,7 +117,9 @@ where match find_validation_data(&mut new_sender, &_candidate.descriptor()).await { Ok(Some((validation_data, validation_code))) => { - sender.send((validation_data, validation_code, n_validators)); + sender + .send((validation_data, validation_code, n_validators)) + .expect("channel is still open"); }, _ => { panic!("Unable to fetch validation data"); @@ -198,11 +200,14 @@ where "Created malicious candidate" ); + // 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 message = FromOverseer::Communication { msg: CandidateBackingMessage::Second(relay_parent, malicious_candidate, pov), }; @@ -216,18 +221,14 @@ where fn intercept_outgoing(&self, msg: AllMessages) -> Option { let msg = match msg { - // TODO: Send the Seconded statement for the original candidate. AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded( relay_parent, statement, )) => { - // match self.inner.lock().expect("bad lock").map.entry(statement.payload().candidate_hash()) { - // Entry::Occupied(original_candidate) => { - // // Create new statement - // statement.payload_ut(). - - // } - // } + // `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. AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded( relay_parent, statement, From b6e1bbd27349ad2001b167a1cef864b6d1cb766d Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Fri, 1 Apr 2022 11:17:10 +0000 Subject: [PATCH 28/47] Fix tests Signed-off-by: Andrei Sandu --- node/core/approval-voting/src/tests.rs | 2 +- node/core/backing/src/tests.rs | 30 +++++++--- node/core/candidate-validation/src/tests.rs | 25 ++++++++ .../src/real/participation/mod.rs | 4 +- .../src/real/participation/tests.rs | 29 +++++---- .../dispute-coordinator/src/real/tests.rs | 59 +++++++++++++++---- node/malus/src/malus.rs | 2 +- node/overseer/examples/minimal-example.rs | 1 + node/overseer/src/tests.rs | 2 + zombienet_tests/functional/0000.feature | 8 +++ zombienet_tests/functional/0000.toml | 45 ++++++++++++++ 11 files changed, 174 insertions(+), 33 deletions(-) create mode 100644 zombienet_tests/functional/0000.feature create mode 100644 zombienet_tests/functional/0000.toml diff --git a/node/core/approval-voting/src/tests.rs b/node/core/approval-voting/src/tests.rs index 0bb6104dae3f..c5f34654c69c 100644 --- a/node/core/approval-voting/src/tests.rs +++ b/node/core/approval-voting/src/tests.rs @@ -2403,7 +2403,7 @@ pub async fn handle_double_assignment_import( assert_eq!(candidate_index, c_index); }, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx), + CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx, _), ) if timeout == APPROVAL_EXECUTION_TIMEOUT => { tx.send(Ok(ValidationResult::Valid(Default::default(), Default::default()))) .unwrap(); diff --git a/node/core/backing/src/tests.rs b/node/core/backing/src/tests.rs index a6316df34a2f..6cc18b950f56 100644 --- a/node/core/backing/src/tests.rs +++ b/node/core/backing/src/tests.rs @@ -336,8 +336,9 @@ fn backing_second_works() { pov, timeout, tx, + commitments_hash ) - ) if pov == pov && &c == candidate.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT => { + ) if pov == pov && &c == candidate.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && commitments_hash == candidate.commitments.hash() => { tx.send(Ok( ValidationResult::Valid(CandidateCommitments { head_data: expected_head_data.clone(), @@ -419,6 +420,8 @@ fn backing_works() { .build(); let candidate_a_hash = candidate_a.hash(); + let candidate_a_commitments_hash = candidate_a.commitments.hash(); + let public1 = CryptoStore::sr25519_generate_new( &*test_state.keystore, ValidatorId::ID, @@ -496,8 +499,9 @@ fn backing_works() { pov, timeout, tx, + hash ) - ) if pov == pov && &c == candidate_a.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT => { + ) if pov == pov && &c == candidate_a.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && hash == candidate_a_commitments_hash=> { tx.send(Ok( ValidationResult::Valid(CandidateCommitments { head_data: expected_head_data.clone(), @@ -594,6 +598,8 @@ fn backing_works_while_validation_ongoing() { .build(); let candidate_a_hash = candidate_a.hash(); + let candidate_a_commitments_hash = candidate_a.commitments.hash(); + let public1 = CryptoStore::sr25519_generate_new( &*test_state.keystore, ValidatorId::ID, @@ -690,8 +696,9 @@ fn backing_works_while_validation_ongoing() { pov, timeout, tx, + hash ) - ) if pov == pov && &c == candidate_a.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT => { + ) if pov == pov && &c == candidate_a.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && candidate_a_commitments_hash == hash => { // we never validate the candidate. our local node // shouldn't issue any statements. std::mem::forget(tx); @@ -799,6 +806,8 @@ fn backing_misbehavior_works() { .build(); let candidate_a_hash = candidate_a.hash(); + let candidate_a_commitments_hash = candidate_a.commitments.hash(); + let public2 = CryptoStore::sr25519_generate_new( &*test_state.keystore, ValidatorId::ID, @@ -864,8 +873,9 @@ fn backing_misbehavior_works() { pov, timeout, tx, + hash ) - ) if pov == pov && &c == candidate_a.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT => { + ) if pov == pov && &c == candidate_a.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && candidate_a_commitments_hash == hash => { tx.send(Ok( ValidationResult::Valid(CandidateCommitments { head_data: expected_head_data.clone(), @@ -1024,6 +1034,7 @@ fn backing_dont_second_invalid() { pov, timeout, tx, + _ ) ) if pov == pov && &c == candidate_a.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT => { tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::BadReturn))).unwrap(); @@ -1053,6 +1064,7 @@ fn backing_dont_second_invalid() { pov, timeout, tx, + _ ) ) if pov == pov && &c == candidate_b.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT => { tx.send(Ok( @@ -1184,8 +1196,9 @@ fn backing_second_after_first_fails_works() { pov, timeout, tx, + hash ) - ) if pov == pov && &c == candidate.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT => { + ) if pov == pov && &c == candidate.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && hash == candidate.commitments.hash() => { tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::BadReturn))).unwrap(); } ); @@ -1232,6 +1245,7 @@ fn backing_second_after_first_fails_works() { pov, _, _, + _, ) ) => { assert_eq!(&*pov, &pov_to_second); @@ -1318,8 +1332,9 @@ fn backing_works_after_failed_validation() { pov, timeout, tx, + hash ) - ) if pov == pov && &c == candidate.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT => { + ) if pov == pov && &c == candidate.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && hash == candidate.commitments.hash() => { tx.send(Err(ValidationFailed("Internal test error".into()))).unwrap(); } ); @@ -1696,8 +1711,9 @@ fn retry_works() { pov, timeout, _tx, + hash, ) - ) if pov == pov && &c == candidate.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT + ) if pov == pov && &c == candidate.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && hash == candidate.commitments.hash() ); virtual_overseer }); diff --git a/node/core/candidate-validation/src/tests.rs b/node/core/candidate-validation/src/tests.rs index 29c4185ed2cb..919cb8912b0c 100644 --- a/node/core/candidate-validation/src/tests.rs +++ b/node/core/candidate-validation/src/tests.rs @@ -406,6 +406,15 @@ fn candidate_validation_ok_is_ok() { hrmp_watermark: 0, }; + let commitments = CandidateCommitments { + head_data: validation_result.head_data.clone(), + upward_messages: validation_result.upward_messages.clone(), + horizontal_messages: validation_result.horizontal_messages.clone(), + new_validation_code: validation_result.new_validation_code.clone(), + processed_downward_messages: validation_result.processed_downward_messages, + hrmp_watermark: validation_result.hrmp_watermark, + }; + let v = executor::block_on(validate_candidate_exhaustive( MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), validation_data.clone(), @@ -414,6 +423,7 @@ fn candidate_validation_ok_is_ok() { Arc::new(pov), Duration::from_secs(0), &Default::default(), + commitments.hash(), )) .unwrap(); @@ -463,6 +473,7 @@ fn candidate_validation_bad_return_is_invalid() { Arc::new(pov), Duration::from_secs(0), &Default::default(), + Hash::zero(), )) .unwrap(); @@ -505,6 +516,7 @@ fn candidate_validation_timeout_is_internal_error() { Arc::new(pov), Duration::from_secs(0), &Default::default(), + Hash::zero(), )); assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::Timeout))); @@ -546,6 +558,7 @@ fn candidate_validation_code_mismatch_is_invalid() { Arc::new(pov), Duration::from_secs(0), &Default::default(), + Hash::zero(), )) .unwrap(); @@ -583,6 +596,15 @@ fn compressed_code_works() { hrmp_watermark: 0, }; + let commitments = CandidateCommitments { + head_data: validation_result.head_data.clone(), + upward_messages: validation_result.upward_messages.clone(), + horizontal_messages: validation_result.horizontal_messages.clone(), + new_validation_code: validation_result.new_validation_code.clone(), + processed_downward_messages: validation_result.processed_downward_messages, + hrmp_watermark: validation_result.hrmp_watermark, + }; + let v = executor::block_on(validate_candidate_exhaustive( MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), validation_data, @@ -591,6 +613,7 @@ fn compressed_code_works() { Arc::new(pov), Duration::from_secs(0), &Default::default(), + commitments.hash(), )); assert_matches!(v, Ok(ValidationResult::Valid(_, _))); @@ -636,6 +659,7 @@ fn code_decompression_failure_is_invalid() { Arc::new(pov), Duration::from_secs(0), &Default::default(), + Hash::zero(), )); assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::CodeDecompressionFailure))); @@ -682,6 +706,7 @@ fn pov_decompression_failure_is_invalid() { Arc::new(pov), Duration::from_secs(0), &Default::default(), + Hash::zero(), )); assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::PoVDecompressionFailure))); diff --git a/node/core/dispute-coordinator/src/real/participation/mod.rs b/node/core/dispute-coordinator/src/real/participation/mod.rs index fd1ccf06ed19..7ef528ce0e4d 100644 --- a/node/core/dispute-coordinator/src/real/participation/mod.rs +++ b/node/core/dispute-coordinator/src/real/participation/mod.rs @@ -372,9 +372,11 @@ async fn participate( ) .await; + let res = validation_rx.await; + println!("Validation res: {:?}", res); // we cast votes (either positive or negative) depending on the outcome of // the validation and if valid, whether the commitments hash matches - match validation_rx.await { + match res { Err(oneshot::Canceled) => { gum::warn!( target: LOG_TARGET, diff --git a/node/core/dispute-coordinator/src/real/participation/tests.rs b/node/core/dispute-coordinator/src/real/participation/tests.rs index bbb83e9fcda0..d4c611d5ebda 100644 --- a/node/core/dispute-coordinator/src/real/participation/tests.rs +++ b/node/core/dispute-coordinator/src/real/participation/tests.rs @@ -108,7 +108,10 @@ async fn activate_leaf( } /// Full participation happy path as seen via the overseer. -pub async fn participation_full_happy_path(ctx_handle: &mut VirtualOverseer) { +pub async fn participation_full_happy_path( + ctx_handle: &mut VirtualOverseer, + expected_commitments_hash: Hash, +) { recover_available_data(ctx_handle).await; fetch_validation_code(ctx_handle).await; store_available_data(ctx_handle, true).await; @@ -116,9 +119,13 @@ pub async fn participation_full_happy_path(ctx_handle: &mut VirtualOverseer) { assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx) + CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx, commitments_hash) ) if timeout == APPROVAL_EXECUTION_TIMEOUT => { - tx.send(Ok(ValidationResult::Valid(dummy_candidate_commitments(None), PersistedValidationData::default()))).unwrap(); + if expected_commitments_hash != commitments_hash { + tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::ComittmentsHashMismatch))).unwrap(); + } else { + tx.send(Ok(ValidationResult::Valid(dummy_candidate_commitments(None), PersistedValidationData::default()))).unwrap(); + } }, "overseer did not receive candidate validation message", ); @@ -419,7 +426,7 @@ fn cast_invalid_vote_if_validation_fails_or_is_invalid() { assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx) + CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx, _) ) if timeout == APPROVAL_EXECUTION_TIMEOUT => { tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::Timeout))).unwrap(); }, @@ -438,7 +445,7 @@ fn cast_invalid_vote_if_validation_fails_or_is_invalid() { } #[test] -fn cast_invalid_vote_if_validation_passes_but_commitments_dont_match() { +fn cast_invalid_vote_if_commitments_dont_match() { futures::executor::block_on(async { let (mut ctx, mut ctx_handle) = make_our_subsystem_context(TaskExecutor::new()); @@ -457,13 +464,9 @@ fn cast_invalid_vote_if_validation_passes_but_commitments_dont_match() { assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx) + CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx, _) ) if timeout == APPROVAL_EXECUTION_TIMEOUT => { - let mut commitments = CandidateCommitments::default(); - // this should lead to a commitments hash mismatch - commitments.processed_downward_messages = 42; - - tx.send(Ok(ValidationResult::Valid(commitments, PersistedValidationData::default()))).unwrap(); + tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::ComittmentsHashMismatch))).unwrap(); }, "overseer did not receive candidate validation message", ); @@ -499,7 +502,7 @@ fn cast_valid_vote_if_validation_passes() { assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx) + CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx, _) ) if timeout == APPROVAL_EXECUTION_TIMEOUT => { tx.send(Ok(ValidationResult::Valid(dummy_candidate_commitments(None), PersistedValidationData::default()))).unwrap(); }, @@ -538,7 +541,7 @@ fn failure_to_store_available_data_does_not_preclude_participation() { assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx) + CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx, _) ) if timeout == APPROVAL_EXECUTION_TIMEOUT => { tx.send(Err(ValidationFailed("fail".to_string()))).unwrap(); }, diff --git a/node/core/dispute-coordinator/src/real/tests.rs b/node/core/dispute-coordinator/src/real/tests.rs index bfed38265513..b1b87dd3bfa2 100644 --- a/node/core/dispute-coordinator/src/real/tests.rs +++ b/node/core/dispute-coordinator/src/real/tests.rs @@ -407,8 +407,9 @@ where async fn participation_with_distribution( virtual_overseer: &mut VirtualOverseer, candidate_hash: &CandidateHash, + expected_commitments_hash: Hash, ) { - participation_full_happy_path(virtual_overseer).await; + participation_full_happy_path(virtual_overseer, expected_commitments_hash).await; assert_matches!( virtual_overseer.recv().await, AllMessages::DisputeDistribution( @@ -426,7 +427,6 @@ fn make_valid_candidate_receipt() -> CandidateReceipt { } fn make_invalid_candidate_receipt() -> CandidateReceipt { - // Commitments hash will be 0, which is not correct: dummy_candidate_receipt_bad_sig(Default::default(), Some(Default::default())) } @@ -593,7 +593,12 @@ fn dispute_gets_confirmed_via_participation() { }) .await; - participation_with_distribution(&mut virtual_overseer, &candidate_hash1).await; + participation_with_distribution( + &mut virtual_overseer, + &candidate_hash1, + candidate_receipt1.commitments_hash, + ) + .await; { let (tx, rx) = oneshot::channel(); @@ -942,7 +947,12 @@ fn conflicting_votes_lead_to_dispute_participation() { }) .await; - participation_with_distribution(&mut virtual_overseer, &candidate_hash).await; + participation_with_distribution( + &mut virtual_overseer, + &candidate_hash, + candidate_receipt.commitments_hash, + ) + .await; { let (tx, rx) = oneshot::channel(); @@ -1224,7 +1234,12 @@ fn finality_votes_ignore_disputed_candidates() { }) .await; - participation_with_distribution(&mut virtual_overseer, &candidate_hash).await; + participation_with_distribution( + &mut virtual_overseer, + &candidate_hash, + candidate_receipt.commitments_hash, + ) + .await; { let (tx, rx) = oneshot::channel(); @@ -1322,7 +1337,12 @@ fn supermajority_valid_dispute_may_be_finalized() { }) .await; - participation_with_distribution(&mut virtual_overseer, &candidate_hash).await; + participation_with_distribution( + &mut virtual_overseer, + &candidate_hash, + candidate_receipt.commitments_hash, + ) + .await; let mut statements = Vec::new(); for i in (0..supermajority_threshold - 1).map(|i| i + 3) { @@ -1442,7 +1462,12 @@ fn concluded_supermajority_for_non_active_after_time() { }) .await; - participation_with_distribution(&mut virtual_overseer, &candidate_hash).await; + participation_with_distribution( + &mut virtual_overseer, + &candidate_hash, + candidate_receipt.commitments_hash, + ) + .await; let mut statements = Vec::new(); // -2: 1 for already imported vote and one for local vote (which is valid). @@ -1543,7 +1568,13 @@ fn concluded_supermajority_against_non_active_after_time() { ImportStatementsResult::ValidImport => {} ); - participation_with_distribution(&mut virtual_overseer, &candidate_hash).await; + // Use a different expected commitments hash to ensure the candidate validation returns invalid. + participation_with_distribution( + &mut virtual_overseer, + &candidate_hash, + CandidateCommitments::default().hash(), + ) + .await; let mut statements = Vec::new(); // minus 2, because of local vote and one previously imported invalid vote. @@ -1579,7 +1610,10 @@ fn concluded_supermajority_against_non_active_after_time() { }) .await; - assert!(rx.await.unwrap().is_empty()); + let res = rx.await.unwrap(); + + println!("supermajority_threshold {} result {:?}", supermajority_threshold, res); + assert!(res.is_empty()); let (tx, rx) = oneshot::channel(); @@ -1672,7 +1706,12 @@ fn resume_dispute_without_local_statement() { let candidate_receipt = make_valid_candidate_receipt(); let candidate_hash = candidate_receipt.hash(); - participation_with_distribution(&mut virtual_overseer, &candidate_hash).await; + participation_with_distribution( + &mut virtual_overseer, + &candidate_hash, + candidate_receipt.commitments_hash, + ) + .await; let valid_vote0 = test_state .issue_explicit_statement_with_index(0, candidate_hash, session, true) diff --git a/node/malus/src/malus.rs b/node/malus/src/malus.rs index 38a5f0afbef8..88b3f8130abd 100644 --- a/node/malus/src/malus.rs +++ b/node/malus/src/malus.rs @@ -122,7 +122,7 @@ mod tests { variant: NemesisVariant::DisputeAncestor(run), .. } => { - assert!(run.base.bob); + assert!(run.cmd.base.bob); }); } } diff --git a/node/overseer/examples/minimal-example.rs b/node/overseer/examples/minimal-example.rs index 20141fad8555..0f8d4484418e 100644 --- a/node/overseer/examples/minimal-example.rs +++ b/node/overseer/examples/minimal-example.rs @@ -78,6 +78,7 @@ impl Subsystem1 { PoV { block_data: BlockData(Vec::new()) }.into(), Default::default(), tx, + Hash::zero(), ); ctx.send_message(::AllMessages::from(msg)) .await; diff --git a/node/overseer/src/tests.rs b/node/overseer/src/tests.rs index cc4bd38f05b0..88fc1b784821 100644 --- a/node/overseer/src/tests.rs +++ b/node/overseer/src/tests.rs @@ -114,6 +114,7 @@ where PoV { block_data: BlockData(Vec::new()) }.into(), Default::default(), tx, + Hash::zero(), )) .await; c += 1; @@ -797,6 +798,7 @@ fn test_candidate_validation_msg() -> CandidateValidationMessage { pov, Duration::default(), sender, + Hash::zero(), ) } diff --git a/zombienet_tests/functional/0000.feature b/zombienet_tests/functional/0000.feature new file mode 100644 index 000000000000..c2508eecf572 --- /dev/null +++ b/zombienet_tests/functional/0000.feature @@ -0,0 +1,8 @@ +Description: Disputes initiation, conclusion and lag +Network: ./0000.toml +Creds: config + +honest-0: is up +malus-0: is up + +sleep 100000 seconds \ No newline at end of file diff --git a/zombienet_tests/functional/0000.toml b/zombienet_tests/functional/0000.toml new file mode 100644 index 000000000000..0e2a69d357f8 --- /dev/null +++ b/zombienet_tests/functional/0000.toml @@ -0,0 +1,45 @@ +[settings] +timeout = 1000 +bootnode = true + +[relaychain.genesis.runtime.runtime_genesis_config.configuration.config] + max_validators_per_core = 1 + needed_approvals = 2 + max_validators = 1000 + +[relaychain] +chain = "rococo-local" +chain_spec_command = "../polkadot/target/testnet/polkadot build-spec --chain rococo-local" +default_command = "../polkadot/target/testnet/polkadot" + + [[relaychain.node_groups]] + name = "honest" + command = "../polkadot/target/testnet/polkadot -lparachain=trace" + count = 3 + + [[relaychain.node_groups]] + name = "malus-garbage-suggester" + command = "../polkadot/target/testnet/malus suggest-garbage-candidate -lparachain=trace" + count = 1 + + # [[relaychain.node_groups]] + # name = "malus-disputer" + # command = "../polkadot/target/testnet/malus dispute-ancestor -lparachain=debug" + # count = 2 + +{% for id in range(2000,2001) %} +[[parachains]] +id = {{id}} +addToGenesis = true +genesis_state_generator = "../polkadot/target/testnet/undying-collator export-genesis-state --pov-size=20000 --pvf-complexity=2" + [parachains.collator] + name = "collator" + command = "../polkadot/target/testnet/undying-collator" + args = ["-lparachain=debug", "--pov-size=20000", "--parachain-id={{id}}", "--pvf-complexity=2"] + +{% endfor %} + +[types.Header] +number = "u64" +parent_hash = "Hash" +post_state = "Hash" From 5f29b6ccc045eb9ca2765cd53bcf088ae503d096 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Fri, 1 Apr 2022 11:23:52 +0000 Subject: [PATCH 29/47] remove debug leftovers Signed-off-by: Andrei Sandu --- node/core/dispute-coordinator/src/real/participation/mod.rs | 4 +--- node/core/dispute-coordinator/src/real/tests.rs | 6 +----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/node/core/dispute-coordinator/src/real/participation/mod.rs b/node/core/dispute-coordinator/src/real/participation/mod.rs index 7ef528ce0e4d..fd1ccf06ed19 100644 --- a/node/core/dispute-coordinator/src/real/participation/mod.rs +++ b/node/core/dispute-coordinator/src/real/participation/mod.rs @@ -372,11 +372,9 @@ async fn participate( ) .await; - let res = validation_rx.await; - println!("Validation res: {:?}", res); // we cast votes (either positive or negative) depending on the outcome of // the validation and if valid, whether the commitments hash matches - match res { + match validation_rx.await { Err(oneshot::Canceled) => { gum::warn!( target: LOG_TARGET, diff --git a/node/core/dispute-coordinator/src/real/tests.rs b/node/core/dispute-coordinator/src/real/tests.rs index b1b87dd3bfa2..35ecd290f435 100644 --- a/node/core/dispute-coordinator/src/real/tests.rs +++ b/node/core/dispute-coordinator/src/real/tests.rs @@ -1610,11 +1610,7 @@ fn concluded_supermajority_against_non_active_after_time() { }) .await; - let res = rx.await.unwrap(); - - println!("supermajority_threshold {} result {:?}", supermajority_threshold, res); - assert!(res.is_empty()); - + assert!( rx.await.unwrap().is_empty()); let (tx, rx) = oneshot::channel(); virtual_overseer From ea2b1e509e7bd695183ff184736dd13526032148 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Fri, 1 Apr 2022 11:25:58 +0000 Subject: [PATCH 30/47] fmt Signed-off-by: Andrei Sandu --- node/core/dispute-coordinator/src/real/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/core/dispute-coordinator/src/real/tests.rs b/node/core/dispute-coordinator/src/real/tests.rs index 35ecd290f435..54b952fd9e2b 100644 --- a/node/core/dispute-coordinator/src/real/tests.rs +++ b/node/core/dispute-coordinator/src/real/tests.rs @@ -1610,7 +1610,7 @@ fn concluded_supermajority_against_non_active_after_time() { }) .await; - assert!( rx.await.unwrap().is_empty()); + assert!(rx.await.unwrap().is_empty()); let (tx, rx) = oneshot::channel(); virtual_overseer From fca095f1e122fd2ac2a57e101a6ea2a3cba43a5e Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Fri, 1 Apr 2022 11:30:39 +0000 Subject: [PATCH 31/47] Accidentally commited some local test Signed-off-by: Andrei Sandu --- zombienet_tests/functional/0000.feature | 8 ----- zombienet_tests/functional/0000.toml | 45 ------------------------- 2 files changed, 53 deletions(-) delete mode 100644 zombienet_tests/functional/0000.feature delete mode 100644 zombienet_tests/functional/0000.toml diff --git a/zombienet_tests/functional/0000.feature b/zombienet_tests/functional/0000.feature deleted file mode 100644 index c2508eecf572..000000000000 --- a/zombienet_tests/functional/0000.feature +++ /dev/null @@ -1,8 +0,0 @@ -Description: Disputes initiation, conclusion and lag -Network: ./0000.toml -Creds: config - -honest-0: is up -malus-0: is up - -sleep 100000 seconds \ No newline at end of file diff --git a/zombienet_tests/functional/0000.toml b/zombienet_tests/functional/0000.toml deleted file mode 100644 index 0e2a69d357f8..000000000000 --- a/zombienet_tests/functional/0000.toml +++ /dev/null @@ -1,45 +0,0 @@ -[settings] -timeout = 1000 -bootnode = true - -[relaychain.genesis.runtime.runtime_genesis_config.configuration.config] - max_validators_per_core = 1 - needed_approvals = 2 - max_validators = 1000 - -[relaychain] -chain = "rococo-local" -chain_spec_command = "../polkadot/target/testnet/polkadot build-spec --chain rococo-local" -default_command = "../polkadot/target/testnet/polkadot" - - [[relaychain.node_groups]] - name = "honest" - command = "../polkadot/target/testnet/polkadot -lparachain=trace" - count = 3 - - [[relaychain.node_groups]] - name = "malus-garbage-suggester" - command = "../polkadot/target/testnet/malus suggest-garbage-candidate -lparachain=trace" - count = 1 - - # [[relaychain.node_groups]] - # name = "malus-disputer" - # command = "../polkadot/target/testnet/malus dispute-ancestor -lparachain=debug" - # count = 2 - -{% for id in range(2000,2001) %} -[[parachains]] -id = {{id}} -addToGenesis = true -genesis_state_generator = "../polkadot/target/testnet/undying-collator export-genesis-state --pov-size=20000 --pvf-complexity=2" - [parachains.collator] - name = "collator" - command = "../polkadot/target/testnet/undying-collator" - args = ["-lparachain=debug", "--pov-size=20000", "--parachain-id={{id}}", "--pvf-complexity=2"] - -{% endfor %} - -[types.Header] -number = "u64" -parent_hash = "Hash" -post_state = "Hash" From 7d6b47219fae89911d0ea83a63a1119daaf1b258 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Fri, 1 Apr 2022 11:57:47 +0000 Subject: [PATCH 32/47] spellcheck Signed-off-by: Andrei Sandu --- node/subsystem-types/src/messages.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/subsystem-types/src/messages.rs b/node/subsystem-types/src/messages.rs index f801daba791e..ad9075cd1b35 100644 --- a/node/subsystem-types/src/messages.rs +++ b/node/subsystem-types/src/messages.rs @@ -158,7 +158,7 @@ pub enum CandidateValidationMessage { /// Execution timeout Duration, oneshot::Sender>, - /// Comittments hash + /// Commitments hash Hash, ), /// Try to compile the given validation code and send back From 3103ce7ae1346a46de50b18b2cf212e0768296ad Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Mon, 4 Apr 2022 09:39:15 +0000 Subject: [PATCH 33/47] some more fixes Signed-off-by: Andrei Sandu --- node/malus/src/variants/common.rs | 86 +++++++++---------- .../src/variants/dispute_valid_candidates.rs | 8 +- 2 files changed, 49 insertions(+), 45 deletions(-) diff --git a/node/malus/src/variants/common.rs b/node/malus/src/variants/common.rs index 71bc28633106..66b15d85e5d2 100644 --- a/node/malus/src/variants/common.rs +++ b/node/malus/src/variants/common.rs @@ -32,12 +32,12 @@ use polkadot_primitives::v2::{CandidateCommitments, CandidateDescriptor, Persist use polkadot_cli::service::SpawnNamed; -use clap::ArgEnum; use futures::channel::oneshot; use std::sync::Arc; -#[derive(ArgEnum, Clone, Copy, Debug, PartialEq)] +#[derive(clap::ArgEnum, Clone, Copy, Debug, PartialEq)] #[clap(rename_all = "kebab-case")] +#[non_exhaustive] pub enum FakeCandidateValidation { Disabled, BackingInvalid, @@ -46,13 +46,10 @@ pub enum FakeCandidateValidation { BackingValid, ApprovalValid, BackingAndApprovalValid, - // TODO: later. - // BackingValidAndApprovalInvalid, - // BackingInvalidAndApprovalValid, } /// Candidate invalidity details -#[derive(ArgEnum, Clone, Copy, Debug, PartialEq)] +#[derive(clap::ArgEnum, Clone, Copy, Debug, PartialEq)] #[clap(rename_all = "kebab-case")] pub enum FakeCandidateValidationError { /// Validation outputs check doesn't pass. @@ -183,16 +180,23 @@ pub fn create_fake_candidate_commitments( // Create and send validation response. This function needs the persistent validation data. fn create_validation_response( persisted_validation_data: PersistedValidationData, - _candidate_descriptor: CandidateDescriptor, + candidate_descriptor: CandidateDescriptor, _pov: Arc, response_sender: oneshot::Sender>, ) { - response_sender - .send(Ok(ValidationResult::Valid( - create_fake_candidate_commitments(&persisted_validation_data), - persisted_validation_data, - ))) - .unwrap(); + let result = Ok(ValidationResult::Valid( + create_fake_candidate_commitments(&persisted_validation_data), + persisted_validation_data, + )); + + gum::debug!( + target: MALUS, + para_id = ?candidate_descriptor.para_id, + "ValidationResult: {:?}", + &result + ); + + response_sender.send(result).unwrap(); } // TODO: Only fake validation for `MALICIOUS_POV`, otherwise behave normally. @@ -226,24 +230,23 @@ where commitments_hash, ), } => { - // Behave normally if the `PoV` is not known to be malicious. - if pov.block_data.0.as_slice() != MALICIOUS_POV { - return Some(FromOverseer::Communication { - msg: CandidateValidationMessage::ValidateFromExhaustive( - validation_data, - validation_code, - descriptor, - pov, - timeout, - sender, - commitments_hash, - ), - }) - } - match self.fake_validation { FakeCandidateValidation::ApprovalValid | FakeCandidateValidation::BackingAndApprovalValid => { + // Behave normally if the `PoV` is not known to be malicious. + if pov.block_data.0.as_slice() != MALICIOUS_POV { + return Some(FromOverseer::Communication { + msg: CandidateValidationMessage::ValidateFromExhaustive( + validation_data, + validation_code, + descriptor, + pov, + timeout, + sender, + commitments_hash, + ), + }) + } create_validation_response(validation_data, descriptor, pov, sender); None }, @@ -255,7 +258,6 @@ where gum::info!( target: MALUS, para_id = ?descriptor.para_id, - candidate_hash = ?descriptor.para_head, "ValidateFromExhaustive result: {:?}", &validation_result ); @@ -286,22 +288,21 @@ where commitments_hash, ), } => { - // Behave normally if the `PoV` is not known to be malicious. - if pov.block_data.0.as_slice() != MALICIOUS_POV { - return Some(FromOverseer::Communication { - msg: CandidateValidationMessage::ValidateFromChainState( - descriptor, - pov, - timeout, - response_sender, - commitments_hash, - ), - }) - } - match self.fake_validation { FakeCandidateValidation::BackingValid | FakeCandidateValidation::BackingAndApprovalValid => { + // Behave normally if the `PoV` is not known to be malicious. + if pov.block_data.0.as_slice() != MALICIOUS_POV { + return Some(FromOverseer::Communication { + msg: CandidateValidationMessage::ValidateFromChainState( + descriptor, + pov, + timeout, + response_sender, + commitments_hash, + ), + }) + } self.send_validation_response( descriptor, pov, @@ -317,7 +318,6 @@ where gum::info!( target: MALUS, para_id = ?descriptor.para_id, - candidate_hash = ?descriptor.para_head, "ValidateFromChainState result: {:?}", &validation_result ); diff --git a/node/malus/src/variants/dispute_valid_candidates.rs b/node/malus/src/variants/dispute_valid_candidates.rs index 2c4be798c683..4098f2706fa1 100644 --- a/node/malus/src/variants/dispute_valid_candidates.rs +++ b/node/malus/src/variants/dispute_valid_candidates.rs @@ -22,7 +22,6 @@ #![allow(missing_docs)] -use clap::Parser; use polkadot_cli::{ prepared_overseer_builder, service::{ @@ -44,13 +43,18 @@ use polkadot_node_subsystem::messages::{ use std::sync::Arc; -#[derive(Clone, Debug, Parser)] +#[derive(Clone, Debug, clap::Parser)] #[clap(rename_all = "kebab-case")] #[allow(missing_docs)] pub struct DisputeAncestorOptions { + /// Malicious candidate validation subsystem configuration. When enabled, node PVF execution is skipped + /// during backing and/or approval and it's result can by specified by this option and `--fake-validation-error` + /// for invalid candidate outcomes. #[clap(long, arg_enum, ignore_case = true, default_value_t = FakeCandidateValidation::Disabled)] pub fake_validation: FakeCandidateValidation, + /// Applies only when `--fake-validation` is configured to reject candidates as invalid. It allows + /// to specify the exact error to return from the malicious candidate validation subsystem. #[clap(long, arg_enum, ignore_case = true, default_value_t = FakeCandidateValidationError::InvalidOutputs)] pub fake_validation_error: FakeCandidateValidationError, From bde2403734b9ad55dd957257191e80331f955c73 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Fri, 8 Apr 2022 11:10:06 +0000 Subject: [PATCH 34/47] Refactor and fix it Signed-off-by: Andrei Sandu --- .../src/variants/back_garbage_candidate.rs | 198 ++---------------- 1 file changed, 16 insertions(+), 182 deletions(-) diff --git a/node/malus/src/variants/back_garbage_candidate.rs b/node/malus/src/variants/back_garbage_candidate.rs index 2ca98576eda0..9bbf7b170130 100644 --- a/node/malus/src/variants/back_garbage_candidate.rs +++ b/node/malus/src/variants/back_garbage_candidate.rs @@ -14,10 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! A malicious overseer backing a particular candidate with a -//! malicious proof of validity that is received. - -#![allow(missing_docs)] +//! This variant of Malus backs/approves all malicious candidates crafted by +//! `suggest-garbage-candidate` variant and behaves honestly wrt other +//! candidates. use polkadot_cli::{ prepared_overseer_builder, @@ -28,172 +27,15 @@ use polkadot_cli::{ }, }; -// Import extra types relevant to the particular -// subsystem. -use polkadot_node_core_candidate_validation::CandidateValidationSubsystem; -use polkadot_node_subsystem::messages::{ - AvailabilityRecoveryMessage, CandidateValidationMessage, ValidationFailed, -}; -use polkadot_node_subsystem_util as util; - -// Filter wrapping related types. -use crate::{interceptor::*, shared::*}; -use polkadot_node_primitives::{PoV, ValidationResult}; - -use polkadot_primitives::v2::{ - CandidateCommitments, CandidateDescriptor, CandidateReceipt, PersistedValidationData, - ValidationCode, -}; - -use futures::channel::oneshot; -use std::{ - collections::HashMap, - sync::{Arc, Mutex}, +use crate::{ + interceptor::*, + variants::{FakeCandidateValidation, FakeCandidateValidationError, ReplaceValidationResult}, }; -#[derive(Clone, Debug)] -struct BribedPassageInner { - spawner: Spawner, - cache: HashMap, -} - -#[derive(Clone, Debug)] -struct BribedPassage { - inner: Arc>>, -} - -impl BribedPassage -where - Spawner: SpawnNamed, -{ - fn let_pass( - persisted_validation_data: PersistedValidationData, - validation_code: Option, - _candidate_descriptor: CandidateDescriptor, - _pov: Arc, - response_sender: oneshot::Sender>, - ) { - let candidate_commitmentments = CandidateCommitments { - head_data: persisted_validation_data.parent_head.clone(), - new_validation_code: validation_code, - ..Default::default() - }; - - response_sender - .send(Ok(ValidationResult::Valid(candidate_commitmentments, persisted_validation_data))) - .unwrap(); - } -} - -impl MessageInterceptor for BribedPassage -where - Sender: overseer::SubsystemSender - + overseer::SubsystemSender - + Clone - + Send - + 'static, - Spawner: SpawnNamed + Send + Clone + 'static, -{ - type Message = CandidateValidationMessage; - - fn intercept_incoming( - &self, - sender: &mut Sender, - msg: FromOverseer, - ) -> Option> { - match msg { - FromOverseer::Communication { - msg: - CandidateValidationMessage::ValidateFromExhaustive( - persisted_validation_data, - validation_code, - candidate_descriptor, - pov, - _duration, - response_sender, - _candidate_commitments, - ), - } if pov.block_data.0.as_slice() == MALICIOUS_POV => { - Self::let_pass( - persisted_validation_data, - Some(validation_code), - candidate_descriptor, - pov, - response_sender, - ); - None - }, - FromOverseer::Communication { - msg: - CandidateValidationMessage::ValidateFromChainState( - candidate_descriptor, - pov, - _duration, - response_sender, - _commitments_hash, - ), - } if pov.block_data.0.as_slice() == MALICIOUS_POV => { - if let Some(candidate_receipt) = - self.inner.lock().unwrap().cache.get(&candidate_descriptor).cloned() - { - let mut subsystem_sender = sender.clone(); - let spawner = self.inner.lock().unwrap().spawner.clone(); - spawner.spawn( - "malus-back-garbage-adhoc", - Some("malus"), - Box::pin(async move { - let relay_parent = candidate_descriptor.relay_parent; - let session_index = util::request_session_index_for_child( - relay_parent, - &mut subsystem_sender, - ) - .await; - let session_index = session_index.await.unwrap().unwrap(); - - let (a_tx, a_rx) = oneshot::channel(); - - subsystem_sender - .send_message(AllMessages::from( - AvailabilityRecoveryMessage::RecoverAvailableData( - candidate_receipt, - session_index, - None, - a_tx, - ), - )) - .await; - - if let Ok(Ok(availability_data)) = a_rx.await { - Self::let_pass( - availability_data.validation_data, - None, - candidate_descriptor, - pov, - response_sender, - ); - } else { - gum::info!( - target: MALUS, - "Could not get availability data, can't back" - ); - } - }), - ); - } else { - gum::info!(target: MALUS, "No CandidateReceipt available to work with"); - } - None - }, - msg => Some(msg), - } - } - - fn intercept_outgoing(&self, msg: AllMessages) -> Option { - Some(msg) - } -} +use std::sync::Arc; -/// Generates an overseer that exposes bad behavior. +/// Generates an overseer that replaces the candidate validation subsystem with our malicious +/// variant. pub(crate) struct BackGarbageCandidate; impl OverseerGen for BackGarbageCandidate { @@ -207,24 +49,16 @@ impl OverseerGen for BackGarbageCandidate { RuntimeClient::Api: ParachainHost + BabeApi + AuthorityDiscoveryApi, Spawner: 'static + SpawnNamed + Clone + Unpin, { - let candidate_validation_config = args.candidate_validation_config.clone(); let spawner = args.spawner.clone(); + let validation_filter = ReplaceValidationResult::new( + FakeCandidateValidation::BackingAndApprovalValid, + FakeCandidateValidationError::InvalidOutputs, + spawner.clone(), + ); prepared_overseer_builder(args)? - .replace_candidate_validation(|cv| { - InterceptedSubsystem::new( - CandidateValidationSubsystem::with_config( - candidate_validation_config, - cv.metrics, - cv.pvf_metrics, - ), - BribedPassage:: { - inner: Arc::new(Mutex::new(BribedPassageInner { - spawner, - cache: Default::default(), - })), - }, - ) + .replace_candidate_validation(move |cv_subsystem| { + InterceptedSubsystem::new(cv_subsystem, validation_filter) }) .build_with_connector(connector) .map_err(|e| e.into()) From 37849725349eb55b059b3a68b233facc8eed5de6 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Fri, 8 Apr 2022 11:16:46 +0000 Subject: [PATCH 35/47] review feedback Signed-off-by: Andrei Sandu --- node/core/approval-voting/src/lib.rs | 3 +- node/core/approval-voting/src/tests.rs | 2 +- node/core/backing/src/lib.rs | 20 ++---- node/core/candidate-validation/src/lib.rs | 43 ++++++------ .../src/real/participation/mod.rs | 3 +- node/malus/src/shared.rs | 2 +- node/malus/src/variants/common.rs | 65 +++++++++---------- .../src/variants/suggest_garbage_candidate.rs | 10 +-- node/subsystem-types/src/messages.rs | 28 ++++---- 9 files changed, 76 insertions(+), 100 deletions(-) diff --git a/node/core/approval-voting/src/lib.rs b/node/core/approval-voting/src/lib.rs index 577befc6cae7..eba4c21e7113 100644 --- a/node/core/approval-voting/src/lib.rs +++ b/node/core/approval-voting/src/lib.rs @@ -2273,11 +2273,10 @@ async fn launch_approval( CandidateValidationMessage::ValidateFromExhaustive( available_data.validation_data, validation_code, - candidate.descriptor.clone(), + candidate.clone(), available_data.pov, APPROVAL_EXECUTION_TIMEOUT, val_tx, - candidate.commitments_hash, ) .into(), ) diff --git a/node/core/approval-voting/src/tests.rs b/node/core/approval-voting/src/tests.rs index c5f34654c69c..0bb6104dae3f 100644 --- a/node/core/approval-voting/src/tests.rs +++ b/node/core/approval-voting/src/tests.rs @@ -2403,7 +2403,7 @@ pub async fn handle_double_assignment_import( assert_eq!(candidate_index, c_index); }, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx, _), + CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx), ) if timeout == APPROVAL_EXECUTION_TIMEOUT => { tx.send(Ok(ValidationResult::Valid(Default::default(), Default::default()))) .unwrap(); diff --git a/node/core/backing/src/lib.rs b/node/core/backing/src/lib.rs index 56655bfe0795..42cb9ffbbf5c 100644 --- a/node/core/backing/src/lib.rs +++ b/node/core/backing/src/lib.rs @@ -41,8 +41,8 @@ use polkadot_node_subsystem_util::{ request_validators, FromJobCommand, JobSender, Validator, }; use polkadot_primitives::v2::{ - BackedCandidate, CandidateCommitments, CandidateDescriptor, CandidateHash, CandidateReceipt, - CollatorId, CommittedCandidateReceipt, CoreIndex, CoreState, Hash, Id as ParaId, SessionIndex, + BackedCandidate, CandidateCommitments, CandidateHash, CandidateReceipt, CollatorId, + CommittedCandidateReceipt, CoreIndex, CoreState, Hash, Id as ParaId, SessionIndex, SigningContext, ValidatorId, ValidatorIndex, ValidatorSignature, ValidityAttestation, }; use polkadot_subsystem::{ @@ -378,19 +378,17 @@ async fn request_pov( async fn request_candidate_validation( sender: &mut JobSender, - candidate: CandidateDescriptor, + candidate_receipt: CandidateReceipt, pov: Arc, - commitments_hash: Hash, ) -> Result { let (tx, rx) = oneshot::channel(); sender .send_message(CandidateValidationMessage::ValidateFromChainState( - candidate, + candidate_receipt, pov, BACKING_EXECUTION_TIMEOUT, tx, - commitments_hash, )) .await; @@ -452,21 +450,13 @@ async fn validate_and_make_available( }, }; - let expected_commitments_hash = candidate.commitments_hash; - let v = { let _span = span.as_ref().map(|s| { s.child("request-validation") .with_pov(&pov) .with_para_id(candidate.descriptor().para_id) }); - request_candidate_validation( - &mut sender, - candidate.descriptor.clone(), - pov.clone(), - expected_commitments_hash, - ) - .await? + request_candidate_validation(&mut sender, candidate.clone(), pov.clone()).await? }; let res = match v { diff --git a/node/core/candidate-validation/src/lib.rs b/node/core/candidate-validation/src/lib.rs index 4604f29a59e3..1174a1357d94 100644 --- a/node/core/candidate-validation/src/lib.rs +++ b/node/core/candidate-validation/src/lib.rs @@ -41,7 +41,7 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_util::metrics::{self, prometheus}; use polkadot_parachain::primitives::{ValidationParams, ValidationResult as WasmValidationResult}; use polkadot_primitives::v2::{ - CandidateCommitments, CandidateDescriptor, Hash, OccupiedCoreAssumption, + CandidateCommitments, CandidateDescriptor, CandidateReceipt, Hash, OccupiedCoreAssumption, PersistedValidationData, ValidationCode, ValidationCodeHash, }; @@ -134,11 +134,10 @@ where FromOverseer::Signal(OverseerSignal::Conclude) => return Ok(()), FromOverseer::Communication { msg } => match msg { CandidateValidationMessage::ValidateFromChainState( - descriptor, + candidate_receipt, pov, timeout, response_sender, - commitments_hash, ) => { let bg = { let mut sender = ctx.sender().clone(); @@ -150,11 +149,10 @@ where let res = validate_from_chain_state( &mut sender, validation_host, - descriptor, + candidate_receipt, pov, timeout, &metrics, - commitments_hash, ) .await; @@ -168,11 +166,10 @@ where CandidateValidationMessage::ValidateFromExhaustive( persisted_validation_data, validation_code, - descriptor, + candidate_receipt, pov, timeout, response_sender, - commitments_hash, ) => { let bg = { let metrics = metrics.clone(); @@ -184,11 +181,10 @@ where validation_host, persisted_validation_data, validation_code, - descriptor, + candidate_receipt, pov, timeout, &metrics, - commitments_hash, ) .await; @@ -442,18 +438,17 @@ where async fn validate_from_chain_state( sender: &mut Sender, validation_host: ValidationHost, - descriptor: CandidateDescriptor, + candidate_receipt: CandidateReceipt, pov: Arc, timeout: Duration, metrics: &Metrics, - commitments_hash: Hash, ) -> Result where Sender: SubsystemSender, { let mut new_sender = sender.clone(); let (validation_data, validation_code) = - match find_validation_data(&mut new_sender, &descriptor).await? { + match find_validation_data(&mut new_sender, &candidate_receipt.descriptor).await? { Some((validation_data, validation_code)) => (validation_data, validation_code), None => return Ok(ValidationResult::Invalid(InvalidCandidate::BadParent)), }; @@ -462,25 +457,28 @@ where validation_host, validation_data, validation_code, - descriptor.clone(), + candidate_receipt.clone(), pov, timeout, metrics, - commitments_hash, ) .await; if let Ok(ValidationResult::Valid(ref outputs, _)) = validation_result { // If validation produces new commitments we consider the candidate invalid. - if commitments_hash != outputs.hash() { + if candidate_receipt.commitments_hash != outputs.hash() { return Ok(ValidationResult::Invalid(InvalidCandidate::ComittmentsHashMismatch)) } let (tx, rx) = oneshot::channel(); match runtime_api_request( sender, - descriptor.relay_parent, - RuntimeApiRequest::CheckValidationOutputs(descriptor.para_id, outputs.clone(), tx), + candidate_receipt.descriptor.relay_parent, + RuntimeApiRequest::CheckValidationOutputs( + candidate_receipt.descriptor.para_id, + outputs.clone(), + tx, + ), rx, ) .await @@ -499,11 +497,10 @@ async fn validate_candidate_exhaustive( mut validation_backend: impl ValidationBackend, persisted_validation_data: PersistedValidationData, validation_code: ValidationCode, - descriptor: CandidateDescriptor, + candidate_receipt: CandidateReceipt, pov: Arc, timeout: Duration, metrics: &Metrics, - commitments_hash: Hash, ) -> Result { let _timer = metrics.time_validate_candidate_exhaustive(); @@ -511,12 +508,12 @@ async fn validate_candidate_exhaustive( gum::debug!( target: LOG_TARGET, ?validation_code_hash, - para_id = ?descriptor.para_id, + para_id = ?candidate_receipt.descriptor.para_id, "About to validate a candidate.", ); if let Err(e) = perform_basic_checks( - &descriptor, + &candidate_receipt.descriptor, persisted_validation_data.max_pov_size, &*pov, &validation_code_hash, @@ -582,7 +579,7 @@ async fn validate_candidate_exhaustive( Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError(e))), Ok(res) => - if res.head_data.hash() != descriptor.para_head { + if res.head_data.hash() != candidate_receipt.descriptor.para_head { Ok(ValidationResult::Invalid(InvalidCandidate::ParaHeadHashMismatch)) } else { let outputs = CandidateCommitments { @@ -593,7 +590,7 @@ async fn validate_candidate_exhaustive( processed_downward_messages: res.processed_downward_messages, hrmp_watermark: res.hrmp_watermark, }; - if commitments_hash != outputs.hash() { + if candidate_receipt.commitments_hash != outputs.hash() { // If validation produced a new set of commitments, we treat the candidate as invalid. Ok(ValidationResult::Invalid(InvalidCandidate::ComittmentsHashMismatch)) } else { diff --git a/node/core/dispute-coordinator/src/real/participation/mod.rs b/node/core/dispute-coordinator/src/real/participation/mod.rs index fd1ccf06ed19..7f43a22b11cb 100644 --- a/node/core/dispute-coordinator/src/real/participation/mod.rs +++ b/node/core/dispute-coordinator/src/real/participation/mod.rs @@ -362,11 +362,10 @@ async fn participate( CandidateValidationMessage::ValidateFromExhaustive( available_data.validation_data, validation_code, - req.candidate_receipt().descriptor.clone(), + req.candidate_receipt().clone(), available_data.pov, APPROVAL_EXECUTION_TIMEOUT, validation_tx, - req.candidate_receipt().commitments_hash, ) .into(), ) diff --git a/node/malus/src/shared.rs b/node/malus/src/shared.rs index 3c1d55d0d88a..123497340ec5 100644 --- a/node/malus/src/shared.rs +++ b/node/malus/src/shared.rs @@ -17,7 +17,7 @@ use futures::prelude::*; use polkadot_node_primitives::SpawnNamed; -pub const MALUS: &str = "MALUS😈😈😈"; +pub const MALUS: &str = "MALUS"; #[allow(unused)] pub(crate) const MALICIOUS_POV: &[u8] = "😈😈pov_looks_valid_to_me😈😈".as_bytes(); diff --git a/node/malus/src/variants/common.rs b/node/malus/src/variants/common.rs index 66b15d85e5d2..8bed137126d1 100644 --- a/node/malus/src/variants/common.rs +++ b/node/malus/src/variants/common.rs @@ -16,24 +16,22 @@ //! Implements common code for nemesis. Currently, only `FakeValidationResult` //! interceptor is implemented. - -#![allow(missing_docs)] - use crate::{ interceptor::*, shared::{MALICIOUS_POV, MALUS}, }; use polkadot_node_core_candidate_validation::find_validation_data; -use polkadot_node_primitives::{InvalidCandidate, PoV, ValidationResult}; +use polkadot_node_primitives::{InvalidCandidate, ValidationResult}; use polkadot_node_subsystem::messages::{CandidateValidationMessage, ValidationFailed}; -use polkadot_primitives::v2::{CandidateCommitments, CandidateDescriptor, PersistedValidationData}; +use polkadot_primitives::v2::{ + CandidateCommitments, CandidateDescriptor, CandidateReceipt, PersistedValidationData, +}; use polkadot_cli::service::SpawnNamed; use futures::channel::oneshot; -use std::sync::Arc; #[derive(clap::ArgEnum, Clone, Copy, Debug, PartialEq)] #[clap(rename_all = "kebab-case")] @@ -130,7 +128,6 @@ where pub fn send_validation_response( &self, candidate_descriptor: CandidateDescriptor, - pov: Arc, subsystem_sender: Sender, response_sender: oneshot::Sender>, ) where @@ -160,7 +157,7 @@ where }), ); let (validation_data, _) = receiver.recv().unwrap(); - create_validation_response(validation_data, candidate_descriptor, pov, response_sender); + create_validation_response(validation_data, candidate_descriptor, response_sender); } } @@ -180,18 +177,20 @@ pub fn create_fake_candidate_commitments( // Create and send validation response. This function needs the persistent validation data. fn create_validation_response( persisted_validation_data: PersistedValidationData, - candidate_descriptor: CandidateDescriptor, - _pov: Arc, + descriptor: CandidateDescriptor, response_sender: oneshot::Sender>, ) { - let result = Ok(ValidationResult::Valid( - create_fake_candidate_commitments(&persisted_validation_data), - persisted_validation_data, - )); + let commitments = create_fake_candidate_commitments(&persisted_validation_data); + + // Craft the new malicious candidate. + let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: commitments.hash() }; + + let result = Ok(ValidationResult::Valid(commitments, persisted_validation_data)); gum::debug!( target: MALUS, - para_id = ?candidate_descriptor.para_id, + para_id = ?candidate_receipt.descriptor.para_id, + candidate_hash = ?candidate_receipt.hash(), "ValidationResult: {:?}", &result ); @@ -199,7 +198,6 @@ fn create_validation_response( response_sender.send(result).unwrap(); } -// TODO: Only fake validation for `MALICIOUS_POV`, otherwise behave normally. impl MessageInterceptor for ReplaceValidationResult where Sender: overseer::SubsystemSender @@ -223,11 +221,10 @@ where CandidateValidationMessage::ValidateFromExhaustive( validation_data, validation_code, - descriptor, + candidate_receipt, pov, timeout, sender, - commitments_hash, ), } => { match self.fake_validation { @@ -239,15 +236,18 @@ where msg: CandidateValidationMessage::ValidateFromExhaustive( validation_data, validation_code, - descriptor, + candidate_receipt, pov, timeout, sender, - commitments_hash, ), }) } - create_validation_response(validation_data, descriptor, pov, sender); + create_validation_response( + validation_data, + candidate_receipt.descriptor, + sender, + ); None }, FakeCandidateValidation::ApprovalInvalid | @@ -255,9 +255,9 @@ where let validation_result = ValidationResult::Invalid(InvalidCandidate::InvalidOutputs); - gum::info!( + gum::debug!( target: MALUS, - para_id = ?descriptor.para_id, + para_id = ?candidate_receipt.descriptor.para_id, "ValidateFromExhaustive result: {:?}", &validation_result ); @@ -269,11 +269,10 @@ where msg: CandidateValidationMessage::ValidateFromExhaustive( validation_data, validation_code, - descriptor, + candidate_receipt, pov, timeout, sender, - commitments_hash, ), }), } @@ -281,11 +280,10 @@ where FromOverseer::Communication { msg: CandidateValidationMessage::ValidateFromChainState( - descriptor, + candidate_receipt, pov, timeout, response_sender, - commitments_hash, ), } => { match self.fake_validation { @@ -295,17 +293,15 @@ where if pov.block_data.0.as_slice() != MALICIOUS_POV { return Some(FromOverseer::Communication { msg: CandidateValidationMessage::ValidateFromChainState( - descriptor, + candidate_receipt, pov, timeout, response_sender, - commitments_hash, ), }) } self.send_validation_response( - descriptor, - pov, + candidate_receipt.descriptor, subsystem_sender.clone(), response_sender, ); @@ -315,9 +311,9 @@ where FakeCandidateValidation::BackingAndApprovalInvalid => { let validation_result = ValidationResult::Invalid(self.fake_validation_error.clone().into()); - gum::info!( + gum::debug!( target: MALUS, - para_id = ?descriptor.para_id, + para_id = ?candidate_receipt.descriptor.para_id, "ValidateFromChainState result: {:?}", &validation_result ); @@ -328,11 +324,10 @@ where }, _ => Some(FromOverseer::Communication { msg: CandidateValidationMessage::ValidateFromChainState( - descriptor, + candidate_receipt, pov, timeout, response_sender, - commitments_hash, ), }), } diff --git a/node/malus/src/variants/suggest_garbage_candidate.rs b/node/malus/src/variants/suggest_garbage_candidate.rs index 1f893621c1ee..af8191fe10a5 100644 --- a/node/malus/src/variants/suggest_garbage_candidate.rs +++ b/node/malus/src/variants/suggest_garbage_candidate.rs @@ -90,7 +90,7 @@ where FromOverseer::Communication { msg: CandidateBackingMessage::Second(relay_parent, candidate, _pov), } => { - gum::info!( + gum::debug!( target: MALUS, candidate_hash = ?candidate.hash(), ?relay_parent, @@ -106,14 +106,14 @@ where "malus-get-validation-data", Some("malus"), Box::pin(async move { - gum::info!(target: MALUS, "Requesting validators"); + gum::trace!(target: MALUS, "Requesting validators"); let n_validators = request_validators(relay_parent, &mut new_sender) .await .await .unwrap() .unwrap() .len(); - gum::info!(target: MALUS, "Validators {}", n_validators); + gum::trace!(target: MALUS, "Validators {}", n_validators); match find_validation_data(&mut new_sender, &_candidate.descriptor()).await { Ok(Some((validation_data, validation_code))) => { @@ -134,7 +134,7 @@ where let validation_code_hash = validation_code.hash(); let validation_data_relay_parent_number = validation_data.relay_parent_number; - gum::info!( + gum::trace!( target: MALUS, candidate_hash = ?candidate.hash(), ?relay_parent, @@ -193,7 +193,7 @@ where }; let malicious_candidate_hash = malicious_candidate.hash(); - gum::info!( + gum::debug!( target: MALUS, candidate_hash = ?candidate.hash(), ?malicious_candidate_hash, diff --git a/node/subsystem-types/src/messages.rs b/node/subsystem-types/src/messages.rs index ad9075cd1b35..69b2baf0af12 100644 --- a/node/subsystem-types/src/messages.rs +++ b/node/subsystem-types/src/messages.rs @@ -39,13 +39,13 @@ use polkadot_node_primitives::{ SignedFullStatement, ValidationResult, }; use polkadot_primitives::v2::{ - AuthorityDiscoveryId, BackedCandidate, BlockNumber, CandidateDescriptor, CandidateEvent, - CandidateHash, CandidateIndex, CandidateReceipt, CollatorId, CommittedCandidateReceipt, - CoreState, GroupIndex, GroupRotationInfo, Hash, Header as BlockHeader, Id as ParaId, - InboundDownwardMessage, InboundHrmpMessage, MultiDisputeStatementSet, OccupiedCoreAssumption, - PersistedValidationData, PvfCheckStatement, SessionIndex, SessionInfo, - SignedAvailabilityBitfield, SignedAvailabilityBitfields, ValidationCode, ValidationCodeHash, - ValidatorId, ValidatorIndex, ValidatorSignature, + AuthorityDiscoveryId, BackedCandidate, BlockNumber, CandidateEvent, CandidateHash, + CandidateIndex, CandidateReceipt, CollatorId, CommittedCandidateReceipt, CoreState, GroupIndex, + GroupRotationInfo, Hash, Header as BlockHeader, Id as ParaId, InboundDownwardMessage, + InboundHrmpMessage, MultiDisputeStatementSet, OccupiedCoreAssumption, PersistedValidationData, + PvfCheckStatement, SessionIndex, SessionInfo, SignedAvailabilityBitfield, + SignedAvailabilityBitfields, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, + ValidatorSignature, }; use polkadot_statement_table::v2::Misbehavior; use std::{ @@ -126,20 +126,18 @@ pub enum CandidateValidationMessage { /// /// This will implicitly attempt to gather the `PersistedValidationData` and `ValidationCode` /// from the runtime API of the chain, based on the `relay_parent` - /// of the `CandidateDescriptor`. + /// of the `CandidateReceipt`. /// /// This will also perform checking of validation outputs against the acceptance criteria. /// /// If there is no state available which can provide this data or the core for /// the para is not free at the relay-parent, an error is returned. ValidateFromChainState( - CandidateDescriptor, + CandidateReceipt, Arc, /// Execution timeout Duration, oneshot::Sender>, - /// Original commitments hash - Hash, ), /// Validate a candidate with provided, exhaustive parameters for validation. /// @@ -153,13 +151,11 @@ pub enum CandidateValidationMessage { ValidateFromExhaustive( PersistedValidationData, ValidationCode, - CandidateDescriptor, + CandidateReceipt, Arc, /// Execution timeout Duration, oneshot::Sender>, - /// Commitments hash - Hash, ), /// Try to compile the given validation code and send back /// the outcome. @@ -178,8 +174,8 @@ impl CandidateValidationMessage { /// If the current variant contains the relay parent hash, return it. pub fn relay_parent(&self) -> Option { match self { - Self::ValidateFromChainState(_, _, _, _, _) => None, - Self::ValidateFromExhaustive(_, _, _, _, _, _, _) => None, + Self::ValidateFromChainState(_, _, _, _) => None, + Self::ValidateFromExhaustive(_, _, _, _, _, _) => None, Self::PreCheck(relay_parent, _, _) => Some(*relay_parent), } } From 991d77f5558d4e86caf2a8f8cd86d00e1682c02c Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Fri, 8 Apr 2022 11:18:11 +0000 Subject: [PATCH 36/47] typo Signed-off-by: Andrei Sandu --- node/core/backing/src/lib.rs | 2 +- node/core/candidate-validation/src/lib.rs | 4 ++-- node/core/dispute-coordinator/src/real/participation/tests.rs | 4 ++-- node/primitives/src/lib.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/node/core/backing/src/lib.rs b/node/core/backing/src/lib.rs index 42cb9ffbbf5c..9e65e6e1ab98 100644 --- a/node/core/backing/src/lib.rs +++ b/node/core/backing/src/lib.rs @@ -491,7 +491,7 @@ async fn validate_and_make_available( }, } }, - ValidationResult::Invalid(InvalidCandidate::ComittmentsHashMismatch) => { + ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch) => { // If validation produces a new set of commitments, we vote the candidate as invalid. gum::warn!( target: LOG_TARGET, diff --git a/node/core/candidate-validation/src/lib.rs b/node/core/candidate-validation/src/lib.rs index 1174a1357d94..74e49990ba16 100644 --- a/node/core/candidate-validation/src/lib.rs +++ b/node/core/candidate-validation/src/lib.rs @@ -467,7 +467,7 @@ where if let Ok(ValidationResult::Valid(ref outputs, _)) = validation_result { // If validation produces new commitments we consider the candidate invalid. if candidate_receipt.commitments_hash != outputs.hash() { - return Ok(ValidationResult::Invalid(InvalidCandidate::ComittmentsHashMismatch)) + return Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch)) } let (tx, rx) = oneshot::channel(); @@ -592,7 +592,7 @@ async fn validate_candidate_exhaustive( }; if candidate_receipt.commitments_hash != outputs.hash() { // If validation produced a new set of commitments, we treat the candidate as invalid. - Ok(ValidationResult::Invalid(InvalidCandidate::ComittmentsHashMismatch)) + Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch)) } else { Ok(ValidationResult::Valid(outputs, persisted_validation_data)) } diff --git a/node/core/dispute-coordinator/src/real/participation/tests.rs b/node/core/dispute-coordinator/src/real/participation/tests.rs index d4c611d5ebda..b6c3433eac08 100644 --- a/node/core/dispute-coordinator/src/real/participation/tests.rs +++ b/node/core/dispute-coordinator/src/real/participation/tests.rs @@ -122,7 +122,7 @@ pub async fn participation_full_happy_path( CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx, commitments_hash) ) if timeout == APPROVAL_EXECUTION_TIMEOUT => { if expected_commitments_hash != commitments_hash { - tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::ComittmentsHashMismatch))).unwrap(); + tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch))).unwrap(); } else { tx.send(Ok(ValidationResult::Valid(dummy_candidate_commitments(None), PersistedValidationData::default()))).unwrap(); } @@ -466,7 +466,7 @@ fn cast_invalid_vote_if_commitments_dont_match() { AllMessages::CandidateValidation( CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx, _) ) if timeout == APPROVAL_EXECUTION_TIMEOUT => { - tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::ComittmentsHashMismatch))).unwrap(); + tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch))).unwrap(); }, "overseer did not receive candidate validation message", ); diff --git a/node/primitives/src/lib.rs b/node/primitives/src/lib.rs index 612d7fd9df6a..989d06517b01 100644 --- a/node/primitives/src/lib.rs +++ b/node/primitives/src/lib.rs @@ -237,7 +237,7 @@ pub enum InvalidCandidate { /// Validation code hash does not match. CodeHashMismatch, /// Validation has generated different candidate commitments. - ComittmentsHashMismatch, + CommitmentsHashMismatch, } /// Result of the validation of the candidate. From 0fa58908272f402c1f229e3a645c42aa635496f4 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Fri, 8 Apr 2022 11:49:39 +0000 Subject: [PATCH 37/47] tests review feedback Signed-off-by: Andrei Sandu --- node/core/candidate-validation/src/tests.rs | 81 +++++++++++++++++---- 1 file changed, 67 insertions(+), 14 deletions(-) diff --git a/node/core/candidate-validation/src/tests.rs b/node/core/candidate-validation/src/tests.rs index 919cb8912b0c..b896a9f7f3d1 100644 --- a/node/core/candidate-validation/src/tests.rs +++ b/node/core/candidate-validation/src/tests.rs @@ -415,15 +415,16 @@ fn candidate_validation_ok_is_ok() { hrmp_watermark: validation_result.hrmp_watermark, }; + let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: commitments.hash() }; + let v = executor::block_on(validate_candidate_exhaustive( MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), validation_data.clone(), validation_code, - descriptor, + candidate_receipt, Arc::new(pov), Duration::from_secs(0), &Default::default(), - commitments.hash(), )) .unwrap(); @@ -463,17 +464,18 @@ fn candidate_validation_bad_return_is_invalid() { ); assert!(check.is_ok()); + let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; + let v = executor::block_on(validate_candidate_exhaustive( MockValidateCandidateBackend::with_hardcoded_result(Err( ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath), )), validation_data, validation_code, - descriptor, + candidate_receipt, Arc::new(pov), Duration::from_secs(0), &Default::default(), - Hash::zero(), )) .unwrap(); @@ -506,22 +508,69 @@ fn candidate_validation_timeout_is_internal_error() { ); assert!(check.is_ok()); + let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; + let v = executor::block_on(validate_candidate_exhaustive( MockValidateCandidateBackend::with_hardcoded_result(Err( ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout), )), validation_data, validation_code, - descriptor, + candidate_receipt, Arc::new(pov), Duration::from_secs(0), &Default::default(), - Hash::zero(), )); assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::Timeout))); } +#[test] +fn candidate_validation_commitment_hash_mismatch_is_invalid() { + let validation_data = PersistedValidationData { max_pov_size: 1024, ..Default::default() }; + let pov = PoV { block_data: BlockData(vec![0xff; 32]) }; + let validation_code = ValidationCode(vec![0xff; 16]); + let head_data = HeadData(vec![1, 1, 1]); + + let candidate_receipt = CandidateReceipt { + descriptor: make_valid_candidate_descriptor( + 1.into(), + validation_data.parent_head.hash(), + validation_data.hash(), + pov.hash(), + validation_code.hash(), + head_data.hash(), + dummy_hash(), + Sr25519Keyring::Alice, + ), + commitments_hash: Hash::zero(), + }; + + // This will result in different commitments for this candidate. + let validation_result = WasmValidationResult { + head_data, + new_validation_code: None, + upward_messages: Vec::new(), + horizontal_messages: Vec::new(), + processed_downward_messages: 0, + hrmp_watermark: 12345, + }; + + let result = executor::block_on(validate_candidate_exhaustive( + MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), + validation_data, + validation_code, + candidate_receipt, + Arc::new(pov), + Duration::from_secs(0), + &Default::default(), + )) + .unwrap(); + + // Ensure `post validation` check on the commitments hash works as expected. + assert_matches!(result, ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch)); +} + #[test] fn candidate_validation_code_mismatch_is_invalid() { let validation_data = PersistedValidationData { max_pov_size: 1024, ..Default::default() }; @@ -548,17 +597,18 @@ fn candidate_validation_code_mismatch_is_invalid() { ); assert_matches!(check, Err(InvalidCandidate::CodeHashMismatch)); + let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; + let v = executor::block_on(validate_candidate_exhaustive( MockValidateCandidateBackend::with_hardcoded_result(Err( ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout), )), validation_data, validation_code, - descriptor, + candidate_receipt, Arc::new(pov), Duration::from_secs(0), &Default::default(), - Hash::zero(), )) .unwrap(); @@ -605,15 +655,16 @@ fn compressed_code_works() { hrmp_watermark: validation_result.hrmp_watermark, }; + let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: commitments.hash() }; + let v = executor::block_on(validate_candidate_exhaustive( MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), validation_data, validation_code, - descriptor, + candidate_receipt, Arc::new(pov), Duration::from_secs(0), &Default::default(), - commitments.hash(), )); assert_matches!(v, Ok(ValidationResult::Valid(_, _))); @@ -651,15 +702,16 @@ fn code_decompression_failure_is_invalid() { hrmp_watermark: 0, }; + let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; + let v = executor::block_on(validate_candidate_exhaustive( MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), validation_data, validation_code, - descriptor, + candidate_receipt, Arc::new(pov), Duration::from_secs(0), &Default::default(), - Hash::zero(), )); assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::CodeDecompressionFailure))); @@ -698,15 +750,16 @@ fn pov_decompression_failure_is_invalid() { hrmp_watermark: 0, }; + let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; + let v = executor::block_on(validate_candidate_exhaustive( MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), validation_data, validation_code, - descriptor, + candidate_receipt, Arc::new(pov), Duration::from_secs(0), &Default::default(), - Hash::zero(), )); assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::PoVDecompressionFailure))); From 71c35a950da97ccccd54eb28b3d0f5a7459832de Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Fri, 8 Apr 2022 12:24:12 +0000 Subject: [PATCH 38/47] refactor disputer Signed-off-by: Andrei Sandu --- .../src/variants/dispute_valid_candidates.rs | 64 +------------------ 1 file changed, 2 insertions(+), 62 deletions(-) diff --git a/node/malus/src/variants/dispute_valid_candidates.rs b/node/malus/src/variants/dispute_valid_candidates.rs index 4098f2706fa1..63a99e7df441 100644 --- a/node/malus/src/variants/dispute_valid_candidates.rs +++ b/node/malus/src/variants/dispute_valid_candidates.rs @@ -34,12 +34,7 @@ use polkadot_cli::{ // Filter wrapping related types. use super::common::{FakeCandidateValidation, FakeCandidateValidationError}; -use crate::{interceptor::*, shared::MALUS, variants::ReplaceValidationResult}; - -// Import extra types relevant to the particular subsystem. -use polkadot_node_subsystem::messages::{ - ApprovalDistributionMessage, CandidateBackingMessage, DisputeCoordinatorMessage, -}; +use crate::{interceptor::*, variants::ReplaceValidationResult}; use std::sync::Arc; @@ -50,7 +45,7 @@ pub struct DisputeAncestorOptions { /// Malicious candidate validation subsystem configuration. When enabled, node PVF execution is skipped /// during backing and/or approval and it's result can by specified by this option and `--fake-validation-error` /// for invalid candidate outcomes. - #[clap(long, arg_enum, ignore_case = true, default_value_t = FakeCandidateValidation::Disabled)] + #[clap(long, arg_enum, ignore_case = true, default_value_t = FakeCandidateValidation::BackingAndApprovalInvalid)] pub fake_validation: FakeCandidateValidation, /// Applies only when `--fake-validation` is configured to reject candidates as invalid. It allows @@ -62,59 +57,6 @@ pub struct DisputeAncestorOptions { pub cmd: RunCmd, } -/// Replace outgoing approval messages with disputes. -#[derive(Clone, Debug)] -struct ReplaceApprovalsWithDisputes; - -impl MessageInterceptor for ReplaceApprovalsWithDisputes -where - Sender: overseer::SubsystemSender + Clone + Send + 'static, -{ - type Message = CandidateBackingMessage; - - fn intercept_incoming( - &self, - _sender: &mut Sender, - msg: FromOverseer, - ) -> Option> { - Some(msg) - } - - fn intercept_outgoing(&self, msg: AllMessages) -> Option { - match msg { - AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeApproval( - _, - )) => { - // drop the message on the floor - None - }, - AllMessages::DisputeCoordinator(DisputeCoordinatorMessage::ImportStatements { - candidate_hash, - candidate_receipt, - session, - .. - }) => { - gum::info!( - target: MALUS, - para_id = ?candidate_receipt.descriptor.para_id, - ?candidate_hash, - "Disputing candidate", - ); - // this would also dispute candidates we were not assigned to approve - Some(AllMessages::DisputeCoordinator( - DisputeCoordinatorMessage::IssueLocalStatement( - session, - candidate_hash, - candidate_receipt, - false, - ), - )) - }, - msg => Some(msg), - } - } -} - pub(crate) struct DisputeValidCandidates { /// Fake validation config (applies to disputes as well). opts: DisputeAncestorOptions, @@ -138,7 +80,6 @@ impl OverseerGen for DisputeValidCandidates { Spawner: 'static + SpawnNamed + Clone + Unpin, { let spawner = args.spawner.clone(); - let backing_filter = ReplaceApprovalsWithDisputes; let validation_filter = ReplaceValidationResult::new( self.opts.fake_validation, self.opts.fake_validation_error, @@ -146,7 +87,6 @@ impl OverseerGen for DisputeValidCandidates { ); prepared_overseer_builder(args)? - .replace_candidate_backing(move |cb| InterceptedSubsystem::new(cb, backing_filter)) .replace_candidate_validation(move |cv_subsystem| { InterceptedSubsystem::new(cv_subsystem, validation_filter) }) From fee4722821df3ea0175ae7217d4d20b7ae130c93 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Fri, 8 Apr 2022 14:32:56 +0000 Subject: [PATCH 39/47] fix tests Signed-off-by: Andrei Sandu --- node/core/backing/src/tests.rs | 33 +++++++------------ .../src/real/participation/tests.rs | 12 +++---- node/overseer/examples/minimal-example.rs | 10 ++++-- node/overseer/src/tests.rs | 20 +++++++---- 4 files changed, 39 insertions(+), 36 deletions(-) diff --git a/node/core/backing/src/tests.rs b/node/core/backing/src/tests.rs index 6cc18b950f56..0ae2ff840888 100644 --- a/node/core/backing/src/tests.rs +++ b/node/core/backing/src/tests.rs @@ -24,7 +24,8 @@ use futures::{future, Future}; use polkadot_node_primitives::{BlockData, InvalidCandidate}; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_primitives::v2::{ - CollatorId, GroupRotationInfo, HeadData, PersistedValidationData, ScheduledCore, + CandidateDescriptor, CollatorId, GroupRotationInfo, HeadData, PersistedValidationData, + ScheduledCore, }; use polkadot_subsystem::{ messages::{ @@ -332,13 +333,12 @@ fn backing_second_works() { virtual_overseer.recv().await, AllMessages::CandidateValidation( CandidateValidationMessage::ValidateFromChainState( - c, + candidate_receipt, pov, timeout, tx, - commitments_hash ) - ) if pov == pov && &c == candidate.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && commitments_hash == candidate.commitments.hash() => { + ) if pov == pov && &candidate_receipt.descriptor == candidate.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && candidate.commitments.hash() == candidate_receipt.commitments_hash => { tx.send(Ok( ValidationResult::Valid(CandidateCommitments { head_data: expected_head_data.clone(), @@ -499,9 +499,8 @@ fn backing_works() { pov, timeout, tx, - hash ) - ) if pov == pov && &c == candidate_a.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && hash == candidate_a_commitments_hash=> { + ) if pov == pov && c.descriptor() == candidate_a.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && c.commitments_hash == candidate_a_commitments_hash=> { tx.send(Ok( ValidationResult::Valid(CandidateCommitments { head_data: expected_head_data.clone(), @@ -696,9 +695,8 @@ fn backing_works_while_validation_ongoing() { pov, timeout, tx, - hash ) - ) if pov == pov && &c == candidate_a.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && candidate_a_commitments_hash == hash => { + ) if pov == pov && c.descriptor() == candidate_a.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && candidate_a_commitments_hash == c.commitments_hash => { // we never validate the candidate. our local node // shouldn't issue any statements. std::mem::forget(tx); @@ -873,9 +871,8 @@ fn backing_misbehavior_works() { pov, timeout, tx, - hash ) - ) if pov == pov && &c == candidate_a.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && candidate_a_commitments_hash == hash => { + ) if pov == pov && c.descriptor() == candidate_a.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && candidate_a_commitments_hash == c.commitments_hash => { tx.send(Ok( ValidationResult::Valid(CandidateCommitments { head_data: expected_head_data.clone(), @@ -1034,9 +1031,8 @@ fn backing_dont_second_invalid() { pov, timeout, tx, - _ ) - ) if pov == pov && &c == candidate_a.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT => { + ) if pov == pov && c.descriptor() == candidate_a.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT => { tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::BadReturn))).unwrap(); } ); @@ -1064,9 +1060,8 @@ fn backing_dont_second_invalid() { pov, timeout, tx, - _ ) - ) if pov == pov && &c == candidate_b.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT => { + ) if pov == pov && c.descriptor() == candidate_b.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT => { tx.send(Ok( ValidationResult::Valid(CandidateCommitments { head_data: expected_head_data.clone(), @@ -1196,9 +1191,8 @@ fn backing_second_after_first_fails_works() { pov, timeout, tx, - hash ) - ) if pov == pov && &c == candidate.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && hash == candidate.commitments.hash() => { + ) if pov == pov && c.descriptor() == candidate.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && c.commitments_hash == candidate.commitments.hash() => { tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::BadReturn))).unwrap(); } ); @@ -1245,7 +1239,6 @@ fn backing_second_after_first_fails_works() { pov, _, _, - _, ) ) => { assert_eq!(&*pov, &pov_to_second); @@ -1332,9 +1325,8 @@ fn backing_works_after_failed_validation() { pov, timeout, tx, - hash ) - ) if pov == pov && &c == candidate.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && hash == candidate.commitments.hash() => { + ) if pov == pov && c.descriptor() == candidate.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && c.commitments_hash == candidate.commitments.hash() => { tx.send(Err(ValidationFailed("Internal test error".into()))).unwrap(); } ); @@ -1711,9 +1703,8 @@ fn retry_works() { pov, timeout, _tx, - hash, ) - ) if pov == pov && &c == candidate.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && hash == candidate.commitments.hash() + ) if pov == pov && c.descriptor() == candidate.descriptor() && timeout == BACKING_EXECUTION_TIMEOUT && c.commitments_hash == candidate.commitments.hash() ); virtual_overseer }); diff --git a/node/core/dispute-coordinator/src/real/participation/tests.rs b/node/core/dispute-coordinator/src/real/participation/tests.rs index b6c3433eac08..d0b38eccbcbd 100644 --- a/node/core/dispute-coordinator/src/real/participation/tests.rs +++ b/node/core/dispute-coordinator/src/real/participation/tests.rs @@ -119,9 +119,9 @@ pub async fn participation_full_happy_path( assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx, commitments_hash) + CandidateValidationMessage::ValidateFromExhaustive(_, _, candidate_receipt, _, timeout, tx) ) if timeout == APPROVAL_EXECUTION_TIMEOUT => { - if expected_commitments_hash != commitments_hash { + if expected_commitments_hash != candidate_receipt.commitments_hash { tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch))).unwrap(); } else { tx.send(Ok(ValidationResult::Valid(dummy_candidate_commitments(None), PersistedValidationData::default()))).unwrap(); @@ -426,7 +426,7 @@ fn cast_invalid_vote_if_validation_fails_or_is_invalid() { assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx, _) + CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx) ) if timeout == APPROVAL_EXECUTION_TIMEOUT => { tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::Timeout))).unwrap(); }, @@ -464,7 +464,7 @@ fn cast_invalid_vote_if_commitments_dont_match() { assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx, _) + CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx) ) if timeout == APPROVAL_EXECUTION_TIMEOUT => { tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch))).unwrap(); }, @@ -502,7 +502,7 @@ fn cast_valid_vote_if_validation_passes() { assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx, _) + CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx) ) if timeout == APPROVAL_EXECUTION_TIMEOUT => { tx.send(Ok(ValidationResult::Valid(dummy_candidate_commitments(None), PersistedValidationData::default()))).unwrap(); }, @@ -541,7 +541,7 @@ fn failure_to_store_available_data_does_not_preclude_participation() { assert_matches!( ctx_handle.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx, _) + CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx) ) if timeout == APPROVAL_EXECUTION_TIMEOUT => { tx.send(Err(ValidationFailed("fail".to_string()))).unwrap(); }, diff --git a/node/overseer/examples/minimal-example.rs b/node/overseer/examples/minimal-example.rs index 0f8d4484418e..fc07672ef4a1 100644 --- a/node/overseer/examples/minimal-example.rs +++ b/node/overseer/examples/minimal-example.rs @@ -33,7 +33,7 @@ use polkadot_overseer::{ gen::{FromOverseer, SpawnedSubsystem}, AllMessages, HeadSupportsParachains, OverseerSignal, SubsystemError, }; -use polkadot_primitives::v2::Hash; +use polkadot_primitives::v2::{CandidateReceipt, Hash}; struct AlwaysSupportsParachains; impl HeadSupportsParachains for AlwaysSupportsParachains { @@ -73,12 +73,16 @@ impl Subsystem1 { Delay::new(Duration::from_secs(1)).await; let (tx, _) = oneshot::channel(); + let candidate_receipt = CandidateReceipt { + descriptor: dummy_candidate_descriptor(dummy_hash()), + commitments_hash: Hash::zero(), + }; + let msg = CandidateValidationMessage::ValidateFromChainState( - dummy_candidate_descriptor(dummy_hash()), + candidate_receipt, PoV { block_data: BlockData(Vec::new()) }.into(), Default::default(), tx, - Hash::zero(), ); ctx.send_message(::AllMessages::from(msg)) .await; diff --git a/node/overseer/src/tests.rs b/node/overseer/src/tests.rs index 88fc1b784821..2e3dca1cf110 100644 --- a/node/overseer/src/tests.rs +++ b/node/overseer/src/tests.rs @@ -29,8 +29,8 @@ use polkadot_node_subsystem_types::{ ActivatedLeaf, LeafStatus, }; use polkadot_primitives::v2::{ - CandidateHash, CollatorPair, InvalidDisputeStatementKind, ValidDisputeStatementKind, - ValidatorIndex, + CandidateHash, CandidateReceipt, CollatorPair, InvalidDisputeStatementKind, + ValidDisputeStatementKind, ValidatorIndex, }; use crate::{ @@ -108,13 +108,17 @@ where let mut c: usize = 0; loop { if c < 10 { + let candidate_receipt = CandidateReceipt { + descriptor: dummy_candidate_descriptor(dummy_hash()), + commitments_hash: Hash::zero(), + }; + let (tx, _) = oneshot::channel(); ctx.send_message(CandidateValidationMessage::ValidateFromChainState( - dummy_candidate_descriptor(dummy_hash()), + candidate_receipt, PoV { block_data: BlockData(Vec::new()) }.into(), Default::default(), tx, - Hash::zero(), )) .await; c += 1; @@ -793,12 +797,16 @@ where fn test_candidate_validation_msg() -> CandidateValidationMessage { let (sender, _) = oneshot::channel(); let pov = Arc::new(PoV { block_data: BlockData(Vec::new()) }); + let candidate_receipt = CandidateReceipt { + descriptor: dummy_candidate_descriptor(dummy_hash()), + commitments_hash: Hash::zero(), + }; + CandidateValidationMessage::ValidateFromChainState( - dummy_candidate_descriptor(dummy_hash()), + candidate_receipt, pov, Duration::default(), sender, - Hash::zero(), ) } From 6fb63d2e11afe543f539dd7e19cf0bebc4b91a0e Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Mon, 11 Apr 2022 09:14:49 +0000 Subject: [PATCH 40/47] Fix zombienet disputes test Signed-off-by: Andrei Sandu --- .../functional/0002-parachains-disputes.toml | 56 +++++-------------- 1 file changed, 13 insertions(+), 43 deletions(-) diff --git a/zombienet_tests/functional/0002-parachains-disputes.toml b/zombienet_tests/functional/0002-parachains-disputes.toml index 8e35ee01f696..016c844eda1c 100644 --- a/zombienet_tests/functional/0002-parachains-disputes.toml +++ b/zombienet_tests/functional/0002-parachains-disputes.toml @@ -2,8 +2,8 @@ timeout = 1000 [relaychain.genesis.runtime.runtime_genesis_config.configuration.config] - max_validators_per_core = 2 - needed_approvals = 2 + max_validators_per_core = 5 + needed_approvals = 8 [relaychain] default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" @@ -18,19 +18,19 @@ requests = { memory = "2G", cpu = "1" } [[relaychain.nodes]] image = "{{MALUS_IMAGE}}" name = "alice" - command = "malus dispute-ancestor" + command = "malus dispute-ancestor --fake-validation approval-invalid -lparachain=debug,MALUS=trace" extra_args = [ "--alice", "-lparachain=debug" ] [[relaychain.nodes]] image = "{{MALUS_IMAGE}}" name = "bob" - command = "malus dispute-ancestor" + command = "malus dispute-ancestor --fake-validation approval-invalid -lparachain=debug,MALUS=trace" extra_args = [ "--bob", "-lparachain=debug"] [[relaychain.nodes]] image = "{{MALUS_IMAGE}}" name = "charlie" - command = "malus dispute-ancestor" + command = "malus dispute-ancestor --fake-validation approval-invalid -lparachain=debug,MALUS=trace" extra_args = [ "--charlie", "-lparachain=debug" ] [[relaychain.nodes]] @@ -53,51 +53,21 @@ requests = { memory = "2G", cpu = "1" } name = "two" extra_args = [ "--two", "-lparachain=debug"] +{% for id in range(2000,2004) %} [[parachains]] -id = 2000 +id = {{id}} addToGenesis = true -genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=1" +genesis_state_generator = "undying-collator export-genesis-state --pov-size={{25000*(id-1999)}} --pvf-complexity={{id - 1999}}" [parachains.collator] image = "{{COL_IMAGE}}" - name = "collator01" - command = "undying-collator" - args = ["-lparachain=debug", "--pov-size=100000", "--pvf-complexity=1", "--parachain-id=2000"] + name = "collator" + command = ".undying-collator" + args = ["-lparachain=debug", "--pov-size={{25000*(id-1999)}}", "--parachain-id={{id}}", "--pvf-complexity={{id - 1999}}"] -[[parachains]] -id = 2001 -addToGenesis = true -genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=2" - - [parachains.collator] - image = "{{COL_IMAGE}}" - name = "collator02" - command = "undying-collator" - args = ["-lparachain=debug", "--pov-size=100000", "--parachain-id=2001", "--pvf-complexity=2"] - -[[parachains]] -id = 2002 -addToGenesis = true -genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=10" - - [parachains.collator] - image = "{{COL_IMAGE}}" - name = "collator03" - command = "undying-collator" - args = ["-lparachain=debug", "--pov-size=100000", "--parachain-id=2002", "--pvf-complexity=10"] - -[[parachains]] -id = 2003 -addToGenesis = true -genesis_state_generator = "undying-collator export-genesis-state --pov-size=20000 --pvf-complexity=1000" - - [parachains.collator] - image = "{{COL_IMAGE}}" - name = "collator04" - command = "undying-collator" - args = ["-lparachain=debug", "--pov-size=20000", "--parachain-id=2003", "--pvf-complexity=1000"] +{% endfor %} [types.Header] number = "u64" parent_hash = "Hash" -post_state = "Hash" \ No newline at end of file +post_state = "Hash" From ab22c59cd4779f2709777a7c2cc496fdb1cd63ef Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Mon, 11 Apr 2022 10:05:26 +0000 Subject: [PATCH 41/47] spellcheck Signed-off-by: Andrei Sandu --- node/malus/src/variants/back_garbage_candidate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/malus/src/variants/back_garbage_candidate.rs b/node/malus/src/variants/back_garbage_candidate.rs index 9bbf7b170130..5ece8cd4bd7b 100644 --- a/node/malus/src/variants/back_garbage_candidate.rs +++ b/node/malus/src/variants/back_garbage_candidate.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see . //! This variant of Malus backs/approves all malicious candidates crafted by -//! `suggest-garbage-candidate` variant and behaves honestly wrt other +//! `suggest-garbage-candidate` variant and behaves honestly with other //! candidates. use polkadot_cli::{ From f67b522f6e8ab6b51d0c97b5548b0b8f862ef2f2 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Mon, 11 Apr 2022 10:17:59 +0000 Subject: [PATCH 42/47] fix Signed-off-by: Andrei Sandu --- zombienet_tests/functional/0002-parachains-disputes.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zombienet_tests/functional/0002-parachains-disputes.toml b/zombienet_tests/functional/0002-parachains-disputes.toml index 8bd40baef1d8..5763f92dde86 100644 --- a/zombienet_tests/functional/0002-parachains-disputes.toml +++ b/zombienet_tests/functional/0002-parachains-disputes.toml @@ -19,13 +19,13 @@ requests = { memory = "2G", cpu = "1" } image = "{{MALUS_IMAGE}}" name = "alice" command = "malus dispute-ancestor --fake-validation approval-invalid" - extra = [ "--alice", " -lparachain=debug,MALUS=trace" ] + args = [ "--alice", " -lparachain=debug,MALUS=trace" ] [[relaychain.nodes]] image = "{{MALUS_IMAGE}}" name = "bob" command = "malus dispute-ancestor --fake-validation approval-invalid" - extra_args = [ "--bob", "-lparachain=debug,MALUS=trace"] + args = [ "--bob", "-lparachain=debug,MALUS=trace"] [[relaychain.nodes]] image = "{{MALUS_IMAGE}}" From 18d4b43a972423c956b2542cc7a92d12f692ede3 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Mon, 11 Apr 2022 10:45:14 +0000 Subject: [PATCH 43/47] rework test Signed-off-by: Andrei Sandu --- .../0003-parachains-bft-disputes.feature | 25 +++++------ .../0003-parachains-bft-disputes.toml | 42 +++++++++---------- 2 files changed, 32 insertions(+), 35 deletions(-) diff --git a/zombienet_tests/functional/0003-parachains-bft-disputes.feature b/zombienet_tests/functional/0003-parachains-bft-disputes.feature index 7e7c9b346681..f3ce05ad7958 100644 --- a/zombienet_tests/functional/0003-parachains-bft-disputes.feature +++ b/zombienet_tests/functional/0003-parachains-bft-disputes.feature @@ -1,5 +1,4 @@ -Description: Test dispute finality lag at BFT threshold. Malus nodes are configured to dispute all candidates -and fake candidate validation (except during backing). +Description: Test dispute finality lag at BFT threshold. Malus nodes are configured to back/approve a garbage candidate. Network: ./0003-parachains-bft-disputes.toml Creds: config @@ -13,12 +12,9 @@ honest-validator-6: is up honest-validator-7: is up honest-validator-8: is up honest-validator-9: is up -honest-validator-10: is up malus-validator-0: is up malus-validator-1: is up malus-validator-2: is up -malus-validator-3: is up -malus-validator-4: is up # Check authority status. honest-validator-0: reports node_roles is 4 @@ -34,17 +30,15 @@ honest-validator-9: reports node_roles is 4 malus-validator-0: reports node_roles is 4 malus-validator-1: reports node_roles is 4 malus-validator-2: reports node_roles is 4 -malus-validator-3: reports node_roles is 4 -malus-validator-4: reports node_roles is 4 -honest-validator-0: parachain 2000 block height is at least 4 within 120 seconds -honest-validator-1: parachain 2001 block height is at least 4 within 120 seconds -honest-validator-2: parachain 2002 block height is at least 4 within 120 seconds -honest-validator-3: parachain 2003 block height is at least 4 within 120 seconds +honest-validator-0: parachain 2000 block height is at least 4 within 180 seconds +honest-validator-1: parachain 2001 block height is at least 4 within 180 seconds +honest-validator-2: parachain 2002 block height is at least 4 within 180 seconds +honest-validator-3: parachain 2003 block height is at least 4 within 180 seconds -# Allow the the chains to make some more progress. -sleep 120 seconds +honest-validator-3: log line contains "reverted due to a bad parachain block" within 180 seconds +sleep 60 seconds honest-validator-0: reports parachain_disputes_finality_lag is lower than 4 honest-validator-1: reports parachain_disputes_finality_lag is lower than 4 @@ -54,4 +48,7 @@ honest-validator-6: reports parachain_disputes_finality_lag is lower than 4 honest-validator-7: reports parachain_disputes_finality_lag is lower than 4 honest-validator-8: reports parachain_disputes_finality_lag is lower than 4 honest-validator-9: reports parachain_disputes_finality_lag is lower than 4 -honest-validator-10: reports parachain_disputes_finality_lag is lower than 4 + +honest-validator-0: reports parachain_candidate_disputes_total is at least 4 within 15 seconds +honest-validator-1: reports parachain_candidate_dispute_concluded{validity="invalid"} is at least 4 within 15 seconds +honest-validator-2: reports parachain_candidate_dispute_concluded{validity="valid"} is 0 within 15 seconds diff --git a/zombienet_tests/functional/0003-parachains-bft-disputes.toml b/zombienet_tests/functional/0003-parachains-bft-disputes.toml index 1f4ce3c8aee4..e6d434ff2c1c 100644 --- a/zombienet_tests/functional/0003-parachains-bft-disputes.toml +++ b/zombienet_tests/functional/0003-parachains-bft-disputes.toml @@ -1,46 +1,46 @@ [settings] timeout = 1000 +bootnode = true [relaychain.genesis.runtime.runtime_genesis_config.configuration.config] max_validators_per_core = 3 - needed_approvals = 10 + needed_approvals = 7 [relaychain] default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" chain = "rococo-local" -chain_spec_command = "polkadot build-spec --chain rococo-local --disable-default-bootnode" +chain_spec_command = "polkadot build-spec --chain rococo-local" +default_command = "polkadot" [relaychain.default_resources] -limits = { memory = "8G", cpu = "2" } +limits = { memory = "4G", cpu = "2" } requests = { memory = "2G", cpu = "1" } - [[relaychain.node_groups]] - image = "{{MALUS_IMAGE}}" - name = "malus-validator" - args = [ "-lparachain=debug" ] - command = "malus --fake-approval-validation=invalid dispute-ancestor" - count = 5 - [[relaychain.node_groups]] name = "honest-validator" - args = [ "-lparachain=debug" ] - count = 11 + count = 10 + args = ["-lparachain=debug,runtime=debug"] + [[relaychain.node_groups]] + image = "{{MALUS_IMAGE}}" + name = "malus-validator" + command = "malus suggest-garbage-candidate -lparachain=debug,MALUS=trace" + args = ["-lparachain=debug,MALUS=trace"] + count = 3 + {% for id in range(2000,2004) %} [[parachains]] id = {{id}} addToGenesis = true -genesis_state_generator = "undying-collator export-genesis-state --pov-size={{(id - 1999)*1000}} --pvf-complexity={{(id - 1999)*10}}" - - [parachains.collator] - name = "collator" - image = "{{COL_IMAGE}}" - command = "undying-collator" - args = ["--pov-size={{(id - 1999)*1000}}", "--pvf-complexity={{(id - 1999)*10}}", "-lparachain=debug", "--parachain-id {{id}}"] - count = 1 +genesis_state_generator = "undying-collator export-genesis-state --pov-size={{10000*(id-1999)}} --pvf-complexity={{id - 1999}}" + [parachains.collator] + image = "{{COL_IMAGE}}" + name = "collator" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size={{10000*(id-1999)}}", "--parachain-id={{id}}", "--pvf-complexity={{id - 1999}}"] {% endfor %} [types.Header] number = "u64" parent_hash = "Hash" -post_state = "Hash" \ No newline at end of file +post_state = "Hash" From b4f1766bbc81b2cb311908afbc16712096a43356 Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Mon, 11 Apr 2022 10:46:20 +0000 Subject: [PATCH 44/47] don't allow failure Signed-off-by: Andrei Sandu --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1f035cd8f68f..b63a301c3660 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -752,7 +752,7 @@ zombienet-tests-bft-disputes-lag: - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh --github-remote-dir="${GH_DIR}" --test="0003-parachains-bft-disputes.feature" - allow_failure: true + allow_failure: false retry: 2 tags: - zombienet-polkadot-integration-test From 61811574d06b34c75d254f53dc3b518f7dc1627a Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Mon, 11 Apr 2022 13:32:05 +0000 Subject: [PATCH 45/47] Fix ui tests Signed-off-by: Andrei Sandu --- .../tests/ui/err-01-duplicate-consumer.stderr | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/node/overseer/overseer-gen/tests/ui/err-01-duplicate-consumer.stderr b/node/overseer/overseer-gen/tests/ui/err-01-duplicate-consumer.stderr index 18ba674324b5..ea67ef7aad5b 100644 --- a/node/overseer/overseer-gen/tests/ui/err-01-duplicate-consumer.stderr +++ b/node/overseer/overseer-gen/tests/ui/err-01-duplicate-consumer.stderr @@ -1,21 +1,21 @@ -error[E0119]: conflicting implementations of trait `std::convert::From` for type `AllMessages` +error[E0119]: conflicting implementations of trait `polkadot_overseer_gen::SubsystemSender` for type `OverseerSubsystemSender` --> tests/ui/err-01-duplicate-consumer.rs:19:1 | 19 | #[overlord(signal=SigSigSig, event=Event, gen=AllMessages, error=OverseerError)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | first implementation here - | conflicting implementation for `AllMessages` + | conflicting implementation for `OverseerSubsystemSender` | = note: this error originates in the attribute macro `overlord` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0119]: conflicting implementations of trait `polkadot_overseer_gen::SubsystemSender` for type `OverseerSubsystemSender` +error[E0119]: conflicting implementations of trait `std::convert::From` for type `AllMessages` --> tests/ui/err-01-duplicate-consumer.rs:19:1 | 19 | #[overlord(signal=SigSigSig, event=Event, gen=AllMessages, error=OverseerError)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | first implementation here - | conflicting implementation for `OverseerSubsystemSender` + | conflicting implementation for `AllMessages` | = note: this error originates in the attribute macro `overlord` (in Nightly builds, run with -Z macro-backtrace for more info) From be49341bea89097ad8694ea928ac046142c2e84b Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Mon, 11 Apr 2022 13:48:29 +0000 Subject: [PATCH 46/47] remove leftovers Signed-off-by: Andrei Sandu --- zombienet_tests/functional/0003-parachains-bft-disputes.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zombienet_tests/functional/0003-parachains-bft-disputes.toml b/zombienet_tests/functional/0003-parachains-bft-disputes.toml index e6d434ff2c1c..3e1cc15e528e 100644 --- a/zombienet_tests/functional/0003-parachains-bft-disputes.toml +++ b/zombienet_tests/functional/0003-parachains-bft-disputes.toml @@ -24,7 +24,7 @@ requests = { memory = "2G", cpu = "1" } [[relaychain.node_groups]] image = "{{MALUS_IMAGE}}" name = "malus-validator" - command = "malus suggest-garbage-candidate -lparachain=debug,MALUS=trace" + command = "malus suggest-garbage-candidate" args = ["-lparachain=debug,MALUS=trace"] count = 3 From 155524cf06083462e94958931af6765601022bcf Mon Sep 17 00:00:00 2001 From: Andrei Sandu Date: Mon, 11 Apr 2022 14:17:45 +0000 Subject: [PATCH 47/47] fix typo Signed-off-by: Andrei Sandu --- zombienet_tests/functional/0002-parachains-disputes.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zombienet_tests/functional/0002-parachains-disputes.toml b/zombienet_tests/functional/0002-parachains-disputes.toml index 5763f92dde86..dc909726bdae 100644 --- a/zombienet_tests/functional/0002-parachains-disputes.toml +++ b/zombienet_tests/functional/0002-parachains-disputes.toml @@ -62,7 +62,7 @@ genesis_state_generator = "undying-collator export-genesis-state --pov-size={{25 [parachains.collator] image = "{{COL_IMAGE}}" name = "collator" - command = ".undying-collator" + command = "undying-collator" args = ["-lparachain=debug", "--pov-size={{25000*(id-1999)}}", "--parachain-id={{id}}", "--pvf-complexity={{id - 1999}}"] {% endfor %}