Skip to content

Commit

Permalink
refactoring: Speed up flipped block test (#12840)
Browse files Browse the repository at this point in the history
This PR makes the test
`ultra_slow_test_check_process_flipped_block_fails` more efficient by
re-using the same test loop environment, instead of initializing a new
`TestEnv` at every iteration.

Locally the test runs 40% faster.
  • Loading branch information
Trisfald authored Jan 31, 2025
1 parent e57cc68 commit abb3842
Showing 1 changed file with 34 additions and 17 deletions.
51 changes: 34 additions & 17 deletions integration-tests/src/tests/client/block_corruption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,19 @@ fn is_breaking_block_change(original: &Block, corrupt: &Block) -> bool {
/// Returns `Ok(reason)` if corrupt block wasn't parsed or had changes that are not breaking by design.
/// Returns `Err(reason)` if corrupt block was processed or correct block wasn't processed afterwards.
fn check_corrupt_block(
mut env: TestEnv,
env: &mut TestEnv,
corrupt_block_vec: Vec<u8>,
correct_block: Block,
corrupted_bit_idx: usize,
) -> Result<anyhow::Error, anyhow::Error> {
macro_rules! process_correct_block {
() => {
if let Err(e) = env.clients[0].process_block_test(correct_block.into(), Provenance::NONE) {
return Err(anyhow::anyhow!("Was unable to process default block after attempting to process default block with {} bit switched. {}", corrupted_bit_idx, e));
}
};
}

if let Ok(mut corrupt_block) = Block::try_from_slice(corrupt_block_vec.as_slice()) {
let body_hash = corrupt_block.compute_block_body_hash().unwrap();
corrupt_block.mut_header().set_block_body_hash(body_hash);
Expand All @@ -136,6 +144,7 @@ fn check_corrupt_block(
));

if !is_breaking_block_change(&correct_block, &corrupt_block) {
process_correct_block!();
return Ok(anyhow::anyhow!(NOT_BREAKING_CHANGE_MSG));
}

Expand All @@ -145,24 +154,20 @@ fn check_corrupt_block(
corrupted_bit_idx
)),
Err(e) => {
if let Err(e) =
env.clients[0].process_block_test(correct_block.into(), Provenance::NONE)
{
return Err(anyhow::anyhow!("Was unable to process default block after attempting to process default block with {} bit switched. {}",
corrupted_bit_idx, e)
);
}
process_correct_block!();
Ok(e.into())
}
}
} else {
process_correct_block!();
return Ok(anyhow::anyhow!(BLOCK_NOT_PARSED_MSG));
}
}

/// Each block contains one 'send' transaction.
/// First three blocks are produced without changes.
/// For the fourth block we are calculating two versions – correct and corrupt.
/// Blocks are produced at heights on top of `last_block_height`.
/// Corrupt block is produced by
/// - serializing correct block
/// - flipping one bit
Expand All @@ -175,17 +180,14 @@ fn check_corrupt_block(
/// Returns `Ok(reason)` if corrupt block wasn't parsed or had changes that are not breaking by design.
/// Returns `Err(reason)` if corrupt block was processed or correct block wasn't processed afterwards.
fn check_process_flipped_block_fails_on_bit(
env: &mut TestEnv,
corrupted_bit_idx: usize,
) -> Result<anyhow::Error, anyhow::Error> {
let epoch_length = 5000000;
let mut genesis = Genesis::test(vec!["test0".parse().unwrap(), "test1".parse().unwrap()], 1);
genesis.config.epoch_length = epoch_length;
let mut env = TestEnv::builder(&genesis.config).nightshade_runtimes(&genesis).build();
let mut last_block = env.clients[0].chain.get_head_block().unwrap();
let last_block_height = last_block.header().height();

let mut last_block = env.clients[0].chain.get_block_by_height(0).unwrap();

let mid_height = 3;
for h in 1..=mid_height {
let mid_height = last_block_height + 3;
for h in last_block_height + 1..=mid_height {
let txs = create_tx_load(h, &last_block);
for tx in txs {
assert_eq!(env.clients[0].process_tx(tx, false, false), ProcessTxResponse::ValidTx);
Expand Down Expand Up @@ -247,8 +249,23 @@ fn ultra_slow_test_check_process_flipped_block_fails() {
// List of reasons `check_process_flipped_block_fails_on_bit` returned `Ok`.
// Should contain various validation errors.
let mut oks = vec![];

let create_env = || {
let mut genesis =
Genesis::test(vec!["test0".parse().unwrap(), "test1".parse().unwrap()], 1);
genesis.config.epoch_length = 5000000;
TestEnv::builder(&genesis.config).nightshade_runtimes(&genesis).build()
};

let mut env = create_env();

loop {
let res = check_process_flipped_block_fails_on_bit(corrupted_bit_idx);
// Reset env once in a while to avoid excessive memory usage.
if corrupted_bit_idx % 1_000 == 0 {
env = create_env();
}

let res = check_process_flipped_block_fails_on_bit(&mut env, corrupted_bit_idx);
if let Ok(res) = &res {
if res.to_string() == "End" {
// `corrupted_bit_idx` is out of bounds for correct block length. Should stop iteration.
Expand Down

0 comments on commit abb3842

Please sign in to comment.