Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
fix order, add dispute-unavailable-block malus
Browse files Browse the repository at this point in the history
  • Loading branch information
drahnr committed Aug 31, 2021
1 parent 970647f commit 139ecf9
Show file tree
Hide file tree
Showing 7 changed files with 236 additions and 8 deletions.
6 changes: 3 additions & 3 deletions node/malus/integrationtests/0001-dispute-valid-block.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@ timeout = 1000

[nodes.alice]
validator = true
extra-args = ["--alice"]
image = "{{get_env(name="SYNTHIMAGE") | safe }}"
command = "polkadot"
extra-args = ["--alice"]

[nodes.bob]
validator = true
extra-args = ["--bob"]
image = "{{get_env(name="SYNTHIMAGE") | safe }}"
command = "polkadot"
extra-args = ["--bob"]

[nodes.charlie]
validator = true
extra-args = ["--charlie"]
image = "{{get_env(name="SYNTHIMAGE") | safe }}"
command = "polkadot"
extra-args = ["--charlie"]

[nodes.david]
validator = true
Expand Down
10 changes: 5 additions & 5 deletions node/malus/integrationtests/0002-dispute-invalid-block.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,30 @@ timeout = 1000

[nodes.alice]
validator = true
extra-args = ["--alice"]
image = "{{get_env(name="SYNTHIMAGE") | safe }}"
command = "polkadot"
extra-args = ["--alice"]

[nodes.bob]
validator = true
extra-args = ["back-garbage-candidate", "--bob"]
image = "{{get_env(name="MALUSIMAGE") | safe }}"
command = "/usr/local/bin/malus"
extra-args = ["back-garbage-candidate", "--bob"]

[nodes.charlie]
validator = true
extra-args = ["back-garbage-candidate", "--charlie"]
image = "{{get_env(name="MALUSIMAGE") | safe }}"
command = "/usr/local/bin/malus"
extra-args = ["back-garbage-candidate", "--charlie"]

[nodes.david]
validator = true
extra-args = ["back-garbage-candidate", "--dave"]
image = "{{get_env(name="MALUSIMAGE") | safe }}"
command = "/usr/local/bin/malus"
extra-args = ["back-garbage-candidate", "--dave"]

[nodes.eve]
validator = true
extra-args = ["suggest-garbage-candidate","--eve"]
image = "{{get_env(name="MALUSIMAGE") | safe }}"
command = "/usr/local/bin/malus"
extra-args = ["suggest-garbage-candidate","--eve"]
24 changes: 24 additions & 0 deletions node/malus/integrationtests/0003-dispute-unavailable-block.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Feature: Disputes

Scenario: Dispute Invalid Block
Given a test network
Then alice is up
And alice reports node_roles is 4
And alice reports sub_libp2p_is_major_syncing is 0
Then sleep 15 seconds
Then alice reports block height is greater than 2
And alice reports peers count is at least 2
Then bob is up
And bob reports block height is greater than 2
And bob reports peers count is at least 2
Then charlie is up
And charlie reports block height is greater than 2
And charlie reports peers count is at least 2
Then david is up
Then eve is up
And alice reports polkadot_parachain_candidate_open_disputes is 1
Then alice polkadot_parachain_candidate_dispute_votes is at least 1
And bob polkadot_parachain_candidate_dispute_votes is is at least 2
And charlie polkadot_parachain_candidate_dispute_votes is at least 3
And david polkadot_parachain_candidate_dispute_votes is at least 4
Then alice polkadot_parachain_candidate_dispute_concluded is "invalid"
35 changes: 35 additions & 0 deletions node/malus/integrationtests/0003-dispute-unavailable-block.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[settings.defaults]
image = "{{get_env(name="SYNTHIMAGE") | safe }}"
command = "polkadot"
chain-name = "polkadot-local"
timeout = 1000

[nodes.alice]
validator = true
image = "{{get_env(name="SYNTHIMAGE") | safe }}"
command = "polkadot"
extra-args = ["--alice"]

[nodes.bob]
validator = true
image = "{{get_env(name="MALUSIMAGE") | safe }}"
command = "/usr/local/bin/malus"
extra-args = ["back-garbage-candidate", "--bob"]

[nodes.charlie]
validator = true
image = "{{get_env(name="MALUSIMAGE") | safe }}"
command = "/usr/local/bin/malus"
extra-args = ["back-garbage-candidate", "--charlie"]

[nodes.david]
validator = true
image = "{{get_env(name="MALUSIMAGE") | safe }}"
command = "/usr/local/bin/malus"
extra-args = ["back-garbage-candidate", "--dave"]

[nodes.eve]
validator = true
image = "{{get_env(name="MALUSIMAGE") | safe }}"
command = "/usr/local/bin/malus"
extra-args = ["suggest-garbage-candidate","--eve"]
3 changes: 3 additions & 0 deletions node/malus/src/malus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ enum NemesisVariant {
BackGarbageCandidate(RunCmd),
/// Delayed disputing of ancestors that are perfectly fine.
DisputeAncestor(RunCmd),
/// Instant disputing of a block that was never made available.
DisputeUnavailable(RunCmd),
}

#[derive(Debug, StructOpt)]
Expand All @@ -56,6 +58,7 @@ impl MalusCli {
NemesisVariant::SuggestGarabageCandidate(run) =>
polkadot_cli::run_node(run, SuggestGarbageCandidate)?,
NemesisVariant::DisputeAncestor(run) => polkadot_cli::run_node(run, DisputeAncestor)?,
NemesisVariant::DisputeUnavailable(run) => polkadot_cli::run_node(run, DisputeUnavailable)?,
}
Ok(())
}
Expand Down
164 changes: 164 additions & 0 deletions node/malus/src/variants/dispute_unavailable_block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
// 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 <http://www.gnu.org/licenses/>.

//! A malicious overseer that always disputes a block as
//! as it is observed.
//!
//! Attention: For usage with `simnet`/`gurke` only!

#![allow(missing_docs)]

use polkadot_cli::{
create_default_subsystems,
service::{
AuthorityDiscoveryApi, AuxStore, BabeApi, Block, Error, HeaderBackend, Overseer,
OverseerGen, OverseerGenArgs, OverseerHandle, ParachainHost, ProvideRuntimeApi, SpawnNamed,
},
};

// Filter wrapping related types.
use crate::{interceptor::*, shared::*};
use polkadot_node_subsystem::overseer::SubsystemSender;

// Import extra types relevant to the particular
// subsystem.
use polkadot_node_core_backing::{CandidateBackingSubsystem, Metrics as CandidateBackingMetrics};
use polkadot_node_subsystem::messages::{CandidateBackingMessage, DisputeCoordinatorMessage};
use polkadot_node_subsystem_util as util;
use polkadot_primitives::v1::CandidateReceipt;
use sp_keystore::SyncCryptoStorePtr;
use util::{metered, metrics::Metrics as _};

use std::sync::Arc;

/// Become Loki and throw in a dispute once in a while, for an unfinalized block.
#[derive(Clone, Debug)]
struct TrackCollations<Sender>
where
Sender: Send,
{
sink: metered::UnboundedMeteredSender<(Sender, CandidateReceipt)>,
}

impl<Sender> MessageInterceptor<Sender> for TrackCollations<Sender>
where
Sender: overseer::SubsystemSender<CandidateBackingMessage> + Clone + Send + 'static,
{
type Message = CandidateBackingMessage;

fn intercept_incoming(
&self,
sender: &mut Sender,
msg: FromOverseer<Self::Message>,
) -> Option<FromOverseer<Self::Message>> {
match msg {
FromOverseer::Communication {
// `DistributeCollation` is only received
// by a _collator_, but we are a validator.
// `CollatorProtocolMessage::DistributeCollation(ref ccr, ref pov, _)` hence
// cannot be used.

// Intercepting [`fn request_collation`](https://github.com/paritytech/polkadot/blob/117466aa8e471562f921a90b69a6c265cb6c656f/node/network/collator-protocol/src/validator_side/mod.rs#L736-L736)
// is bothersome, so we wait for the seconding and
// make that disappear, and instead craft our own message.
msg: CandidateBackingMessage::Second(_, ccr, _),
} => {
self.sink.unbounded_send((sender.clone(), ccr)).unwrap();
None
},
msg => Some(msg),
}
}

fn intercept_outgoing(&self, msg: AllMessages) -> Option<AllMessages> {
Some(msg)
}
}

/// Generates an overseer that disputes every ancestor.
pub(crate) struct DisputeUnavailable;

impl OverseerGen for DisputeUnavailable {
fn generate<'a, Spawner, RuntimeClient>(
&self,
args: OverseerGenArgs<'a, Spawner, RuntimeClient>,
) -> Result<(Overseer<Spawner, Arc<RuntimeClient>>, OverseerHandle), Error>
where
RuntimeClient: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block> + AuxStore,
RuntimeClient::Api: ParachainHost<Block> + BabeApi<Block> + AuthorityDiscoveryApi<Block>,
Spawner: 'static + SpawnNamed + Clone + Unpin,
{
let spawner = args.spawner.clone();
let leaves = args.leaves.clone();
let runtime_client = args.runtime_client.clone();
let registry = args.registry.clone();

let (sink, source) = metered::unbounded();

let coll = TrackCollations { sink };

let metrics = CandidateBackingMetrics::register(registry).unwrap();

let crypto_store_ptr = args.keystore.clone() as SyncCryptoStorePtr;

// modify the subsystem(s) as needed:
let all_subsystems = create_default_subsystems(args)?.replace_candidate_backing(
// create the filtered subsystem
FilteredSubsystem::new(
CandidateBackingSubsystem::new(spawner.clone(), crypto_store_ptr, metrics),
coll,
),
);

let (overseer, handle) =
Overseer::new(leaves, all_subsystems, registry, runtime_client, spawner.clone())?;

launch_processing_task(
&spawner,
source,
|(mut subsystem_sender, candidate_receipt): (_, CandidateReceipt)| async move {
let relay_parent = candidate_receipt.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 candidate_hash = candidate_receipt.hash();

tracing::warn!(
target = MALUS,
"Disputing unvailable block with candidate /w hash {} in session {:?} on relay_parent {}",
candidate_hash,
session_index,
relay_parent,
);

// no delay, dispute right away, before it becomes available

// 😈
let msg = DisputeCoordinatorMessage::IssueLocalStatement(
session_index,
candidate_hash,
candidate_receipt,
false,
);

subsystem_sender.send_message(msg).await;
},
);

Ok((overseer, handle))
}
}
2 changes: 2 additions & 0 deletions node/malus/src/variants/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
mod back_garbage_candidate;
mod dispute_ancestor;
mod suggest_garbage_candidate;
mod dispute_unavailable_block;

pub(crate) use self::{
back_garbage_candidate::BackGarbageCandidate, dispute_ancestor::DisputeAncestor,
suggest_garbage_candidate::SuggestGarbageCandidate,
dispute_unavailable_block::DisputeUnavailable,
};

0 comments on commit 139ecf9

Please sign in to comment.