mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-06 18:21:45 +00:00
Enable lints for tests only running optimized (#6664)
* enable linting optimized-only tests * fix automatically fixable or obvious lints * fix suspicious_open_options by removing manual options * fix `await_holding_lock`s * avoid failing lint due to now disabled `#[cfg(debug_assertions)]` * reduce future sizes in tests * fix accidently flipped assert logic * restore holding lock for web3signer download * Merge branch 'unstable' into lint-opt-tests
This commit is contained in:
@@ -322,7 +322,7 @@ pub async fn consensus_gossip() {
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
pub async fn consensus_partial_pass_only_consensus() {
|
||||
/* this test targets gossip-level validation */
|
||||
let validation_level: Option<BroadcastValidation> = Some(BroadcastValidation::Consensus);
|
||||
let validation_level = BroadcastValidation::Consensus;
|
||||
|
||||
// Validator count needs to be at least 32 or proposer boost gets set to 0 when computing
|
||||
// `validator_count // 32`.
|
||||
@@ -378,7 +378,7 @@ pub async fn consensus_partial_pass_only_consensus() {
|
||||
tester.harness.chain.clone(),
|
||||
&channel.0,
|
||||
test_logger,
|
||||
validation_level.unwrap(),
|
||||
validation_level,
|
||||
StatusCode::ACCEPTED,
|
||||
network_globals,
|
||||
)
|
||||
@@ -615,8 +615,7 @@ pub async fn equivocation_gossip() {
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
pub async fn equivocation_consensus_late_equivocation() {
|
||||
/* this test targets gossip-level validation */
|
||||
let validation_level: Option<BroadcastValidation> =
|
||||
Some(BroadcastValidation::ConsensusAndEquivocation);
|
||||
let validation_level = BroadcastValidation::ConsensusAndEquivocation;
|
||||
|
||||
// Validator count needs to be at least 32 or proposer boost gets set to 0 when computing
|
||||
// `validator_count // 32`.
|
||||
@@ -671,7 +670,7 @@ pub async fn equivocation_consensus_late_equivocation() {
|
||||
tester.harness.chain,
|
||||
&channel.0,
|
||||
test_logger,
|
||||
validation_level.unwrap(),
|
||||
validation_level,
|
||||
StatusCode::ACCEPTED,
|
||||
network_globals,
|
||||
)
|
||||
@@ -1228,8 +1227,7 @@ pub async fn blinded_equivocation_gossip() {
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
pub async fn blinded_equivocation_consensus_late_equivocation() {
|
||||
/* this test targets gossip-level validation */
|
||||
let validation_level: Option<BroadcastValidation> =
|
||||
Some(BroadcastValidation::ConsensusAndEquivocation);
|
||||
let validation_level = BroadcastValidation::ConsensusAndEquivocation;
|
||||
|
||||
// Validator count needs to be at least 32 or proposer boost gets set to 0 when computing
|
||||
// `validator_count // 32`.
|
||||
@@ -1311,7 +1309,7 @@ pub async fn blinded_equivocation_consensus_late_equivocation() {
|
||||
tester.harness.chain,
|
||||
&channel.0,
|
||||
test_logger,
|
||||
validation_level.unwrap(),
|
||||
validation_level,
|
||||
StatusCode::ACCEPTED,
|
||||
network_globals,
|
||||
)
|
||||
@@ -1465,8 +1463,8 @@ pub async fn block_seen_on_gossip_with_some_blobs() {
|
||||
"need at least 2 blobs for partial reveal"
|
||||
);
|
||||
|
||||
let partial_kzg_proofs = vec![blobs.0.get(0).unwrap().clone()];
|
||||
let partial_blobs = vec![blobs.1.get(0).unwrap().clone()];
|
||||
let partial_kzg_proofs = vec![*blobs.0.first().unwrap()];
|
||||
let partial_blobs = vec![blobs.1.first().unwrap().clone()];
|
||||
|
||||
// Simulate the block being seen on gossip.
|
||||
block
|
||||
|
||||
@@ -139,7 +139,7 @@ impl ForkChoiceUpdates {
|
||||
fn insert(&mut self, update: ForkChoiceUpdateMetadata) {
|
||||
self.updates
|
||||
.entry(update.state.head_block_hash)
|
||||
.or_insert_with(Vec::new)
|
||||
.or_default()
|
||||
.push(update);
|
||||
}
|
||||
|
||||
|
||||
@@ -57,18 +57,18 @@ async fn el_syncing_then_synced() {
|
||||
mock_el.el.upcheck().await;
|
||||
|
||||
let api_response = tester.client.get_node_syncing().await.unwrap().data;
|
||||
assert_eq!(api_response.el_offline, false);
|
||||
assert_eq!(api_response.is_optimistic, false);
|
||||
assert_eq!(api_response.is_syncing, false);
|
||||
assert!(!api_response.el_offline);
|
||||
assert!(!api_response.is_optimistic);
|
||||
assert!(!api_response.is_syncing);
|
||||
|
||||
// EL synced
|
||||
mock_el.server.set_syncing_response(Ok(false));
|
||||
mock_el.el.upcheck().await;
|
||||
|
||||
let api_response = tester.client.get_node_syncing().await.unwrap().data;
|
||||
assert_eq!(api_response.el_offline, false);
|
||||
assert_eq!(api_response.is_optimistic, false);
|
||||
assert_eq!(api_response.is_syncing, false);
|
||||
assert!(!api_response.el_offline);
|
||||
assert!(!api_response.is_optimistic);
|
||||
assert!(!api_response.is_syncing);
|
||||
}
|
||||
|
||||
/// Check `syncing` endpoint when the EL is offline (errors on upcheck).
|
||||
@@ -85,9 +85,9 @@ async fn el_offline() {
|
||||
mock_el.el.upcheck().await;
|
||||
|
||||
let api_response = tester.client.get_node_syncing().await.unwrap().data;
|
||||
assert_eq!(api_response.el_offline, true);
|
||||
assert_eq!(api_response.is_optimistic, false);
|
||||
assert_eq!(api_response.is_syncing, false);
|
||||
assert!(api_response.el_offline);
|
||||
assert!(!api_response.is_optimistic);
|
||||
assert!(!api_response.is_syncing);
|
||||
}
|
||||
|
||||
/// Check `syncing` endpoint when the EL errors on newPaylod but is not fully offline.
|
||||
@@ -128,9 +128,9 @@ async fn el_error_on_new_payload() {
|
||||
|
||||
// The EL should now be *offline* according to the API.
|
||||
let api_response = tester.client.get_node_syncing().await.unwrap().data;
|
||||
assert_eq!(api_response.el_offline, true);
|
||||
assert_eq!(api_response.is_optimistic, false);
|
||||
assert_eq!(api_response.is_syncing, false);
|
||||
assert!(api_response.el_offline);
|
||||
assert!(!api_response.is_optimistic);
|
||||
assert!(!api_response.is_syncing);
|
||||
|
||||
// Processing a block successfully should remove the status.
|
||||
mock_el.server.set_new_payload_status(
|
||||
@@ -144,9 +144,9 @@ async fn el_error_on_new_payload() {
|
||||
harness.process_block_result((block, blobs)).await.unwrap();
|
||||
|
||||
let api_response = tester.client.get_node_syncing().await.unwrap().data;
|
||||
assert_eq!(api_response.el_offline, false);
|
||||
assert_eq!(api_response.is_optimistic, false);
|
||||
assert_eq!(api_response.is_syncing, false);
|
||||
assert!(!api_response.el_offline);
|
||||
assert!(!api_response.is_optimistic);
|
||||
assert!(!api_response.is_syncing);
|
||||
}
|
||||
|
||||
/// Check `node health` endpoint when the EL is offline.
|
||||
|
||||
@@ -274,10 +274,10 @@ impl ApiTester {
|
||||
let mock_builder_server = harness.set_mock_builder(beacon_url.clone());
|
||||
|
||||
// Start the mock builder service prior to building the chain out.
|
||||
harness.runtime.task_executor.spawn(
|
||||
async move { mock_builder_server.await },
|
||||
"mock_builder_server",
|
||||
);
|
||||
harness
|
||||
.runtime
|
||||
.task_executor
|
||||
.spawn(mock_builder_server, "mock_builder_server");
|
||||
|
||||
let mock_builder = harness.mock_builder.clone();
|
||||
|
||||
@@ -641,7 +641,7 @@ impl ApiTester {
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn test_beacon_blocks_finalized<E: EthSpec>(self) -> Self {
|
||||
pub async fn test_beacon_blocks_finalized(self) -> Self {
|
||||
for block_id in self.interesting_block_ids() {
|
||||
let block_root = block_id.root(&self.chain);
|
||||
let block = block_id.full_block(&self.chain).await;
|
||||
@@ -678,7 +678,7 @@ impl ApiTester {
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn test_beacon_blinded_blocks_finalized<E: EthSpec>(self) -> Self {
|
||||
pub async fn test_beacon_blinded_blocks_finalized(self) -> Self {
|
||||
for block_id in self.interesting_block_ids() {
|
||||
let block_root = block_id.root(&self.chain);
|
||||
let block = block_id.full_block(&self.chain).await;
|
||||
@@ -819,7 +819,7 @@ impl ApiTester {
|
||||
let validator_index_ids = validator_indices
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|i| ValidatorId::Index(i))
|
||||
.map(ValidatorId::Index)
|
||||
.collect::<Vec<ValidatorId>>();
|
||||
|
||||
let unsupported_media_response = self
|
||||
@@ -859,7 +859,7 @@ impl ApiTester {
|
||||
let validator_index_ids = validator_indices
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|i| ValidatorId::Index(i))
|
||||
.map(ValidatorId::Index)
|
||||
.collect::<Vec<ValidatorId>>();
|
||||
let validator_pubkey_ids = validator_indices
|
||||
.iter()
|
||||
@@ -910,7 +910,7 @@ impl ApiTester {
|
||||
for i in validator_indices {
|
||||
if i < state.balances().len() as u64 {
|
||||
validators.push(ValidatorBalanceData {
|
||||
index: i as u64,
|
||||
index: i,
|
||||
balance: *state.balances().get(i as usize).unwrap(),
|
||||
});
|
||||
}
|
||||
@@ -944,7 +944,7 @@ impl ApiTester {
|
||||
let validator_index_ids = validator_indices
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|i| ValidatorId::Index(i))
|
||||
.map(ValidatorId::Index)
|
||||
.collect::<Vec<ValidatorId>>();
|
||||
let validator_pubkey_ids = validator_indices
|
||||
.iter()
|
||||
@@ -1012,7 +1012,7 @@ impl ApiTester {
|
||||
|| statuses.contains(&status.superstatus())
|
||||
{
|
||||
validators.push(ValidatorData {
|
||||
index: i as u64,
|
||||
index: i,
|
||||
balance: *state.balances().get(i as usize).unwrap(),
|
||||
status,
|
||||
validator,
|
||||
@@ -1641,11 +1641,7 @@ impl ApiTester {
|
||||
let (block, _, _) = block_id.full_block(&self.chain).await.unwrap();
|
||||
let num_blobs = block.num_expected_blobs();
|
||||
let blob_indices = if use_indices {
|
||||
Some(
|
||||
(0..num_blobs.saturating_sub(1) as u64)
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
Some((0..num_blobs.saturating_sub(1) as u64).collect::<Vec<_>>())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -1663,7 +1659,7 @@ impl ApiTester {
|
||||
blob_indices.map_or(num_blobs, |indices| indices.len())
|
||||
);
|
||||
let expected = block.slot();
|
||||
assert_eq!(result.get(0).unwrap().slot(), expected);
|
||||
assert_eq!(result.first().unwrap().slot(), expected);
|
||||
|
||||
self
|
||||
}
|
||||
@@ -1701,9 +1697,9 @@ impl ApiTester {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let test_slot = test_slot.expect(&format!(
|
||||
"should be able to find a block matching zero_blobs={zero_blobs}"
|
||||
));
|
||||
let test_slot = test_slot.unwrap_or_else(|| {
|
||||
panic!("should be able to find a block matching zero_blobs={zero_blobs}")
|
||||
});
|
||||
|
||||
match self
|
||||
.client
|
||||
@@ -1772,7 +1768,6 @@ impl ApiTester {
|
||||
.attestations()
|
||||
.map(|att| att.clone_as_attestation())
|
||||
.collect::<Vec<_>>()
|
||||
.into()
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1909,7 +1904,7 @@ impl ApiTester {
|
||||
|
||||
let result = match self
|
||||
.client
|
||||
.get_beacon_light_client_updates::<E>(current_sync_committee_period as u64, 1)
|
||||
.get_beacon_light_client_updates::<E>(current_sync_committee_period, 1)
|
||||
.await
|
||||
{
|
||||
Ok(result) => result,
|
||||
@@ -1921,7 +1916,7 @@ impl ApiTester {
|
||||
.light_client_server_cache
|
||||
.get_light_client_updates(
|
||||
&self.chain.store,
|
||||
current_sync_committee_period as u64,
|
||||
current_sync_committee_period,
|
||||
1,
|
||||
&self.chain.spec,
|
||||
)
|
||||
@@ -2314,7 +2309,7 @@ impl ApiTester {
|
||||
.unwrap()
|
||||
.data
|
||||
.is_syncing;
|
||||
assert_eq!(is_syncing, true);
|
||||
assert!(is_syncing);
|
||||
|
||||
// Reset sync state.
|
||||
*self
|
||||
@@ -2364,7 +2359,7 @@ impl ApiTester {
|
||||
pub async fn test_get_node_peers_by_id(self) -> Self {
|
||||
let result = self
|
||||
.client
|
||||
.get_node_peers_by_id(self.external_peer_id.clone())
|
||||
.get_node_peers_by_id(self.external_peer_id)
|
||||
.await
|
||||
.unwrap()
|
||||
.data;
|
||||
@@ -3514,6 +3509,7 @@ impl ApiTester {
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(clippy::await_holding_lock)] // This is a test, so it should be fine.
|
||||
pub async fn test_get_validator_aggregate_attestation(self) -> Self {
|
||||
if self
|
||||
.chain
|
||||
@@ -4058,7 +4054,7 @@ impl ApiTester {
|
||||
ProduceBlockV3Response::Full(_) => panic!("Expecting a blinded payload"),
|
||||
};
|
||||
|
||||
let expected_fee_recipient = Address::from_low_u64_be(proposer_index as u64);
|
||||
let expected_fee_recipient = Address::from_low_u64_be(proposer_index);
|
||||
assert_eq!(payload.fee_recipient(), expected_fee_recipient);
|
||||
assert_eq!(payload.gas_limit(), DEFAULT_GAS_LIMIT);
|
||||
|
||||
@@ -4085,7 +4081,7 @@ impl ApiTester {
|
||||
ProduceBlockV3Response::Blinded(_) => panic!("Expecting a full payload"),
|
||||
};
|
||||
|
||||
let expected_fee_recipient = Address::from_low_u64_be(proposer_index as u64);
|
||||
let expected_fee_recipient = Address::from_low_u64_be(proposer_index);
|
||||
assert_eq!(payload.fee_recipient(), expected_fee_recipient);
|
||||
// This is the graffiti of the mock execution layer, not the builder.
|
||||
assert_eq!(payload.extra_data(), mock_el_extra_data::<E>());
|
||||
@@ -4113,7 +4109,7 @@ impl ApiTester {
|
||||
ProduceBlockV3Response::Full(_) => panic!("Expecting a blinded payload"),
|
||||
};
|
||||
|
||||
let expected_fee_recipient = Address::from_low_u64_be(proposer_index as u64);
|
||||
let expected_fee_recipient = Address::from_low_u64_be(proposer_index);
|
||||
assert_eq!(payload.fee_recipient(), expected_fee_recipient);
|
||||
assert_eq!(payload.gas_limit(), DEFAULT_GAS_LIMIT);
|
||||
|
||||
@@ -4137,7 +4133,7 @@ impl ApiTester {
|
||||
.unwrap()
|
||||
.into();
|
||||
|
||||
let expected_fee_recipient = Address::from_low_u64_be(proposer_index as u64);
|
||||
let expected_fee_recipient = Address::from_low_u64_be(proposer_index);
|
||||
assert_eq!(payload.fee_recipient(), expected_fee_recipient);
|
||||
assert_eq!(payload.gas_limit(), DEFAULT_GAS_LIMIT);
|
||||
|
||||
@@ -4183,7 +4179,7 @@ impl ApiTester {
|
||||
.unwrap()
|
||||
.into();
|
||||
|
||||
let expected_fee_recipient = Address::from_low_u64_be(proposer_index as u64);
|
||||
let expected_fee_recipient = Address::from_low_u64_be(proposer_index);
|
||||
assert_eq!(payload.fee_recipient(), expected_fee_recipient);
|
||||
assert_eq!(payload.gas_limit(), builder_limit);
|
||||
|
||||
@@ -4267,7 +4263,7 @@ impl ApiTester {
|
||||
ProduceBlockV3Response::Full(_) => panic!("Expecting a blinded payload"),
|
||||
};
|
||||
|
||||
let expected_fee_recipient = Address::from_low_u64_be(proposer_index as u64);
|
||||
let expected_fee_recipient = Address::from_low_u64_be(proposer_index);
|
||||
assert_eq!(payload.fee_recipient(), expected_fee_recipient);
|
||||
assert_eq!(payload.gas_limit(), 30_000_000);
|
||||
|
||||
@@ -5140,9 +5136,8 @@ impl ApiTester {
|
||||
|
||||
pub async fn test_builder_chain_health_optimistic_head(self) -> Self {
|
||||
// Make sure the next payload verification will return optimistic before advancing the chain.
|
||||
self.harness.mock_execution_layer.as_ref().map(|el| {
|
||||
self.harness.mock_execution_layer.as_ref().inspect(|el| {
|
||||
el.server.all_payloads_syncing(true);
|
||||
el
|
||||
});
|
||||
self.harness
|
||||
.extend_chain(
|
||||
@@ -5169,7 +5164,7 @@ impl ApiTester {
|
||||
.unwrap()
|
||||
.into();
|
||||
|
||||
let expected_fee_recipient = Address::from_low_u64_be(proposer_index as u64);
|
||||
let expected_fee_recipient = Address::from_low_u64_be(proposer_index);
|
||||
assert_eq!(payload.fee_recipient(), expected_fee_recipient);
|
||||
|
||||
// If this cache is populated, it indicates fallback to the local EE was correctly used.
|
||||
@@ -5188,9 +5183,8 @@ impl ApiTester {
|
||||
|
||||
pub async fn test_builder_v3_chain_health_optimistic_head(self) -> Self {
|
||||
// Make sure the next payload verification will return optimistic before advancing the chain.
|
||||
self.harness.mock_execution_layer.as_ref().map(|el| {
|
||||
self.harness.mock_execution_layer.as_ref().inspect(|el| {
|
||||
el.server.all_payloads_syncing(true);
|
||||
el
|
||||
});
|
||||
self.harness
|
||||
.extend_chain(
|
||||
@@ -5220,7 +5214,7 @@ impl ApiTester {
|
||||
ProduceBlockV3Response::Blinded(_) => panic!("Expecting a full payload"),
|
||||
};
|
||||
|
||||
let expected_fee_recipient = Address::from_low_u64_be(proposer_index as u64);
|
||||
let expected_fee_recipient = Address::from_low_u64_be(proposer_index);
|
||||
assert_eq!(payload.fee_recipient(), expected_fee_recipient);
|
||||
|
||||
self
|
||||
@@ -6101,16 +6095,17 @@ impl ApiTester {
|
||||
assert_eq!(result.execution_optimistic, Some(false));
|
||||
|
||||
// Change head to be optimistic.
|
||||
self.chain
|
||||
if let Some(head_node) = self
|
||||
.chain
|
||||
.canonical_head
|
||||
.fork_choice_write_lock()
|
||||
.proto_array_mut()
|
||||
.core_proto_array_mut()
|
||||
.nodes
|
||||
.last_mut()
|
||||
.map(|head_node| {
|
||||
head_node.execution_status = ExecutionStatus::Optimistic(ExecutionBlockHash::zero())
|
||||
});
|
||||
{
|
||||
head_node.execution_status = ExecutionStatus::Optimistic(ExecutionBlockHash::zero())
|
||||
}
|
||||
|
||||
// Check responses are now optimistic.
|
||||
let result = self
|
||||
@@ -6143,8 +6138,8 @@ async fn poll_events<S: Stream<Item = Result<EventKind<E>, eth2::Error>> + Unpin
|
||||
};
|
||||
|
||||
tokio::select! {
|
||||
_ = collect_stream_fut => {events}
|
||||
_ = tokio::time::sleep(timeout) => { return events; }
|
||||
_ = collect_stream_fut => { events }
|
||||
_ = tokio::time::sleep(timeout) => { events }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6180,31 +6175,31 @@ async fn test_unsupported_media_response() {
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn beacon_get() {
|
||||
async fn beacon_get_state_hashes() {
|
||||
ApiTester::new()
|
||||
.await
|
||||
.test_beacon_states_root_finalized()
|
||||
.await
|
||||
.test_beacon_states_finality_checkpoints_finalized()
|
||||
.await
|
||||
.test_beacon_states_root()
|
||||
.await
|
||||
.test_beacon_states_finality_checkpoints()
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn beacon_get_state_info() {
|
||||
ApiTester::new()
|
||||
.await
|
||||
.test_beacon_genesis()
|
||||
.await
|
||||
.test_beacon_states_root_finalized()
|
||||
.await
|
||||
.test_beacon_states_fork_finalized()
|
||||
.await
|
||||
.test_beacon_states_finality_checkpoints_finalized()
|
||||
.await
|
||||
.test_beacon_headers_block_id_finalized()
|
||||
.await
|
||||
.test_beacon_blocks_finalized::<MainnetEthSpec>()
|
||||
.await
|
||||
.test_beacon_blinded_blocks_finalized::<MainnetEthSpec>()
|
||||
.await
|
||||
.test_debug_beacon_states_finalized()
|
||||
.await
|
||||
.test_beacon_states_root()
|
||||
.await
|
||||
.test_beacon_states_fork()
|
||||
.await
|
||||
.test_beacon_states_finality_checkpoints()
|
||||
.await
|
||||
.test_beacon_states_validators()
|
||||
.await
|
||||
.test_beacon_states_validator_balances()
|
||||
@@ -6214,6 +6209,18 @@ async fn beacon_get() {
|
||||
.test_beacon_states_validator_id()
|
||||
.await
|
||||
.test_beacon_states_randao()
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn beacon_get_blocks() {
|
||||
ApiTester::new()
|
||||
.await
|
||||
.test_beacon_headers_block_id_finalized()
|
||||
.await
|
||||
.test_beacon_blocks_finalized()
|
||||
.await
|
||||
.test_beacon_blinded_blocks_finalized()
|
||||
.await
|
||||
.test_beacon_headers_all_slots()
|
||||
.await
|
||||
@@ -6228,6 +6235,12 @@ async fn beacon_get() {
|
||||
.test_beacon_blocks_attestations()
|
||||
.await
|
||||
.test_beacon_blocks_root()
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn beacon_get_pools() {
|
||||
ApiTester::new()
|
||||
.await
|
||||
.test_get_beacon_pool_attestations()
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user