Skip to content

Commit

Permalink
[test_loop] Refactor utils module in TestLoop (#11700)
Browse files Browse the repository at this point in the history
Add utils module for future extension, will add some utils related to
restarting nodes soon.
  • Loading branch information
shreyan-gupta authored Jul 2, 2024
1 parent b5ea35b commit 62cd774
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 90 deletions.
83 changes: 1 addition & 82 deletions integration-tests/src/test_loop/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ use near_client::{Client, PartialWitnessActor, SyncAdapter};
use near_epoch_manager::shard_tracker::{ShardTracker, TrackedConfig};
use near_epoch_manager::{EpochManager, EpochManagerAdapter};
use near_network::test_loop::TestLoopPeerManagerActor;
use near_network::types::NetworkRequests;
use near_primitives::network::PeerId;
use near_primitives::test_utils::create_test_signer;
use near_primitives::types::AccountId;
Expand All @@ -38,6 +37,7 @@ use nearcore::state_sync::StateSyncDumper;
use tempfile::TempDir;

use super::env::{ClientToShardsManagerSender, TestData, TestLoopChunksStorage, TestLoopEnv};
use super::utils::network::partial_encoded_chunks_dropper;

pub struct TestLoopBuilder {
test_loop: TestLoopV2,
Expand Down Expand Up @@ -84,15 +84,6 @@ impl TestLoopBuilder {
self
}

/// GC should always be enabled, thus this function should only be invoked
/// for debugging a bug that manifest itself when GC is enabled.
#[allow(unused)]
pub fn disable_gc(mut self) -> Self {
self.gc = false;
tracing::warn!("Garbage collection is disabled!");
self
}

/// Build the test loop environment.
pub fn build(self) -> TestLoopEnv {
self.ensure_genesis().ensure_clients().build_impl()
Expand Down Expand Up @@ -387,75 +378,3 @@ impl TestLoopBuilder {
}
}
}

/// Handler to drop all network messages relevant to chunk validated by
/// `validator_of_chunks_to_drop`. If number of nodes on chain is significant
/// enough (at least three?), this is enough to prevent chunk from being
/// included.
///
/// This logic can be easily extended to dropping chunk based on any rule.
pub fn partial_encoded_chunks_dropper(
chunks_storage: Arc<Mutex<TestLoopChunksStorage>>,
epoch_manager_adapter: Arc<dyn EpochManagerAdapter>,
validator_of_chunks_to_drop: AccountId,
) -> Arc<dyn Fn(NetworkRequests) -> Option<NetworkRequests>> {
Arc::new(move |request| {
// Filter out only messages related to distributing chunk in the
// network; extract `chunk_hash` from the message.
let chunk_hash = match &request {
NetworkRequests::PartialEncodedChunkRequest { request, .. } => {
Some(request.chunk_hash.clone())
}
NetworkRequests::PartialEncodedChunkResponse { response, .. } => {
Some(response.chunk_hash.clone())
}
NetworkRequests::PartialEncodedChunkMessage { partial_encoded_chunk, .. } => {
Some(partial_encoded_chunk.header.chunk_hash())
}
NetworkRequests::PartialEncodedChunkForward { forward, .. } => {
Some(forward.chunk_hash.clone())
}
_ => None,
};

let Some(chunk_hash) = chunk_hash else {
return Some(request);
};

let chunk = {
let chunks_storage = chunks_storage.lock().unwrap();
let chunk = chunks_storage.get(&chunk_hash).unwrap().clone();
let can_drop_chunk = chunks_storage.can_drop_chunk(&chunk);

if !can_drop_chunk {
return Some(request);
}

chunk
};

let prev_block_hash = chunk.prev_block_hash();
let shard_id = chunk.shard_id();
let height_created = chunk.height_created();

// If we don't have block on top of which chunk is built, we can't
// retrieve epoch id.
// This case appears to be too rare to interfere with the goal of
// dropping chunk.
let Ok(epoch_id) = epoch_manager_adapter.get_epoch_id_from_prev_block(prev_block_hash)
else {
return Some(request);
};

// Finally, we drop chunk if the given account is present in the list
// of its validators.
let chunk_validators = epoch_manager_adapter
.get_chunk_validator_assignments(&epoch_id, shard_id, height_created)
.unwrap();
if !chunk_validators.contains(&validator_of_chunks_to_drop) {
return Some(request);
}

return None;
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ use near_primitives::types::{AccountId, BlockHeight};

use crate::test_loop::builder::TestLoopBuilder;
use crate::test_loop::env::{TestData, TestLoopEnv};
use crate::test_loop::utils::{call_contract, deploy_contracts, ONE_NEAR};
use crate::test_loop::utils::transactions::{call_contract, deploy_contracts};
use crate::test_loop::utils::ONE_NEAR;

const NUM_PRODUCERS: usize = 2;
const NUM_VALIDATORS: usize = 2;
Expand Down Expand Up @@ -63,7 +64,7 @@ fn test_congestion_control_adv_chunk_produce() {
let genesis = genesis_builder.build();

let TestLoopEnv { mut test_loop, datas: node_datas, tempdir } =
builder.genesis(genesis).clients(clients).disable_gc().build();
builder.genesis(genesis).clients(clients).build();

let first_epoch_tracked_shards = get_tracked_shards(&test_loop, &node_datas);
tracing::info!("First epoch tracked shards: {:?}", first_epoch_tracked_shards);
Expand Down
3 changes: 2 additions & 1 deletion integration-tests/src/test_loop/tests/in_memory_tries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use near_store::ShardUId;

use crate::test_loop::builder::TestLoopBuilder;
use crate::test_loop::env::TestLoopEnv;
use crate::test_loop::utils::{execute_money_transfers, ONE_NEAR};
use crate::test_loop::utils::transactions::execute_money_transfers;
use crate::test_loop::utils::ONE_NEAR;

/// Runs chain with sequence of chunks with empty state changes, long enough to
/// cover 5 epochs which is default GC period.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ use near_primitives::views::CurrentEpochValidatorInfo;

use crate::test_loop::builder::TestLoopBuilder;
use crate::test_loop::env::TestLoopEnv;
use crate::test_loop::utils::{execute_money_transfers, ONE_NEAR};
use crate::test_loop::utils::transactions::execute_money_transfers;
use crate::test_loop::utils::ONE_NEAR;

const NUM_ACCOUNTS: usize = 20;
const NUM_SHARDS: u64 = 4;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use near_primitives::types::AccountId;

use crate::test_loop::builder::TestLoopBuilder;
use crate::test_loop::env::TestLoopEnv;
use crate::test_loop::utils::{execute_money_transfers, ONE_NEAR};
use crate::test_loop::utils::transactions::execute_money_transfers;
use crate::test_loop::utils::ONE_NEAR;

const NUM_CLIENTS: usize = 4;

Expand Down
5 changes: 5 additions & 0 deletions integration-tests/src/test_loop/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub mod network;
pub mod transactions;

pub(crate) const ONE_NEAR: u128 = 1_000_000_000_000_000_000_000_000;
pub(crate) const TGAS: u64 = 1_000_000_000_000;
79 changes: 79 additions & 0 deletions integration-tests/src/test_loop/utils/network.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use std::sync::{Arc, Mutex};

use near_epoch_manager::EpochManagerAdapter;
use near_network::types::NetworkRequests;
use near_primitives::types::AccountId;

use crate::test_loop::env::TestLoopChunksStorage;

/// Handler to drop all network messages relevant to chunk validated by
/// `validator_of_chunks_to_drop`. If number of nodes on chain is significant
/// enough (at least three?), this is enough to prevent chunk from being
/// included.
///
/// This logic can be easily extended to dropping chunk based on any rule.
pub fn partial_encoded_chunks_dropper(
chunks_storage: Arc<Mutex<TestLoopChunksStorage>>,
epoch_manager_adapter: Arc<dyn EpochManagerAdapter>,
validator_of_chunks_to_drop: AccountId,
) -> Arc<dyn Fn(NetworkRequests) -> Option<NetworkRequests>> {
Arc::new(move |request| {
// Filter out only messages related to distributing chunk in the
// network; extract `chunk_hash` from the message.
let chunk_hash = match &request {
NetworkRequests::PartialEncodedChunkRequest { request, .. } => {
Some(request.chunk_hash.clone())
}
NetworkRequests::PartialEncodedChunkResponse { response, .. } => {
Some(response.chunk_hash.clone())
}
NetworkRequests::PartialEncodedChunkMessage { partial_encoded_chunk, .. } => {
Some(partial_encoded_chunk.header.chunk_hash())
}
NetworkRequests::PartialEncodedChunkForward { forward, .. } => {
Some(forward.chunk_hash.clone())
}
_ => None,
};

let Some(chunk_hash) = chunk_hash else {
return Some(request);
};

let chunk = {
let chunks_storage = chunks_storage.lock().unwrap();
let chunk = chunks_storage.get(&chunk_hash).unwrap().clone();
let can_drop_chunk = chunks_storage.can_drop_chunk(&chunk);

if !can_drop_chunk {
return Some(request);
}

chunk
};

let prev_block_hash = chunk.prev_block_hash();
let shard_id = chunk.shard_id();
let height_created = chunk.height_created();

// If we don't have block on top of which chunk is built, we can't
// retrieve epoch id.
// This case appears to be too rare to interfere with the goal of
// dropping chunk.
let Ok(epoch_id) = epoch_manager_adapter.get_epoch_id_from_prev_block(prev_block_hash)
else {
return Some(request);
};

// Finally, we drop chunk if the given account is present in the list
// of its validators.
let chunk_validators = epoch_manager_adapter
.get_chunk_validator_assignments(&epoch_id, shard_id, height_created)
.unwrap();
if !chunk_validators.contains(&validator_of_chunks_to_drop) {
return Some(request);
}

return None;
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ use near_primitives::transaction::SignedTransaction;
use near_primitives::types::AccountId;
use std::collections::HashMap;

pub(crate) const ONE_NEAR: u128 = 1_000_000_000_000_000_000_000_000;

const TGAS: u64 = 1_000_000_000_000;
use super::{ONE_NEAR, TGAS};

/// Execute money transfers within given `TestLoop` between given accounts.
/// Runs chain long enough for the transfers to be optimistically executed.
Expand Down

0 comments on commit 62cd774

Please sign in to comment.