use clap::Parser;
use color_eyre::eyre;
pub(crate) mod interceptor;
pub(crate) mod shared;
mod variants;
use variants::*;
#[derive(Debug, Parser)]
#[command(about = "Malus - the nemesis of polkadot.", version, rename_all = "kebab-case")]
enum NemesisVariant {
SuggestGarbageCandidate(SuggestGarbageCandidateOptions),
SupportDisabled(SupportDisabledOptions),
BackGarbageCandidate(BackGarbageCandidateOptions),
DisputeAncestor(DisputeAncestorOptions),
DisputeFinalizedCandidates(DisputeFinalizedCandidatesOptions),
SpamStatementRequests(SpamStatementRequestsOptions),
}
#[derive(Debug, Parser)]
#[allow(missing_docs)]
struct MalusCli {
#[command(subcommand)]
pub variant: NemesisVariant,
pub finality_delay: Option<u32>,
}
impl MalusCli {
fn launch(self) -> eyre::Result<()> {
let finality_delay = self.finality_delay;
match self.variant {
NemesisVariant::BackGarbageCandidate(opts) => {
let BackGarbageCandidateOptions { percentage, cli } = opts;
polkadot_cli::run_node(cli, BackGarbageCandidates { percentage }, finality_delay)?
},
NemesisVariant::SuggestGarbageCandidate(opts) => {
let SuggestGarbageCandidateOptions { percentage, cli } = opts;
polkadot_cli::run_node(
cli,
SuggestGarbageCandidates { percentage },
finality_delay,
)?
},
NemesisVariant::SupportDisabled(opts) => {
let SupportDisabledOptions { cli } = opts;
polkadot_cli::run_node(cli, SupportDisabled, finality_delay)?
},
NemesisVariant::DisputeAncestor(opts) => {
let DisputeAncestorOptions {
fake_validation,
fake_validation_error,
percentage,
cli,
} = opts;
polkadot_cli::run_node(
cli,
DisputeValidCandidates { fake_validation, fake_validation_error, percentage },
finality_delay,
)?
},
NemesisVariant::DisputeFinalizedCandidates(opts) => {
let DisputeFinalizedCandidatesOptions { dispute_offset, cli } = opts;
polkadot_cli::run_node(
cli,
DisputeFinalizedCandidates { dispute_offset },
finality_delay,
)?
},
NemesisVariant::SpamStatementRequests(opts) => {
let SpamStatementRequestsOptions { spam_factor, cli } = opts;
polkadot_cli::run_node(cli, SpamStatementRequests { spam_factor }, finality_delay)?
},
}
Ok(())
}
}
fn main() -> eyre::Result<()> {
color_eyre::install()?;
let cli = MalusCli::parse();
cli.launch()?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn subcommand_works() {
let cli = MalusCli::try_parse_from(IntoIterator::into_iter([
"malus",
"dispute-ancestor",
"--bob",
]))
.unwrap();
assert_matches::assert_matches!(cli, MalusCli {
variant: NemesisVariant::DisputeAncestor(run),
..
} => {
assert!(run.cli.run.base.bob);
});
}
#[test]
fn percentage_works_suggest_garbage() {
let cli = MalusCli::try_parse_from(IntoIterator::into_iter([
"malus",
"suggest-garbage-candidate",
"--percentage",
"100",
"--bob",
]))
.unwrap();
assert_matches::assert_matches!(cli, MalusCli {
variant: NemesisVariant::SuggestGarbageCandidate(run),
..
} => {
assert!(run.cli.run.base.bob);
});
}
#[test]
fn percentage_works_dispute_ancestor() {
let cli = MalusCli::try_parse_from(IntoIterator::into_iter([
"malus",
"dispute-ancestor",
"--percentage",
"100",
"--bob",
]))
.unwrap();
assert_matches::assert_matches!(cli, MalusCli {
variant: NemesisVariant::DisputeAncestor(run),
..
} => {
assert!(run.cli.run.base.bob);
});
}
#[test]
fn percentage_works_back_garbage() {
let cli = MalusCli::try_parse_from(IntoIterator::into_iter([
"malus",
"back-garbage-candidate",
"--percentage",
"100",
"--bob",
]))
.unwrap();
assert_matches::assert_matches!(cli, MalusCli {
variant: NemesisVariant::BackGarbageCandidate(run),
..
} => {
assert!(run.cli.run.base.bob);
});
}
#[test]
#[should_panic]
fn validate_range_for_percentage() {
let cli = MalusCli::try_parse_from(IntoIterator::into_iter([
"malus",
"suggest-garbage-candidate",
"--percentage",
"101",
"--bob",
]))
.unwrap();
assert_matches::assert_matches!(cli, MalusCli {
variant: NemesisVariant::DisputeAncestor(run),
..
} => {
assert!(run.cli.run.base.bob);
});
}
#[test]
fn dispute_finalized_candidates_works() {
let cli = MalusCli::try_parse_from(IntoIterator::into_iter([
"malus",
"dispute-finalized-candidates",
"--bob",
]))
.unwrap();
assert_matches::assert_matches!(cli, MalusCli {
variant: NemesisVariant::DisputeFinalizedCandidates(run),
..
} => {
assert!(run.cli.run.base.bob);
});
}
#[test]
fn dispute_finalized_offset_value_works() {
let cli = MalusCli::try_parse_from(IntoIterator::into_iter([
"malus",
"dispute-finalized-candidates",
"--dispute-offset",
"13",
"--bob",
]))
.unwrap();
assert_matches::assert_matches!(cli, MalusCli {
variant: NemesisVariant::DisputeFinalizedCandidates(opts),
..
} => {
assert_eq!(opts.dispute_offset, 13); assert!(opts.cli.run.base.bob);
});
}
}